Windows Installer Upgrades

Overview

This is a huge topic and I am no expert on this. There are many articles floating around about Windows Installer upgrades which most conclude with: stick with major upgrades if you can. It comes to no surprise from the developer community to look for alternatives to software lifecycle management due to the sheer complexity and unforeseen problems with Windows Installer upgrades.

Resources

Versioning

The standard version convention is:

Major
.
Minor
.
Build
.
Revision

8bit

.

8bit

.

16bit

.

16bit

255

.

255

.

65535

.

65535

It is common for versioning to deviate and where the build and revision are swapped. Then in CI/CD pipelines, the build number will be incremented. It is a loose convention.

Upgrades Overview

What is changes are required for upgrades:

Upgrade type
Package code
Product version
Product code
Upgrade code

Small Update

X

Minor Upgrade

X

X

Major Upgrade

X

X

X

A really helpful table that suggests doing a certain type of upgrade is important to read about - most forums and posts recommend only major upgrades. You want to test your installer upgrades before you ship your first product.

The WiX package code is an auto-generated GUID that changes on each build unless you're compiling a merge module - this can be left as is.

Note that you always have to change the Package GUID when you create a new .msi file that is different from the previous ones in any respect. The Installer keeps track of your installed programs and finds them when the user wants to change or remove the installation using these GUIDs.

Using the same GUID for different packages will confuse the Installer.

Upgrade checks

It is important for the installer to check if the same product version is already installed or a newer one is. Be sure to abort the installation if the criteria isn't met:

<Upgrade Id='YOURGUID-7349-453F-94F6-BCB5110BA4FD'>

    <!--
        Meaning: SELFFOUND = productVersion <= detectedVersion <= productVersion

        WIX_UPGRADE_DETECTED is automatically added by the WiX Toolset.
    -->
    <UpgradeVersion OnlyDetect='yes' Property='SELFFOUND'
        Minimum='$(var.ProductVersion)' IncludeMinimum='yes'
        Maximum='$(var.ProductVersion)' IncludeMaximum='yes' />

    <!-- Meaning: NEWERFOUND = detectedVersion > productVersion -->
    <UpgradeVersion OnlyDetect='yes' Property='NEWERFOUND'
        Minimum='$(var.ProductVersion)' IncludeMinimum='no' />
</Upgrade>

You then need to create some custom actions and modify the InstallExecuteSequence to make use of the properties that were set in the above Upgrade node:

<!-- Define custom actions to be evaluated by the above properties -->
<CustomAction Id='AlreadyUpdated' Error='Foobar 1.0 has already been updated to $(var.ProductVersion) or newer.' />
<CustomAction Id='NoDowngrade' Error='A later version of [ProductName] is already installed.' />

<!-- Modify the InstallExecuteSequence so that the custom actions are triggered after FindRelatedProducts -->
<InstallExecuteSequence>
    <Custom Action='AlreadyUpdated' After='FindRelatedProducts'>SELFFOUND</Custom>
    <Custom Action='NoDowngrade' After='FindRelatedProducts'>NEWERFOUND</Custom>
</InstallExecuteSequence>

Major Upgrades

  • A typical major upgrade removes a previous version of an application and installs a new version.

  • A major upgrade can reorganize the feature component tree.

  • During a major upgrade using Windows Installer, the installer searches the user's computer for applications that are related to the pending upgrade, and when it detects one, it retrieves the version of the installed application from the system registry.

  • The installer then uses information in the upgrade database to determine whether to upgrade the installed application.

This is generally recommended by most people including the WiX developers - there's even built-in support to make major upgrades much easier to deal with. Although there is a cost involved, there is far less undefined or unexpected behavior.

Steps for major upgrades

  1. Leave the UpgradeCode unchanged

  2. Change the Description if needed

  3. Change the Version number (first three parts) e.g. 1.0.0 to 1.2.0

  4. Change the Product/@Id, else let WiX auto-generate using Id="*"

  5. Test the upgrades

Test scenario 1:

  • Install v1

  • Install v2

  • Verify v1 files are removed and v2 works expectedly

  • Verify files that needed to be upgraded and added in v2

Test scenario 2:

  • Install v2

  • Verify install v1 fails

Pay attention to assemblies that need to be installed to the GAC or the Win32 WinSxS store. There is some information about a sequence of events that can remove assemblies from the GAC and the WinSxS store during some major upgrades in this KB article.

It would be ideal to test upgrades as part of the CI/CD pipelines - BG compatibility etc.

Upgrade conditions

Remember, a major upgrade consists of two parts: uninstalling the old product and then installing the new product.

You might want to be aware of these important MSI properties:

  1. UPGRADINGPRODUCTCODE - see MS Docs

    • Set during uninstall of old product

  2. WIX_UPGRADE_DETECTED - see WiX Docs

    • Set during install of new product for an upgrade

Installation Type
MSI Condition

Major Upgrade

WIX_UPGRADE_DETECTED

Clean install

NOT Installed AND NOT WIX_UPGRADE_DETECTED

Uninstall

REMOVE="ALL" AND NOT UPGRADINGPRODUCTCODE

WiX MajorUpgrade element

The WiX MajorUpgrade element allows the re-scheduling of the RemoveExistingProducts action. This will change the state of the machine and ultimately the behavior of the upgrade. Be sure to read it carefully.

See MajorUpgrade/@Schedule:

afterInstallInitialize

Schedules RemoveExistingProducts after the InstallInitialize standard action. This is similar to the afterInstallValidate scheduling, but if the installation of the upgrade product fails, Windows Installer also rolls back the removal of the installed product -- in other words, reinstalls it.

i.e. if the new product version fails (and rolls-back its changes) - the old product version remains on the machine.

Minor Upgrades

  • A minor upgrade can be used to add new features and components but cannot reorganize the feature-component tree.

  • Minor upgrades provide product differentiation without actually defining a different product.

  • A typical minor upgrade includes all fixes in previous small updates combined into a patch.

  • A minor upgrade is also commonly referred to as a service pack (SP) update.

If you want to ship updates as MSP's (Small Update or Minor Upgrade in Microsoft terminology) don't use auto-generated GUIDs.

If you're only ever going to ship updates as MSI's (Major Upgrades) you need to change the Product Code every time anyway so auto-generating is fine.

Minor upgrades are generally not recommended and many people have encountered issues - e.g. mixing minor and major upgrades. There is a trade-off of cost (reinstalling a product may take a long time), complexity and size.

Steps for minor upgrades

The steps for a minor upgrade:

  1. Leave UpgradeCode and Product/@Id unchanged

  2. Increment the ProductVersion - preferably keep it to minor

  3. Verify the upgrade/downgrade conditions are met

  4. After building the installer, you cannot run it as per usual, you must invoke it with the following flags

    • msiexec /i Installer_Upgrade_v1_1.msi REINSTALL=ALL REINSTALLMODE=vomus /lv*x log.txt

    • The command line requirement for a minor upgrade is not very user-friendly. WiX recommends wrapping it with a Bootstrapper .exe or an Autorun.inf.

The WiX Toolset docs provides some basic steps for a minor upgrades but it doesn't dive into some finer details which may cause problems later on.

Finer points on minor upgrades

This section is important; it is also a reason why WiX recommends major upgrades due to complexity with minor upgrades.

Minor upgrades are as if it is performing a "repair" - the installer will enter "Maintenance" mode and due to this, FindRelatedProducts will not run. This means that the upgrade conditions you have set will not be checked and will be false - this is because of FindRelatedProducts will usually check all versions in the Windows Installer Upgrade table and set the properties accordingly.

Consider the following scenario:

  • v1.msi is installed

    • Has new file foo.txt (v1)

  • v1_1.msi is installed (minor upgrade)

    • Updated file foo.txt (v1.1)

  • Upgrade_v1_2.msi is installed (minor upgrade)

    • Updated file foo.txt (v1.2)

  • v1_1.msi is re-installed (minor upgrade)

    • File foo.txt (v1.2) remains unchanged

Yeah, brain explosion. Minor upgrades will only update and create new files - you cannot remove files. A small summary that I wish I saw earlier or if it were in the docs:

Maintenance mode installations are not intended for "installations".

They are intended to allow installing and/or removing features from already installed products, for applying updates to products (such as patches/hotfixes/etc.), and for removing products (including the removal phase of major upgrades when RemoveExistingProducts removes "old" products).

Things go weird when files are removed from your product. Windows Installer doesn't let you remove components in a minor upgrade, so using one file per component doesn't immediately solve the automation problem: Your automatically-generated minor upgrade will be missing a component, which is a mortal component-rule sin.

Read more here - paying for upgrades.

Small Updates

  • A small update makes changes to one or more application files that are too minor to warrant changing the product code.

  • A small update is also commonly referred to as a quick fix engineering (QFE) update.

  • A small update does not permit reorganization of the feature-component tree.

  • A typical small update changes only one or two files or a registry key. Because a small update changes the information in the .msi file, the installation package code must be changed.

If you want to ship updates as MSP's (Small Update or Minor Upgrade in Microsoft terminology) don't use auto-generated GUIDs.

Last updated