Skip MSI if already installed - wix

I have a WIX installer in which I install my program and .NET Core 1.0.5. The .NET Core is installed in silent mode:
<ExePackage InstallCommand="/q" Id = "DotNetCore.Setup" SourceFile="..\DotNetCore\DotNetCore.exe" />
On a clean system, the installer just goes fine. If I try to reinstall it, I get a reboot. Probably the .NET installer detected to be already installed and triggered the repair feature on its own. Is there any way to skip the .NET Core installation if it's already installed?
I tried looking for command line parameters but nothing seems useful

The ExePackage element has the DetectCondition property. This means that you can specify a condition such that, if the condition evaluates to false, the package will be installed. You can combine this with an util:RegistrySearch element which can be used to search through the registry to detect if the .NET Core has already been installed.
In order to perform the registry search, you will first need to find a registry key which is present whenever .NET is installed.
Find the "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\",
(or "HKLM\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\" on 64-bit machines) key in your registry, then locate the subkey which corresponds to the .NET Core - this key should have a value for "DisplayName" which should be ".NET Core" or something similar.
The correct key, once found, should have a name which is a string of hex characters - this is one of the GUIDs corresponding to the .NET Core program. You can then use the following code to allow the installer to search for the presence of this key:
<util:RegistrySearch Id="VCRedistTest32" Root="HKLM" Key="SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{YOUR_GUID_HERE}" Result="exists" Variable="DOTNETPresent" Win64="no"/>
(Use Win64="yes" instead for the 64-bit registry)
You can then use the following for the ExePackage:
<ExePackage InstallCommand="/q" Id = "DotNetCore.Setup" SourceFile="..\DotNetCore\DotNetCore.exe" DetectCondition="DOTNETPresent"/>
Don't forget to add the reference to the util extension to the top-level wix element:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">

You need to use DetectCondition attribute and registry search that assign property in case the .net Core is installed.
ExePackage Element - DetectCondition
"A condition that determines if the package is present on the target system. This condition can use built-in variables and variables returned by searches. This condition is necessary because Windows doesn't provide a method to detect the presence of an ExePackage. Burn uses this condition to determine how to treat this package during a bundle action; for example, if this condition is false or omitted and the bundle is being installed, Burn will install this package."

Related

Wix toolset Bundle Chain installation global condition

CONTEXT: I created a Bootstrapper installer in order to install, if needed, the .net framework 4.8. together with the setup program I want to deliver with it.
Up to here all works nice: my program gets installed always and the .net just if needed.
The thing is that I need to add some more checks to this installer, for example check for a registry key (if another program proper version is installed) and if this does not meet the condition, then the complete installation should be aborted, nothing should be installed.
PROBLEM: the InstallCondition I have added affects just the MsiPackage but the rest of the installation seems to be considered as totally fine and installation finishes successfully, here the interesting part of code:
<util:RegistrySearch Id="OtherProgramVersionId" Root="HKLM" Key="SOFTWARE\XXX\Install::Version" Variable="OtherProgramVersion"/>
<Chain>
<PackageGroupRef Id="NetFx48Redist" />
<MsiPackage
Id="MySuperProgram.Setup"
SourceFile="$(var.MySuperProgram.Setup.TargetPath)"
InstallCondition="OtherProgramVersion >= v10.0"/>
</Chain>
As said before, even the registry key is not found or it does not fulfill the condition, the installation seems to continue "successfully" and I get it in the ControlPanel->Programs as installed... but the main .msi was not really installed! (checking the destination folder, it's empty)
QUESTION: How can I add a global condition in order to stop completely any installation at all and show the user a message with the condition not fulfilled? If possible with a standard dialog.
I have seen (and I am still experiencing) with conditions, but seems they affect just one of the items in the chain... or they seem to break the installation somehow, I have tried adding to the .msi setup creation, file Product.wxs, the condition in order to abort this installation, but when installing I get this not passed condition as a setup error, seems the exit is not clean at all... even able to see the log where I see something like this:
Error 0x80070643: Failed to install MSI package.
Thanks in advance!
If you're using WixStandardBootstrapperApplication, you can use bal:Condition to define bundle-level conditions. The WiX documentation has a sample: https://wixtoolset.org/documentation/manual/v3/howtos/redistributables_and_install_checks/block_stdba_install_on_reg.html

Wix Burn: How to store the custom InstallFolder for later modifications?

I'm trying to solve this for a while now. I've authored a custom UI for my Bootstrapper Application. Setting a default value for InstallFolder is not the problem, but when the user changes this path, how can I store this path for later changes in add/remove programms, e.g. when another Package in the bundle should be installed by modifying the Bundle?
To write in the Registry could be an option, but the Bootstrapper Application doesn't run elevated all the time, so that it can't write to HKLM. But there should be a way to do this, I saw similar things for Visual Studio...
You should be storing the InstallFolder value in the registry in one (or all depending on how it is authored) of your MSIs that are packaged with the bootstrapper application. On startup you can use a util:RegistrySearch to look for and set the InstallFolder in the bootstrapper.
<Fragment>
<util:RegistrySearch
Id="ServerInstalledCheck"
Root="HKLM"
Key="SOFTWARE\$(var.OEMRegistryRootKeyName)\v7"
Value="ServerPath"
Result="value"
Variable="ServerInstalled"/>
<util:DirectorySearch
Path='[ServerInstalled]'
Variable='InstallFolder'
After='ServerInstalledCheck'
Condition='ServerInstalled' />
</Fragment>
I think you can directly set the variable InstallFolder in the registry search itself and omit the DirectorySearch. The DirectorySearch approach was used just to ensure we only set the InstallFolder to a location that actually exists on the machine. There may be other advantages as well but I can't think of them at the moment.
This will retain your default InstallFolder location on a fresh install and 'remember' the selected install location when running to uninstall/modify/upgrade.
You are right that you cannot rely on writing any registry keys inside your bootstrapper application because it is not guaranteed (and really shouldn't be) run elevated.
This is basically following the 'remember property' pattern which is explained here. Whenever you want to remember a value set in a previous install during modify/upgrade/removal, this is generally the go to.

Wix Check if Application Initialization is installed on 2008R2

I need to check if Application Initialization is installed on a 2008R2 Server.
The app is not installed as a feature, it is an IIS Module that I downloaded from the following link.
The problem I'm having is where does the folders actually get placed to be able to perform a search in my WiX project to see if they exist or not.
TLDR:
Look for the Version value in HKLM\SOFTWARE\Microsoft\IIS Extensions\Application Initilaization. Current version is 7.1.1636.0.
Full answer:
Since this is a MSI installation package, you can open it using Orca and search for any registry key being created.
Then in Orca, you open the Registry table and find the
row with Registry=reg8BD5741527F144C70BDB7B0134BC7B84. In it, you will find the Key where the value will be created, the Name of it and the Value.
This way, you can easily perform a registry search and evaluate if the module is installed.
EDIT
To perform a search during launch and verify if the module is installed, add the following code:
<Property Id="MODULEINSTALLED">
<RegistrySearch Id="IsModuleInstalled"
Root="HKLM"
Key="SOFTWARE\Microsoft\IIS Extensions\Application Initilaization"
Name="Version"
Type="raw" />
</Property>
Then use the property in a condition:
<Condition Message="This application requires Application Initialization module. Please install the Application Initialization module then run this installer again.">
<![CDATA[Installed OR MODULEINSTALLED]]>
</Condition>

WiX bootstrapper: Uninstall packages in a chain

<ExePackage Id="PackageID1" DisplayName="xxx" Compressed="yes"
SourceFile="..\xxx\MyExe.exe" Vital="yes"
InstallCommand="parameters to the exe"
UninstallCommand="parameters to the exe"/>
When I trigger the Uninstall action:
this.Engine.Detect();
this.Engine.Plan(LaunchAction.Uninstall);
this.Engine.Apply(System.IntPtr.Zero);
The exePackage does not get invoked. However, during Install, it enters the exe package with the right parameters.
Am I missing something here?
You need a DetectCondition attribute on your ExePackage element. The DetectCondition is how the Burn engine determines if the package is installed on the machine or not. Without a DetectCondition the engine will think the package is never installed so it will never need to be uninstalled. Since all executables are different you have to provide your own DetectCondition. Usually the XxxSearch elements in the util namespace are helpful to detect if your executable is installed.
Note: you can see the 'plan' in the log file and it should show the PackageID1 package being detected as 'Absent' even though it is installed.

Wix bootstrapper uninstall shortcut

I am trying to create shortcuts to uninstalling whatever the bootstrapper has installed.
So simply i want to do the same thing as the uninstall does when going to Add and remove programs.
I found that de bootstrapper is installed in package cache{guid}[bootstrappername].exe
One of the msi packages that it installs also installs a shortcut to this bootstrapper /uninstall call.
However problem is that the GUID of the package is regenerated on every build. So i some how have to set it as
a msi property.
But i cannot figure out how to do this, seem to me that the GUID is not known during building but only after build is done?
is there another way to determine the location of the cached bootstrapper ?
If you are use Managed BA you can try this:
In your Bundle.wxs in chain with MsiPackage add MsiProperty like:
<MsiPackage SourceFile="Setup.msi">
<MsiProperty Name="UNINSTALLER_PATH" Value="[UNINSTALLER_PATH]"/>
</MsiPackage>
Somewhere in code (before call install action), you need set value for this variable like this:
Engine.StringVariables["UNINSTALLER_PATH"] = string.Format(#"{0}\{1}\{2}\{3}.exe", Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Package Cache", Engine.StringVariables["WixBundleProviderKey"], ProductName);
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) – path to %systemdir%:\ProgramData
Package Cache- folder name in ProgramData where installing bundle caching
Engine.StringVariables["WixBundleProviderKey"] – name of folder (guid) created by caching bundle
ProductName – name of your bootstrapper “exe”
And finally in your Product.wxs you can create shortcut usual way, but in “Target” attribute you need pass UNINSTALLER_PATH value and “Arguments” set ="/uninstall":
<Shortcut Id="Shortcut1" Name="Uninstall" Description="Uninstall" Target="[UNINSTALLER_PATH]" Arguments="/uninstall" WorkingDirectory="Programmenufolder" />
sorry for my english :)
You can determine the location using the bundle upgradecode you define in your bundle.wxs.
Use the registry path to windows uninstall location of your bundle
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall{upgradecode of your bundle}
or for 64 Bit OS
HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall{upgradecode of your bundle}
The value BundleCachePath contains the fullpath including your bootstrapper.exe filename to the package cache where your bundle is cached.
You can also use the value QuietUninstallString which contains the full quiet uninstall command or UninstallString to launch the uninstall in non quiet mode.