Making changes to installed MSI - wix

I will try to explain the issue by example. I have mypackage-v1.0.msi and mypackage-v1.1.msi. Both packages when installed silently expecting PASSWORD parameter:
msiexec /i mypackage-v1.0.msi /qb PASSWORD=SomeThing1
mypackage-v1.0.msi is already installed and mypackage-v1.1.msi should upgrade mypackage-v1.0.msi. There is a custom action in both packages that depends on this parameter but because of the issue with conditioning this custom action in mypackage-v1.0.msi, during upgrade it is executed but the PASSWORD parameter is not transferred to it.
I wonder if there is a way to patch mypackage-v1.0.msi before upgrading to mypackage-v1.1.msi. But the patch is not changing any contents of installation but the package itself. Is it possible?
Edit:
More focused input - is it possible with the patch to replace a condition for InstallExecuteSequence custom actions?

Yes. Patches include transforms, which modify packages. In fact, patches always modify tables in the package, even when they don't change content of the payload files.

The comments above became too messy. Here is a quick re-write as a regular answer:
Minor Upgrade: A minor upgrade can change most things in an installed MSI package before its uninstall or upgrade sequence is called. It can hence fix problems relating to major upgrades or failed uninstalls among other things (you fix the uninstall sequence before it is invoked).
Sample: Here is the simplest sample of a minor upgrade I could find at the moment (another sample from FireGiant's documentation).
For the simple sample: open the CreatePatch.cmd and update path to WiX binaries (likely ending in v3.11 at this point in time: set wixDir="C:\Program Files (x86)\WiX Toolset v3.11\bin\").
Keep in mind that a minor upgrade has many limitations. Keep things simple and change only what you need to fix your problem.
Minor Upgrade Details: The table at the bottom here shows what needs to change for a minor upgrade. Essentially package code and product version + plus whatever change you want to implement. The above link is to InstallShield's documentation (a different MSI tool), but this is a generic MSI technology concept - it is not vendor specific.
You can deliver the minor upgrade as a new MSI or as a patch file (*.msp). For an MSI you need to use a special command line to install. Something like this:
msiexec.exe /i MySetup.msi REINSTALLMODE=vomus REINSTALL=ALL
The v tells msiexec to re-cache the MSI so that it updates the existing cached one "in-place".
REINSTALLMODE documentation.
Applying Small Updates by Reinstalling the Product.
Links:
https://support.firegiant.com/hc/en-us/articles/230912367-Upgrade-options
https://www.firegiant.com/wix/tutorial/upgrades-and-modularization/

Related

Uninstall msi with full ui mode condition (wix toolset)

I've added the following to my WIX template to prevent installation without entering values in a custom dialog i've made.
<Condition Message='This installation can only run in full UI mode.'>
<![CDATA[UILevel = 5]]>
</Condition>
When I try to uninstall the application I get this message, and I'm unable to proceed.
How do I fix this so that it does not apply on uninstall?
How can I forcibly uninstall this application?
Question 1: LaunchCondition
LaunchConditions must always evaluate to true for the setup to be able to install / run. There are some further details here: Failing condition wix (recommended for more context). When you invoke uninstall via Add / Remove Programs it will run the installer in silent mode (I believe UILevel = 2 or UILevel = 3), which fails your LaunchCondition since UILevel is not equal to 5.
OR Installed: A common technique to prevent LaunchConditions to trigger problems in other installation modes than fresh install, is to add OR Installed to the LaunchCondition in question. This will force the LaunchCondition to be true for all situations and modes where the product is already installed (modify, uninstall, repair, etc...).
So something like this could probably work as an updated condition:
Installed OR UILevel = 5
Wrong Approach?: With that said I would rather implement a check to determine if the value you need specified has been set on the command line via PUBLIC properties for a silent install, instead of that rather strange LaunchCondition checking the setup's GUI level. You can still implement this as a LaunchCondition - or use a custom action for more flexibility. The LaunchCondition would check for values for all critical setup parameters, and you would prevent them from running on uninstall and other modes with the OR Installed mechanism. Here is an answer on the topic of silent installation, transforms and public properties: How to make better use of MSI files (silent deployment is crucial for corporate deployment and software acceptance).
Question 2: Forcibly Uninstall
UPDATE: A couple of additional options listed towards the bottom for completeness.
2.1 - ARP Modify: I want to run the simplest option by you before going into too much crazy detail. Is the Modify option available for your setup in Add / Remove Programs? If so, please click it and see if you then can select remove from the setup's Modify dialogs. This should work (since you are generally not running the setup in silent mode when choosing Modify).
2.2 - Interactive msiexec.exe Uninstall Command: I forgot to add that you should be able to kick off an interactive uninstall via command line as follows: msiexec.exe /x {PRODUCT-GUID} /qf. Here is how you can find the product GUID: How can I find the product GUID of an installed MSI setup? So in summmary: you find the product GUID as explained in the link, and then you open a cmd.exe window and fire off the uninstall command indicated above.
2.3 - Microsoft FixIt: If the first option above is not available, there are several other options that could work, but before trying them I would recommend giving the Microsoft FixIt tool for installation / uninstallation problems a chance to see if this does the trick for you. Run it, select your installation and see if some auto-magic is there for you to get it uninstalled.
2.4 - Advanced (avoid if you can) - hack system-cached MSI: This answer will be the next step, if the above fails: I screwed up, how can I uninstall my program? Please let us know if the above does not work, and we will check the options here. I would just zip up the cached MSI and disable the launch condition, but this is way too hacky for comfort if you can avoid it.
UPDATE: The below was added, but not needed to solve the problem. It is not recommended, it is the last resort. Leaving the content in.
Finding Cached MSI: you can find the system cached MSI using Powershell as explained here. I will inline the Powershell command here:
gwmi -Query "SELECT Name,LocalPackage FROM Win32_Product WHERE
IdentifyingNumber='{PRODUCT-GUID}'" | Format-Table Name,
LocalPackage
You then open the cached file (make a backup of it first, or zip it) with Orca or an equivalent tool, and you make whatever change needed to get the uninstall to function correctly. This is not generally considered a sane approach - it is the last resort. And what you change in the MSI is different depending on what is wrong with it. This requires specialist MSI knowledge. It is easy to mess things up so uninstall becomes even more difficult.
I just saw you got the product uninstalled whilst writing this. Puh! Be glad you don't need this latter approach. I think I will commit it and set it to strikeout so it is visible but not recommended (if only for myself to reuse if needed).
UPDATE, some additional alternatives (not always applicable, included for reference and potential re-use): 1) If you have access to the original MSI used to install your software (it must be the exact copy of the MSI used to install), then you can try to double click it and this should take you into modify directly. 2) You can also double click the file in the system cache folder if you no longer have the original installation MSI. 3) It might be you can hotfix the uninstall string in the registry as well to force a non-silent uninstall:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall
There are probably further ways. For example 4) hack a transform to apply during uninstall, 5) patch the installed MSI (if it is in the wild with lots of installs everywhere), etc...

How does Wix decide to install a particular file?

As I put in title, the question is how does Wix decide to install a particular file?
So I have exe file and when I change something in exe file and rebuild it, it will not get reinstalled if I don't change version. But if I change something in resource file, resource file will be replaced even if I don't change version of my application. So how wix is deciding if he need to replace file during upgrade or not.
I am using wix3.9. MajorUpgrade is schedule afterInstallFinalize.
Versioned files get replaced based on file version, yes, but data files get replaced based on whether you have specified file hash or not. I think WiX generates file hases by default, so this is the overwrite rule:
https://msdn.microsoft.com/en-us/library/aa370532(v=vs.85).aspx
and it's a Windows Installer rule that applies to all MSI settup, not a WiX decision.
P.S. afterInstallFinalize isn't an ideal place. afterInstallExecute is safer, and it will have the same overall result. The issue is that after InstallFinalize means that the new product is installed. If the uninstall of the older product then fails and rolls back you will end up with both old and new products installed, otherwise known as a mess. afterInstallExecute makes everything part of the transaction so you get the original product installed if there is a failure to uninstall it.

Small updates not applying with WiX

I have WiX building MSIs as part of my automated build. I want the user to be able to install one of these builds and then be able to install the next day's version on top of it.
Doing a minor or major upgrade which would require changing the build number within the ProductVersion, I don't see to be an option for several reasons:
Firstly that the only thing I could think to peg it to is either the subversion revision or the build number but that number overflows at 65,535 which we could hit in the future. Secondly that number is already in use for distributing bug fix releases to customers.
So if I cannot change the ProductVersion then the only option left to me is a Small Update. I tried to achieve this by making sure the package code in the revision number summary had changed by not specifying an id for the package element which according to the documentation will result in a new one being generated each time.
<Package InstallerVersion="405" Compressed="yes" InstallScope="perMachine" />
However when running the MSI this generates an error dialog appears warning the user that this product is already installed. The only way to install it is to pass additional command line arguments to msiexec and even that doesn't seem to actually reinstall the components.
Changing the ProductCode to be automatically generated <Product Id="*"...> but not changing the ProductVersion seems to follows the rules described for setting AllowSameVersionUpgrades to no which is the default value. This means Windows Installer treats it as a separate package and installs it alongside the first one but again does not seem to overwrite the installed files, just adds an entry in the installed programs table.
The definition of a small update or minor upgrade includes the fact that you need to specify REINSTALL and REINSTALLMODE - that's just the definition of how to apply them because as you say, that product code is already installed and you can't reinstall it, only update it with a command line update.
You could package the MSI inside a zipped up exe that extracts the MSI and runs it with the appropriate command line, you may need to write a small program to run the MSI depending on whether the self extracting exe tool lets you run external commands. The only other thing I can think of is that you use one of the ooher fields of ProductVersion to indicate that this is NOT a customer product, (such as minor=254) and that leaves you free to use build number up to 65535, at which point do a major upgrade. In practice that may be a long time.
Changing the ProductCode just makes it a new product and yes therefore it will install side by side unless you have specified a major upgrade.

Using Minor Upgrade to deliver a few new files

I am doing a PoC that involves creating an MSI that has version 1.0.0.0; installing that version to a test machine.
Next, I create another MSI (same name, same product code, different package code, same upgrade code). I merely added a single new .txt file to the sources of the original (v1.0.0.0) MSI. I create the new MSI file using WiX and give it version 1.1.0.0.
All good so far.
Here's a breakdown of the codes so far (from Orca.exe):
ProductCode for msi-v1.0.0.0: {CBCF9206-1539-47B8-9A46-A18C2E40D7A1}
ProductCode for msi-v1.1.0.0: {CBCF9206-1539-47B8-9A46-A18C2E40D7A1}
PackageCode for msi-v1.0.0.0: {AB2B02E4-213E-48C1-9394-E30A75BAF2BE}
PackageCode for msi-v1.1.0.0: {C68D3A88-583A-41BF-A971-CB5E083B8547}
UpgradeCode for msi-v1.0.0.0: {06726F10-FF0B-4534-A008-032A70CACDBB}
UpgradeCode for msi-v1.1.0.0: {06726F10-FF0B-4534-A008-032A70CACDBB}
ProductVersion for msi-v1.0.0.0: 1.0.0.0
ProductVersion for msi-v1.1.0.0: 1.1.0.0
What I am trying to accomplish is the deployment of that new single .txt file via this Minor Upgrade. I know that there is a smaller type update called Small Update, but that is not where this PoC is headed. We will need to change the version number as a part of our end game.
I have this in the Wix script that is used to gen both the MSIs (I really don't think this has anything to do with my issue - just including it because it has the word 'Upgrade' in it):
<MajorUpgrade
DowngradeErrorMessage="A later version of [ProductName] is already installed. Setup will now exit."
AllowDowngrades="no"
AllowSameVersionUpgrades="yes"
/>
What I am seeing is that when I run:
msiexec.exe /i FileName.msi REINSTALLMODE=vomus REINSTALL=ALL
I do not get the new single .txt file delivered. I do see that the product version (in appwiz.cpl) changes from 1.0.0.0 to 1.1.0.0, and the cached local MSI file (under C:\Windows\Installer dir) is indeed now version 1.1.0.0 (verified by Orca.exe).
I am puzzled as to why the new single .txt file is not being deployed.
I guess my primary question is: Why won't this Minor Upgrade (i.e. same product code, diff package code, diff product version) deliver the new file?
Thanks in advance for any pointers!
If you broke the component rules you'll see something in the log about it. There'll be SELMGR entries and something about removing components being unsupported. That might happen if you didn't add the file correctly. If you do the minor update install with MSIENFORCEUPGRADECOMPONENTRULES set to 1 on the command line it will fail the install if you broke the rules.
I would read:
What happens if the component rules are broken?
and
Dealing with very large number of files
I'm not a huge opponent of this type of automation. Especially if you are trying to do minor upgrades and patches. Far too often I find people who learn a little bit about installers, don't really want to do it and find it more interesting and "automated" to automate the automation. Don't do it! :) Instead I focus on creating processes that make installer development and maintenance as easy as possible. (See IsWiX on CodePlex) Only the experienced developer knows his code and can make the right choices on how to deploy his resources.

How can I prevent windows installer from asking for the original package on patch uninstall?

My original product has a custom action which does not have the "NOT Installed" condition set, so it tries to run when I uninstall a patch. I've verified that changing the base install fixes the problem, but the product has already been deployed.
Is there some way that I can modify the patch so that it can properly uninstall?
I am using the Purely WiX method.
So far I have tried setting OptimizeCustomActions, but it didn't seem to have an effect:
<OptimizeCustomActions SkipImmediate="yes" SkipDeferred="yes" SkipAssignment="yes"/>
I also tried adding a CustomActionRef to the PatchFamily, which seemed to make it include the custom actions binary, but the uninstall still wants the original package.
A verbose log will indicate why the original package is required. The most common cause is to retrieve an original file. See http://blogs.msdn.com/b/heaths/archive/2006/12/08/source-resolution-during-patch-uninstall.aspx for suggestions.