WIX MSI perMachine installer writing installed property to HKCU instead of HKLM.
One of the symptoms is that the original logic I used to detect an attempt to install an older version of the product fails because I was depending on the Installed property to get defined on a system where an install had previously been executed. Just to be clear this logic has worked in the past but now I am doing regression testing and it failed.
I edited the msi with orca and modified the launch condition that tests for this. I changed the launch condition to "Installed" and the message to "Not installed" I then ran the installer on several systems where our application is installed. If Installed were true then the installer would run but in every case the installer displayed the message box meaning that it couldn't find the registry entry.
I looked in all these systems and the "installed" registry entry was located in HKCU/Software/company/product/installed=1 instead of in HKLM.
Also this is a 64 bit installer and when I run the installer it gets into the UI and I look at the task manager to make sure it is running the 64 bit version of msiexec which it is.
Here's the relevant WIX fragment which stopped working. See the 1st launch condition. I am adding the beginning of the Product ... section.
<Product Id="*"
Name="$(var.ProductDisplayName)"
Language="1033"
Version="$(var.OurVersion)"
Manufacturer="$(var.ProductAuthor)"
UpgradeCode="$(var.ProductUpgradeCode)">
<Product Id="*"
Name="$(var.ProductDisplayName)"
Language="1033"
Version="$(var.VayTekVersion)"
Manufacturer="$(var.ProductAuthor)"
UpgradeCode="$(var.ProductUpgradeCode)"
>
<Package
Description="$(var.ProductDisplayName)"
Comments="$(var.ProductDisplayComment)"
Manufacturer="$(var.ProductAuthor)"
InstallerVersion="301" Compressed="yes"
Platform="$(var.Platform)"
InstallScope="perMachine"
InstallPrivileges="elevated"/>
<Upgrade Id="$(var.ProductUpgradeCode)">
<UpgradeVersion Minimum="$(var.OurVersion)"
IncludeMinimum="no"
OnlyDetect="yes"
Property="NEWERPRODUCTFOUND" />
<UpgradeVersion
Minimum="07.01.01001" IncludeMinimum="yes"
Maximum="$(var.OurVersion)" IncludeMaximum="no"
Property="PREVIOUSVERSIONSINSTALLED"/>
</Upgrade>
<InstallExecuteSequence>
<RemoveExistingProducts After="InstallFinalize"/>
</InstallExecuteSequence>
<Condition
Message="A later version of the product is already installed. Setup will now exit.">
(NOT NEWERPRODUCTFOUND) OR (NOT Installed)
</Condition>
After I stared at the code a while I removed the "NOT Installed" logic and left
NOT NEWERPRODUCTFOUND
This isn't ideal but it works in most situations.
Anyone have an idea why the registry entry is getting placed in the wrong hive?
An MSI package is per-machine when the ALLUSERS property is set to "1". In the WiX toolset, you can set this using the Package element InstallScope attribute is set to "perMachine".
Also, upgrades will not detect packages in the other install scope. In other words, per-machine cannot upgrade per-user and vice versa.
PS: "NOT Installed" in a LaunchCondition is a very strange thing to see. That would just try to block repair/uninstall.
Related
I'm using WiX toolset to create my msi file from a C++ codebase with cmake and cpack. This setup works great for the past 6 months, but now i'm getting sporadic bad behaviour.
My Setup uninstall older products with the same upgrade-code to guarantee that there is only one version of my product installed (always major upgrade). I rolled out the newest version to my users (via SCCM) two days ago and in 10% of all installations I have the following problem.
The uninstall of the old installation seems to be sometimes wrong. The uninstall process remove the files, but left the root directory and the bin directory but all files are removed. When I query for the installation of the old product via WMI it say that it is installed, which is strange. The other 90% of the instllations everything works great. I also can not reproduce that locally.
I have a log file, but i'm not sure if it is from an misbehaving installation or not.
The logfile is very long, so I post only snippets which makes me sceptical.
MSI (s) (0C:9C) [15:21:35:083]: Component: CM_CP_runtime.bin.main2.exe;
Installed: Absent; Request: Null; Action: Null
...
MSI (s) (0C:78) [15:21:43:591]: Executing op: FileCopy(SourceName=-dbqfin2.dll|FreeImage.dll,SourceCabKey=CM_FP_runtime.bin.FreeImage.dll,DestName=FreeImage.dll,Attributes=512,FileSize=6201856,PerTick=65536,,VerifyMedia=1,,,,,CheckCRC=0,Version=3.17.0.0,Language=1033,InstallMode=58982400,,,,,,,)
MSI (s) (0C:78) [15:21:43:591]: File: C:\Program Files\LDS Studio\bin\FreeImage.dll; To be installed; Won't patch; No existing file
The Action: Null means that there is no operation (but it should be local), but I'm not sure why. When I start the installation a second time everything works fine (because there is no old version). I had that behaviour a year ago (but only for two single files) when we are porting from Visual Studio to cmake and forgot to add a version to our dll (previous dll had a version, new one had no version, so msi think that's not a new version and skip it in REINSTALLMODE default mode 'omus'). Since then we have changed nothing and everything works fine until 2 days ago.
Here is my wix_main.wxs file
<Product Id="$(var.CPACK_WIX_PRODUCT_GUID)"
Name="$(var.CPACK_PACKAGE_NAME)"
Language="1033"
Version="$(var.CPACK_PACKAGE_VERSION)"
Manufacturer="$(var.CPACK_PACKAGE_VENDOR)"
UpgradeCode="$(var.CPACK_WIX_UPGRADE_GUID)">
<Package InstallerVersion="301" Compressed="yes" InstallScope="perMachine"/>
<Media Id="1" Cabinet="media1.cab" EmbedCab="yes"/>
<Property Id="PREVIOUSVERSIONSINSTALLED" Secure="yes" />
<Upgrade Id="$(var.CPACK_WIX_UPGRADE_GUID)">
<UpgradeVersion
Minimum="1.0.0.0" Maximum="99.0.0.0"
Property="PREVIOUSVERSIONSINSTALLED"
IncludeMinimum="yes" IncludeMaximum="no"
/>
</Upgrade>
<WixVariable Id="WixUILicenseRtf" Value="$(var.CPACK_WIX_LICENSE_RTF)"/>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALL_ROOT"/>
<?ifdef CPACK_WIX_PRODUCT_ICON?>
<Property Id="ARPPRODUCTICON">ProductIcon.ico</Property>
<Icon Id="ProductIcon.ico" SourceFile="$(var.CPACK_WIX_PRODUCT_ICON)"/>
<?endif?>
<?ifdef CPACK_WIX_UI_BANNER?>
<WixVariable Id="WixUIBannerBmp" Value="$(var.CPACK_WIX_UI_BANNER)"/>
<?endif?>
<?ifdef CPACK_WIX_UI_DIALOG?>
<WixVariable Id="WixUIDialogBmp" Value="$(var.CPACK_WIX_UI_DIALOG)"/>
<?endif?>
<FeatureRef Id="ProductFeature"/>
<UIRef Id="$(var.CPACK_WIX_UI_REF)" />
<?include "properties.wxi"?>
<?include "product_fragment.wxi"?>
<CustomAction Id="RegisterExtensions"
FileKey="CM_FP_runtime.bin.main.exe"
ExeCommand="-regext"
Execute="deferred"
Return="check"
HideTarget="no"
Impersonate="no"
/>
<CustomAction Id="UnregisterExtensions"
FileKey="CM_FP_runtime.bin.main.exe"
ExeCommand="-unregext"
Execute="deferred"
Return="ignore"
HideTarget="no"
Impersonate="no"
/>
<InstallExecuteSequence>
<RemoveExistingProducts Before='InstallInitialize'>
NOT REMOVE
</RemoveExistingProducts>
<Custom Action="RegisterExtensions" After="InstallFiles">
NOT REMOVE
</Custom>
<Custom Action="UnregisterExtensions" After="InstallInitialize">
Installed AND (REMOVE = "ALL")
</Custom>
</InstallExecuteSequence>
</Product>
I've found some blogpost where people deal with the OnlyDetect mode in but I'm not sure if it can help me or not because I'm not able to reproduce it on my machines.
Switching to REINSTALLMODE amus (https://msdn.microsoft.com/en-us/library/windows/desktop/aa371182(v=vs.85).aspx) maybe is my last resort, but that would be my last resort.
I've found this blogpost https://jpassing.com/2007/06/16/where-to-place-removeexistingproducts-in-a-major-msi-upgrade/ => could it be that i have to change from
<RemoveExistingProducts Before='InstallInitialize'>
NOT REMOVE
</RemoveExistingProducts>
to
<RemoveExistingProducts After='InstallInitialize'>
NOT REMOVE
</RemoveExistingProducts>
???
Maybe somebody can help me with the problem
Greetings
Tonka
The most likely explanation for what you see is that RemoveExistingProducts (an uninstall of the older product) is failing. That will result in a rollback that restores that older product. The old product is then installed, and then the new product continues with its install. At some point in time the install of your new upgrade fails and rolls back, and this will potentially damage the older installed product. That's the general issue with doing an upgrade RemoveExistingProducts outside of the upgrade's transaction. If your REP was after InstallInitize it would fail and the upgrade would not proceed.
(As an aside, asimilar issue can happen if you sequence REP after InstallFinalize and outside the upgrade's transaction, because you install the upgrade product, the transaction finishes, the uninstall of the older product is attempted and fails, it rolls back and restores the older product so now you have both old and new products installed. )
You need to create a verbose MSI log of the upgrade to see why the REP is failing and leaving the older product installed, and why the new upgrade is failing (because otherwise it would show in Program&Features). Also it is safer to keep RemoveExistingProducts inside the upgrade's transaction.
I have the following problem and I'm trying to understand what is happening. I have this code:
...
<Product Name="My Service"
Id="*"
UpgradeCode="$(var.UpgradeCode)"
Language="$(var.Language)"
Codepage="$(var.CodePage)"
Version="$(var.ProductVersion)"
Manufacturer="$(var.Manufacturer)">
<Package Id="*"
Keywords="Installer"
Description="My Service Installer"
Comments="Service Installer"
Manufacturer="$(var.Manufacturer)"
InstallerVersion="300"
Languages="$(var.Language)"
Compressed="yes"
SummaryCodepage="$(var.CodePage)" />
<Upgrade Id="$(var.UpgradeCode)">
<!-- Populate NEWERVERSIONDETECTED if there is an installed
package with the same upgrade code
and version is > the version being installed -->
<UpgradeVersion Minimum="$(var.ProductVersion)"
IncludeMinimum="no"
OnlyDetect="no"
Property="NEWERVERSIONDETECTED" />
<!-- 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.ProductVersion)"
IncludeMaximum="no"
Property="PREVIOUSVERSIONSINSTALLED" />
</Upgrade>
<Condition Message="A newer version is already installed.">NOT NEWERVERSIONDETECTED</Condition>
<InstallExecuteSequence>
<RemoveExistingProducts Before="InstallInitialize" />
</InstallExecuteSequence>
<!-- Step 1: Define the directory structure -->
...
<!-- Step 2: Add files to your installer package -->
...
<!-- Step 3: Tell WiX to install the files -->
...
ProductVersion and FirstVersion has the x.x.x format. Because the msi contains only 3 files I prefer to uninstall everything and put the new files in place (like a major upgrade).
Here is what it's happening:
FirstVersion is defined as "0.0.1"; I build twice my project (to generate two msi with ProductVersion "0.0.2" for the first build and with "0.0.3" for the second). When I install 0.0.3 on top of 0.0.2 everything is going smoothly. In Add/Remove Programs I see the new version installed, "My Service" is up&running in Local Services, in Program Files I see my folder containing the new files.
If I build the project with the ProductVersion 2.0.2 and 2.0.3 (same steps as the previous ones), when I install 2.0.3 on top of 2.0.2, no error pops-up, the installation finishes successfully (at least Event Viewer says so) but my folder in Program Files doesn't exist, My Service is unknown in Local Services (it will not start). The only thing looking good is in Add/Remove programs which shows me the new version 2.0.3 is installed. And another strange thing is the fact that I can uninstall my application from Add/Remove Programs successfully. No error!
So why for 0.0.x format as ProductVersion upgrading is working fine, but
not for 2.0.x?
I tried to log the output of msiexec during the upgrading, but it is too
complicated for me.
PS: do not recommend another way of implementing upgrade. I need to stick
to this code because I'm using msitools which has a lot of limitations.
The versions is right, you haven't made any mistake there.
Without a verbose log your chances to find the problem are quite small. It is not hard at all. Follow the link above and you will find examples on multiple methods to generate a log and share it with us or try to read it be yourself.
My WiX installer does not uninstall previous version record in ARP when I change the version number. It installs the updated files, but I end up with duplicate records in ARP. Does this have something to do with minor versus major upgrades? The beginning of my WiX installer file is as follows:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product Id="*" Name="Blah" Language="1033" Version="1.0.0.6" Manufacturer="Blah Inc." UpgradeCode="c6044fe4-e07a-4dd0-9540-cc77b4430466">
<Package Id ="*" Keywords="Installer" Description="Blah Installer" Manufacturer="Blah Inc." InstallerVersion="200" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated" />
<Property Id="OLDVERSION" Secure="yes" />
<Upgrade Id="7BDF86F7-C6A8-4112-9DA6-FDFB6864AE66">
<UpgradeVersion OnlyDetect="no" Minimum="1.0.0.0" Maximum="99.0.0.0" Property="OLDVERSION" IncludeMinimum="yes" IncludeMaximum="no" />
</Upgrade>
<InstallExecuteSequence>
<RemoveExistingProducts Overridable="no" After="InstallInitialize" />
</InstallExecuteSequence>
Couple of things to check:
Is the Upgrade ID same for both MSI's? The MSI wont know that there is a related product installed unless the upgrade GUID's are same.
Looks like you have updated only the last digit of the version number? if your version 1 uses Version value 1.0.1.0, then version 2 should have a Version value of 1.0.2.0 or higher (1.0.1.1 will not work here).
From Wix3.5, there is a new element called MAJORUPGRADE MajorUpgrade which consolidates the lines which you have written and makes things easier. Can you make use of that and see if it works? Here is a link to Bob Arnsons blog introducing "MajorUpgrade" MajorUpgrade
Check this link for more details: How to implement major upgrade
Your Upgrade Code must generally be stable across versions to identify the products in question as related. They seem to differ in your code.
Furthermore you must implement a major upgrade to ensure that the old product version is uninstalled before the new one is installed. Otherwise you will get multiple installations showing up in ARP.
For good measure always uppercase your GUIDs, though I believe WIX will do this for you on compile. And make sure you uninstall all versions of your application before you try anything else.
I have a product that used to ship with a .vdproj installer. In the most recent version, I shipped a beta with a completely redone installer using WiX (as part of the move to Visual Studio 2012, which no longer supports .vdproj). Unfortunately, at the time I didn't know that the upgrade code was supposed to be consistent across copies, and already shipped one beta installer with a different upgrade code.
I would like my installer to automatically remove previous versions built with the .vdproj installer, as well as the version that was shipped as a beta copy. This is where I've gotten so far:
<Product Id="{A4CBA9F9-D86B-400C-BD23-996B4367931A}" Name="Foo Viewer" Language="1033" Version="6.0.1.0" Manufacturer="Foo Corporation" UpgradeCode="43e024b8-b3ea-40a3-a854-2af83f207f0f">
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MediaTemplate EmbedCab="yes" />
<Feature Id="FOOVIEWERFeature" Title="Foo Viewer" Level="1" Description="The Foo Viewer GUI and CLI binaries." AllowAdvertise="no" Absent="disallow" Display="expand">
<!-- Stuff -->
</Feature>
<PropertyRef Id="NETFRAMEWORK40CLIENT" />
<Condition Message="Foo Viewer requires the .NET Framework 4.0 Client Profile or higher to run.">Installed OR NETFRAMEWORK40CLIENT</Condition>
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER" />
<UIRef Id="FooViewerInstallerUI" />
<UIRef Id="WixUI_ErrorProgressText" />
<Icon Id="FooViewerIcon" SourceFile="../FooViewer.ico" />
<Property Id="ARPPRODUCTICON" Value="FooViewerIcon" />
<!-- I got this upgrade code by opening one of the old .vdproj MSIs in Orca -->
<Upgrade Id="{80539F30-8176-4DCC-A102-ED32A34A91CB}">
<UpgradeVersion OnlyDetect="no"
Minimum="0.0.0.0"
IncludeMinimum="yes"
MigrateFeatures="no"
IgnoreRemoveFailure="no"
Property="UPGRADE_VDPROJ_FOOVIEWER"
/>
</Upgrade>
<Upgrade Id="{43e024b8-b3ea-40a3-a854-2af83f207f0f}">
<!-- Foo Viewer 6.0.0.0 (Beta) shipped with a version 5.3.0.0 in the installer. -->
<UpgradeVersion OnlyDetect="no"
Minimum="5.3.0.0"
Maximum="5.3.0.0"
IncludeMinimum="yes"
IncludeMaximum="yes"
MigrateFeatures="yes"
IgnoreRemoveFailure="no"
Property="UPGRADE_WIX_FOOVIEWER"
/>
<!-- Detect newer versions -->
<UpgradeVersion OnlyDetect="yes"
Minimum="6.0.1.0"
IncludeMinimum="no"
Property="NEW_VERSION_FOUND"/>
</Upgrade>
<Condition Message="A newer version of Foo Corporation Foo Viewer is already installed.">
Installed OR NOT NEW_VERSION_FOUND
</Condition>
<InstallExecuteSequence>
<RemoveExistingProducts Before="InstallInitialize" />
</InstallExecuteSequence>
</Product>
However, despite putting in a <upgrade> element for the old installer's upgrade code, the old version isn't getting removed. As a result the new copy tries to install on top of the old copy, and then neither version works any longer.
The detection of the beta copy, and of newer versions, works correctly (the <Upgrade with GUID {43e024b8-b3ea-40a3-a854-2af83f207f0f} ). The beta version gets uninstalled, and if I generate a "newer" installer, then the current installer correctly doesn't install. That is, the WiX installers have no problem detecting each other.
Is there something I did wrong here that won't let it detect the old .vdproj installed copies?
EDIT: I tool a log of the installation process when this happens, I get the following:
Action start 17:25:47: FindRelatedProducts.
MSI (c) (10:B8) [17:25:47:269]: FindRelatedProducts: current install is per-machine. Related install for product '{2024FF03-D6F2-4065-A22B-80252B2A66B6}' is per-user. Skipping...
Action ended 17:25:47: FindRelatedProducts. Return value 1.
which appears to be accurate. The old installer gave an option for "Per User" or "Per Machine", whereas the new installer always forces per machine. If I select "Everyone who uses this computer" in the old installer, then the new installer is able to detect it. I would like to detect either option if possible in the WiX.
I'm afraid you can't deal with 2 different existing installations at the same time in single installer. Moreover you shouldn't try to run uninstallation of another product (since your UpgradeCode and ProductCode are different, it is anoter product) because msi can't work with simultaneous installations.
What I would recommend is creating separate exe application (bootstrapper), which will run child uninstallation processes of previously installed products and then immediately run your product's installation (probably in full UI mode).
To uninstall the product with no user interaction, use the following command:
msiexec /x {ProductCode} /qn
I hope you know the ProductIds of the previously installed products. If not, you can find it, searching the registry:
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\{ProductCode}\DisplayName
and HKEY_CURRENT_USER if application was installed for single user.
{ProductCode} mentioined in registry path is GUID which is your productCode. You should retrieve all nodes in "Uninstall" branch and find those which are your products checking the "DisplayName" attribute. I hope you know at least the name of the products installed =). And be careful not to delete all software on client's machine =)
Please note if you installed x86 application on x64 machine, you should search location
HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\{ProductCode}\DisplayName"
One more important notice: if your bootstrapper will be also x86 application, you should retrieve node without "Wow6432Node" node because it will be automatically inserted in the requested path. Wonderful world of registry keys on different platforms =).
Please ensure your bootstrapper will be run with admin permission or will ask permission elevation (it should contain security manifest).
One assumption about problem in your post: maybe you didn't change the ProductCode when changed the UpgradeCode? I'm not sure how it will behave, but it is definitely not a MajorUpgrade which automatically removes the previously installed product. For more details see Wix documentation on upgrades. So you might got Minor upgrade or patch which directly installs new components on top of the previously installed files. That definitely could break the application.
I have a msi setup file which was created with wise for windows installer. Now I want to create a new version of this installer with Wix toolset. The problem is, that the installer detects the previous installed (wise created) version, but isn't able to upgrade it. I get the following error message:
"Another version of this product is already installed. Installation of this version cannot continue. To configure or remove the existing version of this product, use Add/Remove Programs on the Control Panel"
I set the same upgrade code in both installers and chacnged the product code and the package code in the wix project. I set the upgrade informations as follows:
<!-- Upgrade information -->
<Upgrade Id="$(var.UpgradeCode)">
<UpgradeVersion Property="NEWPRODUCTFOUND"
IncludeMinimum="no"
Minimum="$(var.ProductVersion)"
OnlyDetect="yes"/>
<UpgradeVersion Property="OLDPRODUCTFOUND"
IncludeMinimum="yes"
Minimum="0.5.0"
IncludeMaximum="no"
Maximum="$(var.ProductVersion)"/>
<UpgradeVersion Property="NEWERVERSIONINSTALLED"
IncludeMinimum="yes"
Minimum="$(var.ProductVersion)"
OnlyDetect="yes" />
</Upgrade>
I also tried to ensure that the product will be installed for all users by setting the InstallScope to "perMachine"
<Package InstallerVersion="200"
InstallScope="perMachine"
Compressed="yes" />
I have other installer projects where all versions were created with wix and for them the upgrade works fine.
Make sure you increase the Product Version. Only newer product version can automatically upgrade the original package.
Also, please note that Windows Installer ignores the fourth version field (in case you are using it).