WIX Bootstrapper uninstall without uninstalling MSI how to? - wix

I'm building a WIX Bundle/Chain bootstrapper. It runs and installs like I specified.
I would like to be able to uninstall the bootstrapper without installing the installed MSI. How to accomplish that?
I'm using WIX 3.11.
Other posting here seem to have the opposite behaviour and demand. They seem to use other versions of wix (<=3.10).
Is there a way to accomplish that behaviour?
Some snippets:
...
</Chain>
TK

In your MsiPackage node, add the Permanent flag and set it to yes. When you uninstall your bootstrapper, the msi(s) set this way will remain installed on the machine.
<MsiPackage Id="MSI2KEEP"
Cache="no"
Compressed="yes"
Name="MSI2KEEP"
ForcePerMachine="yes"
DisplayInternalUI="no"
Vital="yes"
**Permanent="yes"**
SourceFile="$(var.MSI2KEEP.TargetPath)"
DisplayName="MSI 2 KEEP"
Description="MSI 2 KEEP" />

Related

How to conditionally install third party applications in WiX Bundle

I have a WiX installer and I have created a bootstrapper project for the same in order to install my pre requisites. However, I would like pre-requisites to only get installed if they are not already there on the system. Is it possible to add such a condition to my code?
This is the code I have right now, where in it installs my application. But I would like to add the conditions to it.
<Fragment>
<PackageGroup Id="OpenTAP">
<ExePackage
SourceFile="..\..\..\External\Prerequisites\OpenTAP\ITS_OpenTap.9.18.5_Installer.exe"
DetectCondition="ExeDetectedVariable"
InstallCommand="/q /ACTION=Install"
RepairCommand="/q ACTION=Repair /hideconsole"
UninstallCommand="/q ACTION=Uninstall /hideconsole" />
</PackageGroup>
</Fragment>
The ExePackage will only install if the DetectCondition is false. So, as long as you are setting the ExeDetectedVariable correctly then Burn will behave exactly as you desire.

WiX burn bootstrapping run different InstallCommand parameter for silent install

I have a Wix installer which needs to use a bootstrapper. I have included an extract of the Bundle.wxs below. It shows the Chain, which is to first install .Net 4.5.2 and then depending upon whether the installer has been called with -s for silent install calls ExePackage with or without the InstallCommand with a value of /S. The "OtherInstaller" is a NSIS (nulscript installer) installer so requires a case sensitive /S to trigger it's silent install. I understand that UILevel=2 is the condition to check for for a silent install, but for some reason "OtherInstaller" is not getting called with the /S silent argument. Then after that the "MainMsiInstaller" is called.
<Chain>
<PackageGroupRef Id="NetFx452Web"/>
<ExePackage Id="OtherInstallerLoud"
SourceFile="..\..\bootstrapper\OtherInstallerFile"
InstallCondition="NOT UILevel=2"/>
<ExePackage Id="OtherInstallerSilent"
SourceFile="..\..\bootstrapper\\OtherInstallerFile"
InstallCommand="/S "
InstallCondition="UILevel=2"/>
<MsiPackage Id="MainMsiInstaller"
DisplayInternalUI="yes"
SourceFile="..\..\bin\$(var.CandleCfgName)\MainMsiInstaller.msi" />
</Chain>
Any help appreciated.
In the end a solution that worked for me (whether the best solution, or not) was to ensure that the version of burn.exe I was using was 3.11.xxxx and InstallCondition="WixBundleUILevel=2" which is a WIX variable which is available in v3.11 upwards.
So in essence...
<Chain>
<PackageGroupRef Id="NetFx452Web"/>
<ExePackage Id="OtherInstallerLoud"
SourceFile="..\..\bootstrapper\OtherInstallerFile"
InstallCondition="NOT WixBundleUILevel=2"/>
<ExePackage Id="OtherInstallerSilent"
SourceFile="..\..\bootstrapper\OtherInstallerFile"
InstallCommand="/S "
InstallCondition="WixBundleUILevel=2"/>
<MsiPackage Id="MainMsiInstaller"
DisplayInternalUI="no"
SourceFile="..\..\bin\$(var.CandleCfgName)\MainMsiInstaller.msi" />
</Chain>

WiX Burn bootstrapper does not uninstall MSI package

I have created a Wix Burn boostrapper that successfully installs all of the chained packages. When I run uninstall, it doesn't uninstall the following MSI package. Why? Also, I realized this question has been asked, but none of the previously asked questions seem to have answers.
<MsiPackage Id="SyncManager" Name="Sync Manager 2.0" Permanent="yes" Vital="yes" Compressed="yes"
DownloadUrl="http://localhost/SyncManager2.0.msi" SourceFile="SyncManager2.0.msi">
<Payload DownloadUrl="http://localhost/SyncManager2.0.msi" SourceFile="SyncManager2.0.msi" Name="Synce Manager 2.0" />
</MsiPackage>
Thank you in advance.
Because you have Permanent="yes"

Wix burn upgrade needs to uninstall both MSI's before upgrading

I have two MSI's; framework.msi and product.msi. The framework.msi installs dll's into the GAC that the product.msi depends on for both install and uninstall.
I've created a BA that chains the two MSI's together.
<Bundle ...>
<Chain>
<PackageGroupRef Id='framework'/>
<PackageGroupRef Id='product'/>
</Chain>
</Bundle>
<Fragment>
<PackageGroup Id="framework">
<MsiPackage Name="Product Framework"
ForcePerMachine="yes"
SourceFile="framework.msi"
Vital="yes"
Cache="no"
Permanent="no"
Compressed="yes"
Visible="yes"/>
</PackageGroup>
<PackageGroup Id="product">
<MsiPackage Name="Product"
ForcePerMachine="yes"
SourceFile="product.msi"
Vital="yes"
Cache="no"
Permanent="no"
Compressed="yes"
Visible="yes"/>
</PackageGroup>
</Fragment>
For fresh installs, my framework.msi and product.msi install correctly. When I go to upgrade to a new version, it upgrades the framework.msi successfully. Then it proceeds to uninstall the product.msi but it fails (for this error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'CheckInstaller, Version=1.0.0.0' or one of its dependencies. The system cannot find the file specified.) because the uninstall CustomAction references a version of an assembly (CheckInstaller) that is no longer in the GAC (because it has been upgraded as part of the framework.msi upgrade).
Without having to write a custom BA, I want to be able to do something like this:
// pseudo code
if(product.Exists() && framework.Exists())
{
product.Uninstall(); // product is dependent on the framework
framework.Uninstall();
}
framework.Install();
product.Install();
I realize this would be possible if we were to combine the two MSI's into one big product but since we disperse the framework.msi to other teams and for various other reasons, they need to be kept separate.
Is what I want to do even possible to do with the WiX bootstrapper?
That isn't possible with Burn today. The chain is fixed. On install it runs through forward, on uninstall it runs through backwards. I can think of two options available today:
Do not have the MSI's upgrade each other and let the old MSIs be removed when the new Bundle uninstalls the old Bundle.
Avoid creating install time dependencies between packages. This generally is a good thing to do anyway.
A feature request might be to have the new Bundle have the ability to remove the old Bundle before installing instead of after like it is today, but that isn't supported at this point in time.

Specify the INSTALLLOCATION of packages in WiX inside the Burn managed bootstrapper

I have a WiX 3.6 bundle (using Burn) and managed bootstrapper that install several MSI packages. Some of the packages install to a common location (C:\program files\MyApp).
I want to let the user choose the install location inside the managed bootstrapper application (C# WPF, especially because the application is large to install; about 1 GB). How can I specify the INSTALLLOCATION for each MSI packages inside my bundle?
Use an MsiProperty child for each MsiPackage to specify INSTALLLOCATION=[BurnVariable]. Then use Engine.StringVariables to set BurnVariable.
For example, in your bundle you set:
<Bundle ...>
<Variable Name='BurnVariable' Value='bar' />
...
<Chain>
<MsiPackage Source='path\to\your.msi'>
<MsiProperty Name="INSTALLLOCATION" Value="[BurnVariable]" />
</MsiPackage>
</Chain>
</Bundle>
See also the FireGiant explanation on this topic.
Then in the managed bootstrapper you can do something similar to this:
Engine.StringVariables["BurnVariable"] = "C:\program files\MyApp";