Why Windows Installer removes files during a major upgrade if they go backwards in version numbers
Recently, I investigated an issue where some files were missing from a user’s PC after installing version 1 of a product and then upgrading to version 2 of the product. I wanted to write about how we diagnosed and resolved the issue in more detail in case others run into similar issues in the future.
I started the investigation by looking in the verbose MSI log file for the version 2 upgrade process, and I found entries for the RemoveExistingProducts action that showed the missing files being uninstalled from the PC. Later in the log, I found entries for the CopyFiles action that showed most of the files in version 2 being installed onto the PC, but I didn’t see any CopyFiles entries for a few of the files that should’ve been installed.
I dug a bit deeper, and early on in the log file, I found an entry like the following for each of the components that contained files that were missing after the upgrade finished:
MSI (s) (60:00) [12:34:56:789]: Disallowing installation of component: {GUID} since the same component with higher versioned keyfile exists
It turned out that each of the files that were missing after the version 2 upgrade had file versions that were lower in version 2 than they were in version 1. The MSI in question has the RemoveExistingProducts action scheduled after the InstallInitialize action (based on this Windows Installer documentation), and Windows Installer evaluates whether or not it needs to install each of the components in version 2 of the MSI before it uninstalls the components in version 1. Because a higher version of the component’s key path file is found on the PC, it decides that it needs to skip attempting to install the component. However, after that decision has been made to skip attempting to install the component, the component is then removed during the RemoveExistingProducts action.
There are a few options to work around this issue, and we ended up choosing option 1:
- Re-build the affected files to ensure that they have higher file versions than any previously shipped versions, then re-package version 2 of the MSI with the updated files.
- Update the build process for the MSI to ensure that the files in newer builds of the MSI have higher file versions than in any older build of the MSI.
- Re-name the affected files and put them into new components in version 2 of the MSI.
- Schedule the RemoveExistingProducts action before the costing actions in version 2 of the MSI (as described on Stack Overflow).
In my scenario, option 2 wasn’t technically feasible because the files in question were built by one team and delivered to another team to include in an MSI, option 3 wasn’t technically feasible because other components depended on the affected files having a standard, well-known name, and option 4 was discarded because it contradicted Windows Installer documentation and led to ICE validation errors for the resultant MSI.
Comments
Anonymous
November 16, 2015
Nice article Aaron. I came across this very issue a couple of weeks back. In my case I'd forgotten to update the version and the files in question were the same version at those already installed. I never did get completely to the bottom of it, but I ended up just updating the version numbers too. I did come across REINSTALLMODE which sounded like it would have an affect but I didn't want to go against the norm. Links: msdn.microsoft.com/.../aa371182%28v=vs.85%29.aspx msdn.microsoft.com/.../aa367835%28v=vs.85%29.aspxAnonymous
November 17, 2015
The comment has been removedAnonymous
November 17, 2015
The comment has been removedAnonymous
November 17, 2015
Hi Rob D. - Thanks for posting about your experiences with this scenario. It does technically work to schedule the RemoveExistingProducts action before the FileCost action, but the product I worked on decided not to do that because it triggers an ICE validation failure. We also had the benefit of being able to re-build the impacted binaries with updated version numbers to eliminate the issue, and I recognize that this isn't an option for every product/scenario too.Anonymous
November 21, 2015
As someone who's worked at a dozen companies while using MSI for the last dozen years I'd say this is a good article to understand the rock and the hard place we setup developer are often put. As Rob D said, these things are canon to the Windows Installer. To developers? YMMV but usually not. It's good to understand what works and what doesn't, anticipate developers doing bad things and know when/where you can influence and when you cannot. For example, as a consultant, I make sure I ask the customer for several builds of their binaries so I can judge their behaviors. Nothing is worse then creating a perfect MSI based on one snapshot of their binaries just for them to come back 6 months later and say your installers upgrades are broken.Anonymous
November 22, 2015
Could you not just version lie in the MSI? Of course this file will always be repaired in a repair scenario and may therefore require source, but maybe you need that at repair time anyway?Anonymous
November 23, 2015
Hi matt@configurationnation.com - Yes, I think that would be technically possible. However, it can lead to Windows Installer resiliency repairs and other possible issues, so I wouldn't recommend it as a workaround for the issue described in this blog post.Anonymous
December 07, 2015
Aaron, Thanks for replying. The REINSTALLMODE option that interested me was "e" which means "Reinstall if the file is missing, or is an equal or older version.". In my particular scenario I had forgotten to update the file version so the new file version was the same as the existing. Not replacing seemed a bit odd and the side effect of it being completely deleted even more so. I just wasn't sure if there would be any unintended side effects with the "e" option, can you think of any? I'm surprised windows installer doesn't spot the RemoveExistingProducts action and take it into account before deciding the course of action. If doing an upgrade with RemoveExistingProducts it seems to me that the file should only ever be deleted if it doesn't appear in the new version.. I expect there are reasons for this behaviour, but I'm not sure what they are other than technical? :) LJAnonymous
December 08, 2015
Hi Laughing John - The "e" flag is typically included in the REINSTALLMODE property by default when doing a repair (in case an existing file got corrupted on the user's PC for example), and there shouldn't be any unintended side effects of doing so. I was surprised that Windows Installer didn't take the presence of the RemoveExistingProducts action into account in this scenario too. I'm sure there must have been a good reason for it at the time, but it led to a counter-intuitive outcome in this type of file downgrade scenario.Anonymous
February 25, 2016
Hello, Thanks for the excellent article and the informative comments. Of all the options listed here, if i have to choose between sequencing REP before Costing and REINSTALLMODE=emus, what would be better? Also please state the reason as to why you think one is better than the other. Regards, Kiran HegdeAnonymous
February 26, 2016
Hi Kiran Hegde - I assume you mean "amus" as opposed to "emus", correct? If those are your only 2 choices, then I would probably choose using REINSTALLMODE=amus but only if you are positive that you won't be shipping side-by-side versions of your product at some point in the future. The "amus" switch presents problems with side-by-side installs when installing v2 before installing v1 - any files shared by the 2 versions will be downgraded in that scenario. If you need to support that type of side-by-side scenario, then you'll probably need to go with the sequencing change. I personally don't like to introduce ICE validation issues into an MSI, so I would avoid that type of sequencing change just in case, but I've heard from several other folks who have used this option successfully, so it is up to you.