WiX - not executing custom action during update - wix

I have two custom actions (immediate and deferrend). I would like to skipping actions during upgrade.
I tried:
<Product Id="*" Name="$(var.ProductName)" Language="1033" Version="$(var.Version)"
Manufacturer="$(var.Manufacturer)" UpgradeCode="{GUID}">
<MajorUpgrade DowngradeErrorMessage="Newer version is already installed." />
<Custom Action='CAa' After='InstallInitialize'>NOT Installed AND NOT PATCH</Custom>
and:
<Custom Action='CAa' After='InstallInitialize'>NOT Installed AND NOT UPGRADINGPRODUCTCODE</Custom>
Currently, actions starts during the update.

When you're doing a major upgrade with WiX MajorUpgrade the WIX_UPGRADE_DETECTED is set - see:
http://wixtoolset.org/documentation/manual/v3/xsd/wix/majorupgrade.html
so that is what you use in the upgrade install to detect that there is an older product installed. In other words it means that the new incoming install has detected an older version that is being upgraded.
UPGRADINGPRODUCTCODE is not the one to use. This property is set in the old product being upgraded and uninstalled so it knows the difference between being uninstalled and being upgraded, as the docs here say:
https://msdn.microsoft.com/en-us/library/aa372380(v=vs.85).aspx
"An application determines whether it is being removed by an upgrade or the Add or Remove Programs by checking UPGRADINGPRODUCTCODE."
Its value is the ProductCode of the incoming upgrade that is causing it to be removed.

These conditions are fiddly to get right - there are many options and modes for the InstallExecuteSequence (first time install, major upgrade install, minor upgrade install, maintenance install, uninstall, major upgrade uninstall sequence, patching, auto repair etc...). As I wrote in the comment above, you can try this PDF from Flexera.
No guarantees, but here is a proposal. You can try if this is what you want by showing message boxes from your CA (I can't test this using this lousy thin client, so it is a bit risky to try to answer without having done my own testing - please check carefully yourself):
Not Installed AND NOT PATCH AND NOT UPGRADINGPRODUCTCODE AND NOT REMOVE=~"ALL").
(NOT Installed) = run during first time installation
(NOT PATCH) = don't run during patching
(NOT UPGRADINGPRODUCTCODE) = don't run during a major upgrade uninstall
(NOT REMOVE=~"ALL") = don't run on uninstall
"Reference style table":
How to add a WiX custom action that happens only on uninstall (via MSI)?

Related

NOT UPGRADINGPRODUCTCODE evaluates to true on a major upgrade for custom action

I'm creating an installer with an exe that needs to be called during first installation only.
On any upgrade the custom action shouldn't be called.
<CustomAction Id="MyExe"
Directory="INSTALLFOLDER"
ExeCommand=""[INSTALLFOLDER]MyExe.exe" /arg"
Execute="deferred"
Return="ignore"
Impersonate="no"
/>
and the sequence/condition set as:
<InstallExecuteSequence>
<DeleteServices>NOT UPGRADINGPRODUCTCODE</DeleteServices>
<Custom Action='MyExe' After='InstallFiles' >(NOT Installed) AND (NOT UPGRADINGPRODUCTCODE)</Custom>
</InstallExecuteSequence>
The behaviour I've found is:
On first install - Action is run
On upgrade - Action is run <-- I don't want it to run here
On uninstall - Action is not run
In the MSI installation log I can see an upgradingproductcode is set. I'm not sure how to identify from logs whether it thinks it is installed or not.
I tried changing "NOT UPGRADINGPRODUCTCODE" to "UPGRADINGPRODUCTCODE" and then the CA didn't run on upgrade. But it also didn't run on initial installation then.
Am I setting the condition to run on initial installation wrong?
Using Wix 3.11.
Major Upgrades & Conditions: Please read this answer. What you have to get your head around is the fact that a major upgrade is: 1) a sequence of uninstall of old product and 2) install of a new one - with variations with regards to what order this happens in. Hence one setup is an uninstall and the other one is an install. You can use a debugging approach described here to check conditions.
Essentially:
UPGRADINGPRODUCTCODE is set only in a setup that is being uninstalled as part of a major upgrade. It is not set in the new version being installed. The condition UPGRADINGPRODUCTCODE is hence not true in the installing setup, only in the uninstalling setup.
WIX_UPGRADE_DETECTED is set only in setups that are using WiX's MajorUpgrade element that have detected that another version is being uninstalled as part of its install.
The condition WIX_UPGRADE_DETECTED is hence true in the installing setup, but not in the uninstalling setup.
Application Launch: Very often things you run as part of the setup can be run on first application launch. Very much easier in terms of debugging and testing (familiar context, no impersonation, no sequencing, no conditioning, same-source as main application and easy debugging step-through). In short: much more reliable and easier to manage. Benefits for QA teams as well who can use it to test "clean slates" and / or upgrade scenarios.
Some Links:
Run Wix Custom action only during uninstall and not during Major upgrade

Adding entries to MSI UpgradeTable to remove related products

A WiX installer product node has an attribute UpgradeCode. It is used to refer to previous versions of the same product. The value is stored in the UpgradeTable. The UpgradeTable is parsed by the FindRelatedProducts action.
The UpgradeCode allows to remove previous products with the same UpgradeCode. But the plan is to integrate several outdated legacy products to a combined single product. The UpgradeCode of this legacy product is known. I hope adding this code to the UpgardeTable will remove this legacy product too. This can be done by filling the UpgradeTable.
How can I add more entries in the UpgradeTable in a WiX setup?
Edit: What Syntax is required?
Is there a better way to remove products that are absolete after an upgrade?
Short Answer: You add several Upgrade Element entries in your WiX
source which will create several rows in the compiled MSI's Upgrade Table which then list products that are to be uninstalled during
installation (or that can abort your installation). You must be very careful about the options you specify for each product family to uninstall.
Major Upgrade Failure: Here is a list to help debug failing major upgrades by identifying the most common problems: Common causes of failed major upgrades.
Side-By-Side Installations: Be aware that an alternative to uninstalling older versions during a major upgrade, is to make your new version isolated enough to be able to co-exist with existing installations. Such isolation can be challenging, and is a whole other ballgame (prevent: fighting over file associations, incompatible COM server installations, incompatible runtimes, conflicting services, unexpected locks of configuration files and registry keys, etc...).
MajorUpgrade Element: Newer versions of WiX feature a "convenience feature" for major upgrade implementation in the form of the MajorUpgrade element. This elements simplifies the implementation of normal major upgrades.
Upgrade Element: In earlier versions of WiX more basic elements had to be used to implement major upgrades. This element is still available, and it is what you need to do more elaborate and fine-grained UpgradeTable configuration.
The differences between using these methods are very nicely illustrated by Wim Coenen here: Majorupgrade or Upgrade ID which is preferred for Major upgrade? I think that explanation is so good that I refuse to repeat it too much here :-). Give it a quick read please.
Major Upgrade Configuration Choices: The below is just a sample. The actual configuration of a major upgrade has to be carefully reasoned in each case:
Do you want to abort if higher versions are found?
From what product line?
What will the error message be?
Do you want to continue if an uninstall of an older version fails?
Do you want to allow lower versions to uninstall higher version? (please don't).
Do you want to allow the same version to uninstall itself and re-install?
You obviously have to plan for this and test in detail. Below is a mock-up. This combines the use of the MajorUpgrade Element and Upgrade elements. You can also rely solely on Upgrade elements to do things "manually" with more fine grained control:
<!-- Major upgrade - Your New Product Line, using the MajorUpgrade convenience element -->
<MajorUpgrade DowngradeErrorMessage="A later version of [ProductName] is already installed" />
<!-- Older Product Line 1: Upgrade Code -->
<Upgrade Id="{11111111-1111-1111-1111-000000000000}">
<UpgradeVersion Property="PRODUCTLINE1" IncludeMinimum="yes" Minimum="0.0.0" />
</Upgrade>
<!-- Older Product Line 2: Upgrade Code -->
<Upgrade Id="{22222222-2222-2222-2222-000000000000}">
<UpgradeVersion Property="PRODUCTLINE2" IncludeMinimum="yes" Minimum="0.0.0" />
</Upgrade>
<!-- Older Product Line 3: Upgrade Code -->
<Upgrade Id="{33333333-3333-3333-3333-000000000000}">
<UpgradeVersion Property="PRODUCTLINE3" IncludeMinimum="yes" Minimum="0.0.0" />
</Upgrade>
I would suggest you change the name of these PRODUCTLINE properties that is inherently understandable as a specific product line. In other words if you uninstall WiX3 you call it WIX3PRODUCTLINE etc... This is so the resulting log file is easier to comprehend.
Sample Upgrade Table:
The Attributes column of the Upgrade Table is important to control the behavior of the major upgrade. Continue on uninstall failure, etc...
And a list of free tools you can use to view a compiled MSI files (for whoever might find this answer): How can I compare the content of two (or more) MSI files?
UPDATE:
Unable to remove previous versions of MSI. Multiple entry's show up in control panel
WIX does not uninstall older version (potential causes of failed major upgrade)
Older Entries:
How can I find the Upgrade Code for an installed MSI file?
How can I find the product GUID of an installed MSI setup?
How To: Implement a Major Upgrade In Your Installer
Majorupgrade or Upgrade ID which is preferred for Major upgrade?
Major upgrades now easier than ever
Also want to send you to WiX expert Neil Sleightholm's site for some dated, but still good real-world samples:
WiX Script for Major Upgrades
LaunchConditions, FindRelatedProducts and Downgrades
Just add Upgrade and UpgradeVersion elements as required. That all just works. You might be using the MajorUpgrade element, and perhaps you're unaware of those other elements.

How to prevent Wix from installing an older version?

I have an application that we are switching over to a WiX installer. So far almost everything seems to be going well. The one problem I'm having is that if an older version is downloaded and attempted to install, it does so.
And that's a bit of a problem. If there is a newer version installed I don't want it to install the older version. I thought the problem was with the "Upgrade" component but I must admit I've hit a wall. How can I change it so that the older versions see there is a newer version already installed and not install it?
My test product is now in version 2.4 (the newest version we're trying to push out). It upgrades correctly to 2.4.1 or 2.5 or 3.0. But if I make a 3.0 version, and then run the msi for 2.4 it still adds it.
My upgrade component:
<Upgrade Id="PUT-GUID-HERE">
<UpgradeVersion Maximum="2.4" Property="PREVIOUSVERSIONSINSTALLED" />
<UpgradeVersion Minimum="1.0" Property="NEWERPRODUCTFOUND" OnlyDetect="yes" IncludeMinimum="no" />
</Upgrade>
Follow Up:
After following Steins suggestion I got an error like this
"Duplicate symbol 'WixAction:InstallExecuteSequence/RemoveExistingProducts' found"
After looking around in the Product.wxs file under the <InstallExecuteSequence>I had to delete <RemoveExistingProducts Sequence="6550" /> because that was the duplicate it was referring to. After doing that the installer worked and old versions can no longer be installed on top of new versions.
Packages of Futures Past: You can not change older versions of your package to detect newer ones. You need to build protection into your packages from the start. Packages need to be pre-cognitive. It's an industry problem.
Modern Times: The WiX elements you show above are "old-style". There is a new "convenience feature" described here: How do you detect installed product versions at each startup? It involves the "new" MajorUpgrade element. This new MajorUpgrade element features some auto-magic and I believe it adds the protection you describe by default (downgrade protection). Hence you can switch to using it. I would try that first. Let me inline the basic markup:
<MajorUpgrade Schedule="afterInstallInitialize"
DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit."
AllowDowngrades="no" AllowSameVersionUpgrades="no" />
In addition to removing the old-style upgrade elements, please also remember to delete any hard coded scheduling of the RemoveExistingProducts standard action. For example, remove this line (sequence number will likely be different, but same name):
<RemoveExistingProducts Sequence="6550" />
Decoupling: If you find that there is a high risk that people will run the older versions and mess with your newest application, you could set a new installation location and a new upgrade code for your latest version and install side-by-side to decouple your old and new products.
Side-By-Side: For this to work your product(s) must be capable of co-existing peacefully and not fight over file associations, per-machine registered COM servers, or other globally shared data that make the products interfere with each other. Whether this is possible or not depends on your application. A globally shared COM server can not be registered from two different locations - if you use normal registry registration (you can use manifest based reg-free COM though - though this is involved at times). There can be many challenges to overcome before your application supports side-by-side installation, or it could be rather trivial if your package is simple with no registry involvement.
Component GUIDs: You need to set new component GUIDs as well - for all components - in addition to the mentioned change of upgrade code in order to really shield the products from each other. If you use WiX auto-GUIDs this will happen auto-magically. The reason you need new component GUIDs is attempted explained here: Change my component GUID in wix? Essentially a GUID reference counts an absolute installation location, not a file per-se. You install to a new location, you need a new component GUID.

WIX - prevent executing uninstall action and copy some files on major upgrade

This is my install execute sequence:
<InstallExecuteSequence>
<Custom Action='AlreadyUpdated' After='FindRelatedProducts'>SELFFOUND</Custom>
<Custom Action='NoDowngrade' After='FindRelatedProducts'>NEWERFOUND</Custom>
<Custom Action="SetInstallParameters" Before="actionInstall"/>
<Custom Action="SetUninstallParameters" Before="RemoveFiles">Installed AND NOT REINSTALL AND NOT UPGRADINGPRODUCTCODE</Custom>
<Custom Action="actionInstall" Before="InstallFinalize">NOT Installed AND NOT UPGRADINGPRODUCTCODE</Custom>
<Custom Action="actionUninstall" After="SetUninstallParameters">Installed AND NOT REINSTALL AND NOT UPGRADINGPRODUCTCODE</Custom>
<Custom Action="LaunchBrowser" After="InstallFinalize">NOT Installed</Custom>
</InstallExecuteSequence>
So I need to implement major upgrade functionality. Custom action called "actionInstall" is responsible for registering MySQL exe as service and runnig application, that performs all neccesary database updates by connecting to it and executing some sql scripts included in my installer.
"actionUninstall" is responsible for unregistering mysql service. Currently I have no any support for upgrading.
I need to implement major upgrade. So while upgrading I need to perform following operations:
copy and replace all installer files, except MySQL binaries (MySQL is treated as to be never changed). All files should be copied to program directory, that was used previously (it can be non standard), without any user confirmation.
Don't execute SetInstallParameters, actionInstall, SetUninstallParameters and actionUninstall. Instead, I will create another custom action for upgrade only. It will ony execute app to perform database upgrade
Don't display any setup dialogs (for example, destination directory selection, license agreement dialog).
My problems:
It seems, that major upgrade causes also executing Install and Uninstall - how to avoid it?
How to exclude some files (MySQL binaries) from copying to destination dir, but only on upgrade (on install they should be copied)
How to set destination directory for new files to the same as it was used by previous installation (it can be any directory selected by user on first install), without asking user to choose directory?
There are a couple of things to point out first:
The uninstall of the old product is not really "in" the major upgrade - it's a consequence of the major upgrade calling the uninstall of the old product that is already on the system. You can't prevent that uninstall happening because it is embedded in the older installed product and it will happen in a major upgrade.
A major upgrade is not a patch, or update as you seem to be trying to make it. It is a complete new product that replaces the old product entirely. It's an entire product that is available to new clients that happens to replace older products as part of installing the entire brand new product. This comment is really related to your remarks about not replacing the SQL stuff.
So you may not need to implement major upgrade capability unless you change the requirement about the SQL things. For example, if you simply wanted to update some files without doing uninstalls, then you could build an entire MSI file of the same Product, changing only the files you wish to update and incrementing the ProductVersion, a minor upgrade to install with msiexec /i ... REINSTALL=ALL REINSTALLMODE=vomus and there will be no uninstall of the older product - you've done an in-place update. But I don't think you need that.
Note your conditions on the custom actions! They already won't be called on a major upgrade (because of UPGRADINGPRODUCTCODE) or a minor upgrade (because of REINSTALL), so it's not clear to me why you're worried that they will be called during major upgrade. The designer of these calls anticipated this issue.
In your position I'd do this as a major upgrade:
Include the same SQL files as previously. If the binaries are the same they won't be replaced, or the same ones will be there afterwards, so why is there a problem? The install also works as a fresh install for new customers.
The custom actions in the old product being uninstalled won't run because of UPGRADINGPRODUCTCODE in the condition.
The same custom actions in the new product will run during the install, and I assume you don't want that because they will clobber the existing DB. In a WiX major upgrade, use a not WIX_UPGRADE_DETECTED condition (as well as the others) to prevent CAs from running on its install.
If you want to change or suppress dialogs because it's a major upgrade, then use WIX_UPGRADE_DETECTED to alter the flow or suppress them. Don't delete them because, again, you're doing a major upgrade not a "patch".
If you want to install to the same location, it's sometimes useful to write that install location to the registry with the WiX remember property pattern in the older install so you can recover it later. I susperct you didn't test major upgrades before you shipped the product, so you'll need something else. Find a component Id that's in the directory you want to use, then use a WiX Component search to initialize a property that is the directory name.
For the future, make sure that your CA conditions allow a straight uninstall to work properly, and a major upgrade is essentially the same as a fresh install, and replacing or updating binaries doesn't really matter, so make sure new cuatomers can use it. Also, if you need to remember the install location of data files then your design may be incorrect and I suspect your data is in the user-browseable Application Folder. Data should be in a data folder (such as AppDataFolder) so you don't need to worry about its location on an upgrade AND to help enable limited users to run your app because they cannot update files in the Program Files directory.

Force uninstalling before installing any version with wix installer

Does anyone know:
How can I Force wix installer to uninstall any previous copy previously installed, whether minor or major before installing a new version of our setup.
If 1) can't be done when running a new minor/major setup, can I at least display a message saying that a previous version was detected and it should first be uninstalled and cancel the setup?
Thanks.
UPDATE:
I've added the following to my settings.wxi
<Upgrade Id="$(var.UpgradeCode)">
<!-- Populate NEWERPRODUCTFOUND if there is an installed
package with the same upgrade code
and version is > the version being installed -->
<UpgradeVersion
Minimum="$(var.CurrentVersion)"
IncludeMinimum="no"
OnlyDetect="yes"
Language="1033"
Property="NEWERPRODUCTFOUND" />
<!-- Populate UPGRADEFOUND if there is an installed
package with the same upgrade code
and the version is between the earliest version defined
and the version being installed -->
<UpgradeVersion
Minimum="$(var.FirstVersion)"
IncludeMinimum="yes"
Maximum="$(var.CurrentVersion)"
IncludeMaximum="no"
Language="1033"
Property="PREVIOUSVERSIONSINSTALLED" />
</Upgrade>
I've defined the following in MyProduct.wxs
<?define CurrentVersion="5.0.0.18"?>
<?define FirstVersion="1.0.0.0"?>
<?define UpgradeCode="c1b1bfa0-9937-49eb-812c-5bac06eff858"?>
and finally, I've added this to my <InstallExecuteSequence>
<RemoveExistingProducts Before="InstallInitialize" />
But it still not removing the old version when I increase my version to 5.0.0.19.
Maybe I'm looking at this the wrong way, but in my "Add/Remove Programs" window, I see my setup listed as 5.0.0.18 and I see a second entry as 5.0.0.19
Should I be changing the upgrade code every time I change my version? I thought I had read that this should never be changed.
Any ideas?
Thanks.
I figured out the answer after a lot of googling!! Windows Installer doesn't take into account the 4 number of the version which is what I was using i.e. 5.0.0.18.
It only looks at the first 3 sets of number making the version number. Once I changed my version to 5.0.18.0 to 5.0.19.0, it worked immediately with the code posted in the question and it removed the previous version and installed the newer one over it.
Note that I've actually removed the above code and ended up using the MajorUpgrade instead as it was all I needed:
<MajorUpgrade
AllowDowngrades="no"
AllowSameVersionUpgrades="no"
IgnoreRemoveFailure="no"
DowngradeErrorMessage="loc.NewerVersionInstalled"
Schedule="afterInstallInitialize"/>
Hope this helps someone else!
Here is the documentation for the AllowSameVersionUpgrades attribute of the MajorUpgrade element. It contains pertinent information. The emphasis is mine.
When set to no (the default), installing a product with the same
version and upgrade code (but different product code) is allowed and
treated by MSI as two products. When set to yes, WiX sets the
msidbUpgradeAttributesVersionMaxInclusive attribute, which tells MSI
to treat a product with the same version as a major upgrade.
This is useful when two product versions differ only in the fourth
version field. MSI specifically ignores that field when comparing
product versions, so two products that differ only in the fourth
version field are the same product and need this attribute set to yes
to be detected.
Note that because MSI ignores the fourth product version field,
setting this attribute to yes also allows downgrades when the first
three product version fields are identical. For example, product
version 1.0.0.1 will "upgrade" 1.0.0.2998 because they're seen as the
same version (1.0.0). That could reintroduce serious bugs so the
safest choice is to change the first three version fields and omit
this attribute to get the default of no.
This attribute cannot be "yes" when AllowDowngrades is also "yes" --
AllowDowngrades already allows two products with the same version
number to upgrade each other.
Setting this attribute to yes is probably not what you want, though, because, according to the third paragraph, version 5.0.0.18 would be seen as an upgrade over version 5.0.0.19. Set this attribute to no and use the third product version field to only allow upgrades.