Upgradable MSI installations with WiX
I had some interesting challenges when integrating WiX based MSI installer generation into my build scripts. My previous post (NAnt and WiX Versioning) details how I ended up injecting version numbers into the MSI build. In this post, I detail how to ensure that each newly generated installation file will cleanly replace the previous.
When your build script is producing an installer, you want each installation to install cleanly, even if a previous version was already present. The most straightforward way to achieve this with an MSI installer is to build each as a major upgrade (in MSI terms) which removes any existing installation automatically. Achieving this requires a number of elements to interact in a precise manner.
To begin, use your favourite tool to define an UpgradeCode – a unique GUID that must remain constant through all versions of the product.
For ease of reference (since the upgrade code needs to be repeated in a couple of locations), define the upgrade code as a variable at the top of your WXS file.
1: 2: <?define UpgradeCode="{YOURGUID-GOES-HERE-9586-B92717D03E90}"?>
3: This ensures that every reference is identical, avoiding some subtle potential bugs.
The UpgradeCode should remain unchanged throughout the lifetime of your product – it is the one thing in the installer that remains constant. Also, the Upgrade code should be unique to the product you’re installing – never reuse the same upgrade code for multiple different product lines.
Note: You should always include an upgrade code in every installer, even if you do nothing else. Without an upgrade code, it is impossible for any future installer to be an upgrade.
The upgrade code variable should then be referenced from the Product element.
1: 2: <Product Id="YOURGUID-GOES-HERE-0123-012345678901"
3: Name="My Example Product"
4: Language="1033"
5: Version="$(var.version)"
6: Manufacturer="Niche Software"
7: UpgradeCode="$(var.UpgradeCode)">
8: ... 9: 10: </Product>
11: With the upgrade code in place, the next step is to ensure that new product and package GUIDs are used for each installer built.
Fortunately, the WiX toolset provides a simple way to achieve this – instead of supplying a hard coded Id for each, specify a wildcard to request autogeneration of an appropriate GUID.
For WiX 2.x, use a sequence of “?” characters like this:
1: 2: <Product Id="????????-????-????-????-????????????"
3: Name="My Example Product"
4: Language="1033"
5: Version="$(var.version)"
6: Manufacturer="Niche Software"
7: UpgradeCode="$(var.UpgradeCode)">
8: ... 9: 10: </Product>
11: For WiX 3.x, a simpler wildcard “*” can be used instead.
1: 2: <Product Id=”*"
3: Name="My Example Product"
4: Language="1033"
5: Version="$(var.version)"
6: Manufacturer="Niche Software"
7: UpgradeCode="$(var.UpgradeCode)">
8: ... 9: 10: </Product>
11: The same autogeneration needs to be applied to the Package element.
1: 2: <Package Id="????????-????-????-????-????????????"
3: Description="Installer for Example Product"
4: InstallerVersion="200"
5: Compressed="yes" />
6: ... 7: 8: </Package>
9: Again, if you are working with WiX 3.x, use “*” instead.
As a part of the installer, include an Upgrade section to define upgrade policy.
1: 2: <Upgrade Id="$(var.UpgradeCode)">
3: 4: <!-- Detect any newer version of this product -->
5: <UpgradeVersion Minimum="$(var.version)"
6: IncludeMinimum="no"
7: OnlyDetect="yes"
8: Language="1033"
9: Property="NEWPRODUCTFOUND"/>
10: 11: <!-- Detect and remove any older version of this product -->
12: <UpgradeVersion Maximum="$(var.version)"
13: IncludeMaximum="yes"
14: OnlyDetect="no"
15: Language="1033"
16: Property="OLDPRODUCTFOUND"/>
17: 18: </Upgrade>
19: Using the UpgradeCode and Version variables, this policy may define one of two properties. If an installation of this product with a greater version number is found, the property NEWPRODUCTFOUND will be defined. If an installation of this product with a lower or equal version number is found, the property OLDPRODUCTFOUND will be defined.
The policy shown here is sufficient to automatically uninstall any old version when installing a newer one.
To prevent downgrading, add the following.
1: <!-- Define a custom action -->
2: <CustomAction Id=”PreventDowngrading”
3: Error=”Newer version already installed.”/>
4: 5: <InstallExecuteSequence>
6: 7: <!-- Prevent downgrading -->
8: <Custom Action="PreventDowngrading"
9: After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
10: <RemoveExistingProducts After="InstallFinalize" />
11: 12: </InstallExecuteSequence>
13: 14: <InstallUISequence>
15: 16: <!-- Prevent downgrading -->
17: <Custom Action="PreventDowngrading"
18: After="FindRelatedProducts">NEWPRODUCTFOUND</Custom>
19: 20: </InstallUISequence>
21: With all of these elements in place, each new build of your installer should cleanly replace the previous.
I hope you've found this helpful.


Comments
missing prevent downgrading custom action
Thanks for this! Very clear and easy to read for a beginning wix user. One this is missing though--you never define the PreventDowngrading action in your tutorial:
Thanks!
Thanks for letting me know - I'll update the tutorial as soon as I have a chance.
Updated
Now updated to include definition of the PreventDowngrading action.
Versioning
It's the neatest piece of WIX I have seen!!
I have got a problem with upgrading. My version nos are like 0.1.0..
Now, the upgrade does not work for 0.1.0.500 and 0.1.0.600. After installing 500 if I install 600 it works correctly. But after 600, if I try to install 500, that also downgrades, where it should have raised and error saying the newer version exists.
Is there any way to overcome this?
My version nos are like
My version nos are like 0.1.0.#SVN_REVISION#.
MSI Versioning
Hi N!esh.
There are a couple of things with MSI installers that trapped me when I first encountered them. I probably should add details to this article.
Firstly, your version numbers have to be 1.0.x.x or higher. For some reason, if the major version is zero, things don't work right.
Secondly, the fourth part of the version number - what you're populating with your Subversion revision - is ignored.
As far as MsiExec is concerned, 0.1.0.500 and 0.1.0.600 refer to the same revision of the software.
There are a number of ways around this - what I've done with some success is to populate the third part of the version number with the build number from my build server.
Hope this helps,
Bevan.
If I change my versioning to
If I change my versioning to 1.0.500 and 1.0.600. Still the last part is ignored?
No, you'll be fine.
The MSI framework pays attention to the first three parts of the standard four part version number, so 1.0.500 and 1.0.600 would be different.
<UpgradeVersion> IncludeMaximum="yes" or "no"?
According to your upgrade code, the IncludeMaximum attribute should be "yes" for the element:
However, this triggers the following warning from Light.exe:
Should not IncludeMaximum="no" so it does not include identical version numbers? Or, is this prevention for when build numbers change but aren't detected as new versions?
Also, an aside about GUIDs: Is it proper to utilize my .NET assembly GUID for the UpgradeCode? Also, the Component Guid? Product Id? Package Id? So many GUIDs! Not sure which should stay the same and which should autogen.
Excellent article. Most helpful. Thanks!
IncludeMaximum and GUIDs
Thanks for your feedback Kevin, I'm glad you found the article helpful.
If I recall correctly, I found that setting
IncludeMaximum="No"resulted in an installer that would cleanly upgrade old versions, but which wouldn't reinstall itself. Instead, attempting to reinstall would give an error indicating "this version is already installed", forcing the user to manually uninstall (through the control panel) before being able to successfully reinstall the software.Since one of the favored ways to "fix" misbehaving software is to reinstall it, I didn't want to force the extra step on my users.
That said, I didn't get the warning that you are, indicating that one of the contributers to WiX considers my approach poor practice. I assume there's a good reason for this, and will venture to find out.
For now, I'd recommend going with the advice given by the warning - the message originates with someone a lot more knowledgeable about WiX than I!
As for GUIDs, reusing the GUID from your .NET Assembly or component would work no better or no worse than any other. To my knowledge, the MSI framework just uses them as unique identifiers for each piece of installation. As long as you generate your own (reusing someone elses' GUID is a recipe for pain), any approach should be fine.
GUESSA CAPTCHA?
FYI- Your CAPTCHA image does not appear on the comment "Preview" page!
CAPTCHA problem
Thanks for the heads up Kevin - I'll run some tests to reproduce the problem, and will check if there's an update to that piece of code.
WiX 3.0 has changed things a bit
I tried using these instructions with WiX 3.0, and if you use the method explained in the article, you'll also be required to add an InstallExecuteSequence section and manually declare the installation process in detail. I was too lazy to do this, and so some more experimenting lead me to discover that as long as the package (and optionally) the product GUIDs change (which will happen automatically if you set them to "*"), then the upgrade process will now happen automatically, as long as you don't provide an Upgrade section.
I haven't tried this with the downgrade restriction, so YMMV.