I had an MSI with a CA type 1. Later on, I realized that CA had to be changed so I updated it and created an MSP.
Q1: If I install the MSI and then apply the MSP, I don't think the cached MSI (one in Windows\Install directory) contain the updated CA, right?
Q2: If I uninstall this MSI, does the installer uninstall the MSP first and then the MSI?
Q3: Which CA would be performed during uninstallation? An updated CA or the original CA? Or an updated CA first and then the original CA?
Thanks in advance.
In (typically) the \windows\installer directory there is the cached MSI and any patches that have been installed for that product. When some installation action is performed the cached MSI and all its related patches are "merged" to create the view of the actual currently installed patched product, so:
So Q1 doesn't really apply because nothing is done with the cached MSI on its own. If you look at it with Orca it won't reflect the patch, because that's in a separate MSP file.
Q2: There is no first and last because the (MSI+Patches) is what is uninstalled, followed by clean up removing the files that are no longer needed.
Q3: There is only one CA in (MSI+Patches) and that's what is called.
PhilDW has attended to your specific questions, maybe I can make a few guesses as to what the underlying problem really is.
Is this a minor or major upgrade MSP? A minor upgrade patch can be used to "hotfix" errors in the installed MSI's uninstall sequence - if that is what you are really asking. I have done so many times, and when you install the patch first and then uninstall, what is running on uninstall is what you included in your MSP - the new CA - provided you installed everything correctly (command line, etc...). The MSP is merged to the cached MSI - as Phil states - at runtime. What I am a little fuzzy on, is how any applied transforms are handled - this is something I have never had the time to test. Are you using transforms?
This approach is frequently used when you discover an error in the installed setup's uninstall sequence which prevents a major upgrade from running correctly. In a regular major upgrade the old custom action may or may not run from the old setup depending on how it is conditioned (see link for some conditioning cheat sheets), but typically it either runs undesirably, returns an unexpected error that triggers an undesirable rollback or the whole custom action crashes, causing a failed major upgrade (or failed uninstall).
The above yields a catch 22 situation where your existing install appears un-uninstallable and un-upgradeable - but a minor upgrade can come to the rescue (a regular MSI installed as a minor upgrade should also work - it shouldn't need to be delivered as a patch, provided that you properly re-cache the new MSI from the command line - a patch is merely a distribution mechanism for an upgrade that is already working).
A major upgrade patch (MSP), on the other hand, will not allow you to fix errors in the uninstall sequence of the existing installation since it triggers the uninstall sequence of the pre-existing install and just tells it: "uninstall yourself" - as part of the major upgrade operation. When this happens, then the old CA is used - which is embedded in the cached MSI for the old setup. It is the old setup running - unchanged.
It has been over a decade since I made a major upgrade patch - I find them pretty bad and I avoid them if possible. There are too many problems - and honestly: a few serious logical flaws (for example the fact that the product you are trying to patch may already have been uninstalled - if you schedule RemoveExistingProducts early - see below - a rather ridiculous error, one would have to say). I have never made a major upgrade patch using WiX, but I tried with Installshield and briefly with Wise. In order for them to run at all, you have to set the uninstall of the old version to happen after the install of the new version (so the old version isn't already gone by the time you try to patch). This means RemoveExistingProducts must be late in the InstallExecuteSequence - which makes the setups vulnerable to component referencing errors (another common problem).
UPDATE: I should also add that my major upgrade test - done many, many years ago - also had problems with feature state migration (MigrateFeatureStates) - the patch caused all features to show up in an unknown state. To this date I have never had the time to figure out exactly what happened, but I think it may have been my own doing. I did something funky with the Preselected property (I think it may have been related to a merge module doing something stupid - and I tried to "fix" it - with another fix that didn't fix anything, but caused new problems - and such forth and whatnot :-) - deployment is fun). Just reporting the failure, and whatever intel I have - not claiming to have any solutions. There were also other problems - but most of them were Installshield specific I think. WiX might do a lot better. Wise was sensationally good for minor upgrades (they really did work), but I never used Wise for a real major upgrade.
A typical major upgrade custom action problem is that the custom action is erroneously conditioned and will run in both the old version's uninstall, and the new version's install. There are many modes to test your conditions in, and you will be surprised if you take the time to do so: install, repair, modify, uninstall, patch, etc... And you will often find that the custom action runs unexpectedly on modify or repair operations or similar. I linked to a couple of cheat sheets for conditions above, here it is again: Is it possible to run a custom action only in repair mode.
UPDATE: And a common patch problem is that custom actions may run unexpectedly because they are not conditioned with NOT PATCH. Rant: I wish patching would be its own thing in MSI and not just a delivery mechanism for a regular update, and that it would target files only and have its own installation sequence (like admin install has). This would allow "targeted patching" and small hotfixes for huge products - which really need some working, down-to-earth patching that is not overambitious and over-complicated (which is what patching in MSI currently is - in all honesty).
Advice? Use a minor upgrade patch or a regular minor upgrade (not delivered as a patch) to fix the uninstall problem, and then proceed to use your normal upgrade approach. It should be possible to deliver all this in a WiX Burn bundle - but I have never had time to test it.
My 2 cents? Forget patching if your product is small, and just use a regular minor upgrade MSI. If your product is huge, then use a patch package (or your download bundle will be a lot larger than necessary). Be aware that your future setup bundles should also contain the "hotfix" patch / MSI to allow users with older installations to fix the uninstall error before installing the latest version. A little clunky, but it should be manageable. If your old setup has a working uninstall, but fails as a major upgrade (because of an insignificant error in the uninstall sequence making the whole process fall over), you can uninstall the old setup with a regular uninstall command passed to msiexec.exe and then install the new version afterwards (avoiding the major upgrade scenario by performing a manual uninstall first). I haven't tested this with Burn yet.
Related
We have two installers build in WIX with the constraint that Product code has to remain same. On doing an upgarde from old to new, I get an error, "The specifile account already exists."
Does WIX allow any workaround for me to achieve an upgrade while keeping my product code unchanged.
It depends what you mean by "upgrade" but there is no such thing as a major upgrade where the ProductCode stays the same. Keeping it the same is not a constraint, it's against what a major upgrade does. You should say why you believe it's a constraint to keep it the same, and if you decided it's a solution to a problem you haven't told us about.
The error message is from a WiX util CreateUser custom action of some kind. You haven't specified what you have changed in your MSI file, but if you are just running your new MSI and it's got the same ProductCode then you are probably doing a repair, and that repair is running the CreateUser again and telling you it already exists. You should supply more info about your CreateUser.
You'll also need to say what kind of upgrade you are doing (major, minor?) and if it's minor then what is your command line?
Minor Upgrade: That is just a minor upgrade - a different form of MSI update from the more commonly used major upgrade. Info about Patching & Upgrades (in general).
Complex & Limited: There are a number of restrictions for minor upgrades that make most people end up using major upgrades. Essentially a minor upgrade can add new features and components, but cannot reorganize the feature-component tree. But wait, there are many more restrictions:
Minor upgrades can not change the MSI file name, it must match the previously installed version. I always end up banging my head against this one having forgotten the restriction, hence this specific mention.
Some further limitations as capably explained by Flexera's help file: Major Upgrade vs. Minor Upgrade vs. Small Update (third column).
Aging, but good content from installsite.org on the same topic: Windows Installer Updates and Patches.
MSDN description of limitations: Changing the Product Code
Advanced Installer's Creating Patches list of limitations and restrictions (applies to minor upgrades in general as well as minor upgrades delivered as patches).
Installing Minor Upgrades: A minor upgrade can be delivered as a regular MSI or as a patch file. The standard command line used to install a regular MSI file:
msiexec.exe /i MySetup.msi REINSTALLMODE=vomus REINSTALL=ALL
Maybe see this Flexera help file page for some more details on installing minor upgrades (some Flexera-specific stuff, but mostly generic). That is where the above command line is from.
Personal Opinion: Let me end with a subjective observation. I find minor upgrades excruciating for real-world use, and I have only successfully used them for "hotfixing" (just update a couple of files with no other changes), and to fix errors in installed product's uninstall sequences which prevented them from successfully uninstalling. In these cases the minor upgrades became so simple that they worked reliably. In order to deliver a real-world product with only minor upgrades, a lot of care, foresight and discipline is needed (not to mention a patient and insightful product manager who will understand these technology limitations and what they mean for real product deployment).
With all that said, let us not underestimate the huge, corporate benefits of MSI (beyond mere upgrading issues and related details):
The Major Benefits of MSI (compressed - "executive summary")
The Corporate Benefits of Using MSI Files (elaborate and verbose)
I wrote a custom action to help during upgrade of my product (from 1.0 to 1.1). Now I need to upgrade from 1.1 to 1.2 but the existing uninstaller is failing during upgrade. I got the execution conditions of my custom action wrong. (Lesson learned, always test upgrading to the next version before deploying).
Right now it seems my best option is to modify the InstallExecuteSequence table in the existing .msi to disable the failing custom actions. I'll have to create another custom action to browse the registry, locate the existing .msi in C:\
Windows\Installer, patch it, and then continue with the upgrade. This sounds like a terrible, error prone solution, but I'm really at a loss. This was supposed to be an automatic, silent upgrade pushed down from a remote cloud.
Another option would be to write a batch script to uninstall the existing product, then execute the new installer.
Any advice?
EDIT This question is already answered here: I screwed up, how can I uninstall my program?
The supported way to do this is a patch (by which I mean an MSP file, not coding to alter the cached MSI file). That's by far the most straightforward way to get out of the situation. After that, do the upgrade. Using WiX you could probably put the MSP and the upgrade in a bundle.
In any case, you wouldn't do your proposed change with another MSI. A small executable can do what you propose, and:
MsiGetProductInfo (ProductCode, …, INSTALLPROPERTY_LOCALPACKAGE)
is how you find the cached MSI.
Conditioning: What condition did you set on the failing custom action? And more importantly, what is the new condition you are intending to use? It sounds like regular uninstall works but major upgrade fails? The typical problem is that uninstall fails altogether, and then the usual solution is a minor upgrade which I will quickly describe.
Minor Upgrade: Normally what I use is a minor upgrade to fix whatever is wrong in the current install's (un)installation sequence(s). A minor upgrade does not uninstall the existing installation, it upgrades it "in-place", and the uninstall sequence is hence never called and thusly you avoid all its errors from manifesting themselves. There is no need to browse to the cached MSI file and hack it manually if you do things correctly in your minor upgrade. The updating of the cached MSI will happen auto-magically by the Windows Installer Engine provided you install with the correct minor upgrade command line.
Future Upgrades: A minor upgrade will generally always work if you make it simple enough, but the problem is usually applying it since it often targets only a single, previous version. When you get to the next release and if you then use a major upgrade, you will see the error in your original MSI manifest itself on uninstall if you are upgrading an installation that never had the minor upgrade applied - in other words it is still the oldest version of your installation. This is generally solved by a setup.exe launcher which will install the minor upgrade if need be. The bad news is that you need to keep that update in every future release - if you want to avoid any upgrade errors. Or in a corporate environment you would use the distribution system to check what is already on the box and install accordingly. If your manual uninstall works correctly (but major upgrade uninstall fails), all you should need to do is to push an uninstall command line to msiexec.exe as the first command to run via your setup.exe I think. Then there is no need to include any minor upgrade binaries in your setup.exe launcher.
Detect & Abort?: Michael Urman's answer here explains how it might be difficult to make sure that the minor upgrade is present on the box before applying the next version of your software:
InstallShield fails because of a bad uninstall. He suggests making your package better at detecting whether a new upgrade can be safely applied.
Some Links:
how to omit a component when we try to build .msi using wix (on how patching is just a distribution mechanism for MSI upgrades that must already be working)
Is there any possible way to perform upgrade when Product codes for old and new versions are same? (on minor upgrades and their technical limitations)
Here is a hack that I got working, but based on the answers above it looks like it's not the preferred way.
[CustomAction]
public static ActionResult Patch11Installer(Session session)
{
string localPackage = NativeMethods.GetMsiInstallSource("{MY-PRODUCT-CODE}");
if (String.IsNullOrEmpty(localPackage))
{
session.Log("Failed to locate the local package");
return ActionResult.Failure;
}
session.Log($"Found local package at {localPackage}");
using (Database database = new Database(localPackage, DatabaseOpenMode.Direct))
{
foreach (string action in new string[] { LIST OF CUSTOM ACTION NAMES })
{
session.Log($"Modifying condition for action {action}");
database.Execute($"UPDATE InstallExecuteSequence SET Condition='WIX_UPGRADE_DETECTED' WHERE Action='{action}'");
}
database.Commit();
}
return ActionResult.Success;
}
The custom action calls MsiGetProductInfo to query for the v1.1 MSI using the v1.1 product code which I obtained from installer log files. It then opens the MSI database and modifies the Condition property of the InstallExecuteSequence table for the list of custom actions that are failing. It changes the Condition from "UPGRADINGPRODUCTCODE OR WIX_UPGRADE_DETECTED" to "WIX_UPGRADE_DETECTED". UPGRADINGPRODUCTCODE is the property that's causing the uninstall to fail during a major upgrade as this property is passed to the uninstaller and contains the new product code; the product code for v1.2 in my case. Here is the custom action definition in my installer file.
<CustomAction Id="Patch11Installer" Return="check" Impersonate="yes" Execute="immediate" BinaryKey="MyUpgradeCustomActions" DllEntry="Patch11Installer" />
I'll look into implementing a minor upgrade as suggested in other answers. I just thought I would leave this solution here.
We have an installer which requires a reboot on install, but it is also rebooting on uninstall. Is there a way we can prevent the reboot when uninstalling?
This is what we have at the moment:
<InstallExecuteSequence>
<ScheduleReboot After="InstallFinalize"/>
</InstallExecuteSequence>
Many thanks in advance!
Restart Manager: The Restart Manager Feature of Windows (Installer) (middle page) is designed to help restart applications automatically during installation rather than requiring a reboot.
This feature should always be used to try to eliminate reboot requirements.
Only in very special circumstances should a reboot be really required.
Technical Crash Course: This is a technical tidbit and recommendation for implementing Restart Manager in your application - from Advanced Installer, makers of leading deployment tools:
https://www.advancedinstaller.com/user-guide/qa-vista-restart-manager.html
UPDATE: MSI Expert Phil Wilson on Restart Manager (for some Restart Manager reality check - please read).
Add Condition to ScheduleReboot
You need to insert a condition for your ScheduleReboot entry along the lines of what is described here: https://www.firegiant.com/wix/tutorial/events-and-actions/extra-actions/ (the linked article may show a condition that is a little too inclusive or unrestricted).
UPDATE: There are some issues to consider:
Undesired action: ScheduleReboot should never be used unless it is really necessary. For example, if you are trying to replace files that are in use MSI will handle that without a call to ScheduleReboot.
Many installation modes: Without a proper condition, the ScheduleReboot will cause a reboot prompt to show up in many installation modes: install, uninstall, upgrade, repair, self-repair, patching, etc... This is not desirable.
Silent, instant reboot: If an MSI is run in silent mode and REBOOT=ReallySuppress is not specified, a ScheduleReboot action will automatically trigger an instant reboot of the computer in question - which might be very surprising and very undesirable.
For your purpose, you can perhaps use a condition along these lines:
<InstallExecuteSequence>
<ScheduleReboot After='InstallFinalize'>NOT Installed AND NOT WIX_UPGRADE_DETECTED</ScheduleReboot>
</InstallExecuteSequence>
It all depends on whether you want to schedule a reboot during a major upgrade, or just during the original, fresh installation? There is no way to tell without more information. A more run-of-the-mill condition like NOT Installed AND NOT REMOVE~="ALL" would appear to schedule a reboot during a major upgrade, but not for a manual uninstall not triggered by a major upgrade (I will test when I get a chance - UPDATE: verified, basic testing only).
Note that the special WIX_UPGRADE_DETECTED property is a WiX-specific construct that may only be set if you use WiX's MajorUpgrade element. You can also set up major upgrades the old fashioned way in WiX and avoid the MajorUpgrade element "convenience feature" which allows easier configuration of the major upgrade with fewer options - "auto-magic". I didn't verify if WIX_UPGRADE_DETECTED is still set using this "old school" major upgrade configuration.
You can also use the ActionProperty from the Upgrade table to detect that a major upgrade is "about to happen" (see this answer for a sample). This should work even for non-WiX MSI setups - and as such should be an alternative to WIX_UPGRADE_DETECTED (I believe this property is set after FindRelatedProducts has run).
WIX_UPGRADE_DETECTED vs UPGRADINGPRODUCTCODE
The MSI package being uninstalled during a major upgrade will have the special property UPGRADINGPRODUCTCODE set (which will not be set in the MSI being installed during the upgrade). This is a built-in MSI property, and not a WiX-specific construct. In other words, during a major upgrade - which is an uninstall of an old version and an install of a new version - the MSI being uninstalled will have the property UPGRADINGPRODUCTCODE set whilst the MSI being installed will have the property WIX_UPGRADE_DETECTED set (I will verify this shortly). It will also have the ActionProperty from the Upgrade table set after the standard action FindRelatedProducts has run.
If this sounds complicated, then I am afraid it is. This is a key problem with Windows Installer (despite the technology's major corporate benefits) -
that basic, key operations - such as upgrades - are sometimes very complicated to get right. There may be some violations of the principle of least astonishment. There is good and bad in all technologies - obviously.
Special Considerations
Note that a reboot may be initiated regardless of whether the ScheduleReboot action is suppressed or not (for example if there are files that could not be replaced - or worse: a custom action forces a reboot via code - which is always wrong, a reboot should be scheduled not forced via code).
You can suppresses certain prompts for a restart of the system by using the REBOOT property (something you will have read already). More on System Reboots.
MSI Conditions
MSI conditions can be very tricky to get right. Get it wrong and your action runs unexpectedly during the wrong installation mode - or it doesn't run at all when it should. This is much easier to get wrong than what you might think - even with experience. The proof is in the pudding here, real-life testing. Here are some sample, complex conditions as an example: Wix Tools update uses old custom actions (just in case it is interesting).
There are many installation modes you should test in when you try to use complex conditions (or any condition for that matter): 1. fresh install, 2. repair, 3. modify, 4. self-repair, 5. patching, 6. uninstall, 7. major upgrade invoked uninstall, etc... There are also a few weird modes like resumed suspended installs featuring the RESUME property, and the AFTERREBOOT property relating to the ForceReboot action etc... Things one should keep in mind that are rarely tested.
Here are two "cheat-sheets" for conditioning:
Installshield condition cheat sheet.
How to add a WiX custom action that happens only on uninstall (via MSI)?
I have not had the time to go through all these conditions and test them, but the latter table looks reasonable at face value. However: I believe REMOVE can sometimes be set during installation (and during change). It is very complicated to deal with all permutations of possibilities since MSI's command line interface and property configuration is so flexible. Installed is also not set for the new MSI version being installed as part of a major upgrade, but it will be set for the MSI version being uninstalled - very confusing.
The Installshield cheat sheet I have never actively used or checked, but I find their suggestions for repair interesting to say the least - there are different entries depending on how the repair is invoked.
Please remember to also check self-repair - just delete the main application EXE and trigger self-repair by then invoking the application's advertised shortcut (if any). It has been years since I checked, but self-repair may only run actions between InstallInitialize and InstallFinalize. You don't want to schedule a reboot during a self-repair.
We have an installer that consumes a merge module. The newest version of the merge module includes downgrades to some files. When using the installer to upgrade from an earlier version we are having problems downgrading these files.
Initially the files from the merge module were being removed and not re-installed, but after reading wix major upgrade not installing all files I set Schedule='afterInstallFinalize' on the MajorUpgrade element. This resulted in the files with the newer versions being retained.
How can we change either our installer or the merge module so that these files are downgraded during an upgrade?
Well, in my opinion, the best way to approach this issue is to sequence the standard action "RemoveExistingProducts" to before CostInitialize standard action.
Be aware that this scheduling is not in accordance with the Microsoft recommendation at :
https://msdn.microsoft.com/en-us/library/windows/desktop/aa371197(v=vs.85).aspx
So, when you try to build your msi package, you might have to end up suppressing ICE error messages ,which if not suppressed, might prevent you from building.
There is an easy way to suppress ICE error messages in Wix . You can do that in the Visual studio IDE as well as when using the candle.exe to compile your .wxs project. The Wix documentation will give you enough details about this.
If you are wondering if its ok to go against the Microsoft recommended placement for RemoveExistingProducts, take a look at :
Downgrade File in MajorUpgrade
FWIW, I've talked to MS support in the past about having REP before costing to make upgrades work successfully, and at that time they said it was ok, while pointing out that it's also before MigrateExistingFeatures so if you migrate features during upgrades there'll be an issue.
What this means is that , if you have multiple features in your msi package and you want the exact same set of features to be upgraded by your upgrade package, then this approach might not work.
However, if you just have a single feature in your msi package, then this approach will work.
Also, be aware that placing RemoveExistingProducts outside of InstallInitialize and InstallFinalize has other consequences, in case there is an error during your upgrade, as RemoveExistingProducts is not transacted.
What might happen is that , RemoveExistingProducts will uninstall your old application and then the upgrade process starts the installation of your newer version of your product. However, at this point of time, if there happens to be an error installing your newer version of your product, then the upgrade rolls back and then you will be left with no version of the product on your system.
http://blogs.msdn.com/b/heaths/archive/2010/04/09/major-upgrades-with-shared-components.aspx
-The other option is to make use of REINSTALLMODE property.
You will author this property in your property table with a value of emus
REINSTALLMODE = emus.
If emus doesnt work, try with amus.
using amus is fraught with risks and should be avoided for the most part, except in exceptional circumstances.
https://msdn.microsoft.com/en-us/library/aa371182(v=vs.85).aspx
However, exercise caution here again.
REINSTALLMODE are caller properties and are usually set by the person performing the installation and hence its not a good practice to author this in the Property table.
However, there might be exceptional situations such as yours which might require you to take this approach.
-The other option i was thinking was to change the component GUIDs of the components in your Merge module.
However doing so would only work if the following condition is met:
-All the consumers of your merge module have RemoveExistingProducts sequenced very early in the upgrade cycle i.e they follow a method of ugprade where the older product is uninstalled and a newer product is installed.
So this might lead to re-sequencing of RemoveExistingProducts in all of your consumers.
Reason being, assume for a moment that you change the component GUID in the present version of the merge module and then you rebuild the latest version of the installer using this merge module. If RemoveExistingProducts is sequenced later in the upgrade cycle i.e after InstallFinalize, then it's a violation of windows installer component rules. You have two products installing the same file to the same location but with different component GUId's. Hence, its absolutely critical that if this approach is followed, RemoveExistingProducts is sequenced very early in the upgrade cycle.
Hope this helps.
Following the suggestion in this answer I have a patch that suppresses the running of custom actions via the use of PATCH and Not Installed conditions.
Works great when installing the patch but I have the additional requirement that the patch needs to be uninstallable. This presents a problem because when our original product was authored we unfortunately did not take into account the possibility of future patching. My understanding of uninstalling patches is that Windows Installer basically re-runs the original package in REINSTALL mode. This is going to wreak havoc on the application configuration, as it requires a bunch of user-provided values for things such as IIS, config files, etc.
I have read that it's possible to re-cache the originally-installed package with an updated one that has correct conditioning in InstallExecuteSequence to skip actions if it's in a reinstall mode, but it seems risky/hacky. Are there any other ways around this problem?
That re-caching isn't as risky as it sounds, but it's a rare alternative to patching. You'd do it with a command line that has REINSTALL=ALL REINSTALLMODE=vomus.
It's rare because if you're going to rebuild the MSI to fix those conditions you may as well go all the way and do a major upgrade in which you can supply whatever fixes are in the patch as well as fixing the CA conditions to make the new product more easily patchable, including uninstalling patches.