Passing command line args to MSI from WiX bundle - wix

I’m on Wix 3.7. I have an MSI that I would like to set a registry key (perhaps via a Custom Action, as he will have to check if the key already exists).
I understand that a Bundle in a bootstrapper project can't change the machine state (such as setting the registry). Therefore, I'm attempting to pass a command line argument via <MsiProperty>, but doesn't appear to show up as a command line argument in my log file for the bootstrapper.
Is it possible to set a registry key up in a Bundle?
If not, how can I add a command line argument (or some other piece of custom data)
to be passed to the MSI.
How can the MSI read whatever it is I pass to it (whether It ends up being a command line arg or something
else).
Bundle:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Bundle
Name="MyInstallerBootstrapperLocalDb"
Version="1.0.0.0"
Manufacturer="some company"
UpgradeCode="PUT-GUID-HERE">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense" />
<Chain>
<MsiPackage Id="MyInstallerInstaller"
SourceFile="$(var.MyInstallerInstaller.TargetPath)"
Compressed="no">
<!-- TODO - if this is being set correctly, the MSI needs to
interpret it and set up the key-->
<MsiProperty Name="SetLocalDb" Value="yes"/>
</MsiPackage>
</Chain>
</Bundle>
</Wix>

Your MSI needs to define a property like so:
<Property Id="SOMEPROPERTY" Value="Default"/>
You can then set this property from the bundle:
<MsiPackage SourceFile="<package>.msi" Id="SomeId">
<MsiProperty Name="SOMEPROPERTY" Value="[SomeProperty]" />
</MsiPackage>
After this you can set the property in the Bootstrapper as described here: WiX Bootstrapper: How do I set burn variables from the command line?
Notice that SomeProperty is a Burn variable which you have to define:
<Variable Name="SomeProperty" Type="string" Value="DefaultValue" />
Update:
In the MSI you are then able to do a registry search based on this property:
<RegistrySearch Id="GetSomeValue" Root="HKLM" Key="SOFTWARE\<Manufacturer>\[SOMEPROPERTY]" Name="<ValueName>" Type="raw" />

Just to add an extra bit of information. To alter the variable values with command line, I actually had to set it as overriable.
<Variable Name="SomeProperty" Type="string" Value="true" bal:Overridable="yes" />

Related

SqlLocalDB 2019 MSI ignores ARPSYSTEMCOMPONENT from Wix bootstrapper

I have a Wix Bootstrapper application which launches the SqlLocalDB 2019 MSI installer. It works great and everything is installed properly.
In the MsiPackage I'm passing ARPSYSTEMCOMPONET=0 to ensure that the "Microsoft Sql Server 2019 LocalDB" entry appears in Add/Remove Programs on Windows 10.
<?xml version="1.0" encoding="UTF-8"?>
<WixVariable Id="WixUILicenseRtf" Value="$(var.ProjectDir)\Resources\eula_en-us.rtf" />
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication LogoFile="$(var.ProjectDir)\Resources\cs.png"
LicenseFile="$(var.ProjectDir)\Resources\eula_en-us.rtf"
ThemeFile="$(var.ProjectDir)\Resources\customtheme.xml"
SuppressOptionsUI="yes"
SuppressRepair="yes" />
</BootstrapperApplicationRef>
<Chain>
<MsiPackage Id="SqlLocalDBPackage"
DisplayName="Installing Prerequisites... :)" Vital="yes" Visible="yes" Permanent="yes"
SourceFile="$(var.ProjectDir)\Resources\SqlLocalDB2019.msi" >
<MsiProperty Name="ARPSYSTEMCOMPONENT" Value="0"/>
<MsiProperty Name="IACCEPTSQLLOCALDBLICENSETERMS" Value="YES" />
</MsiPackage>
</Chain>
the Logfile for the Sql Installer does show that ARPSYSTEMCOMPONENT=0 and SYSTEMCOMPONENT=0 within the SqlLocalDB2019 MSI installer.
MSI (s) (9C:EC) [10:13:12:576]: Command Line: MSIFASTINSTALL=7 ARPSYSTEMCOMPONENT=0 IACCEPTSQLLOCALDBLICENSETERMS=YES REBOOT=ReallySuppress CLIENTUILEVEL=3 MSICLIENTUSESEXTERNALUI=1 CLIENTPROCESSID=25032
MSI (s) (9C:EC) [10:13:24:346]: Executing op: ProductRegister(UpgradeCode={F0176A51-908A-4240-8853-E229D0AE3F39},VersionString=15.0.2000.5,HelpLink=https://go.microsoft.com/fwlink/?LinkId=230480,,,InstallSource=C:\ProgramData\Package Cache\{F4F4157C-0951-4F00-8530-E3A6B2BE8606}v15.0.2000.5\,Publisher=Microsoft Corporation,,,,,,,,,,,SystemComponent=0,EstimatedSize=264308,,,,)
however, in the Registry, it will always be set to 1 and the package does not appear in ARP. However, if I manually reset it to 0, it does appear.
Note that I have also tried setting ARPSYSTEMCOMPONENT to "YES", "NO", "1" and "0" and they all result in SystemComponent being 1 in the registry.
I'm stumped on this one....any ideas would be greatly appreciated.
TIA!
Remove:
Remove this whole property from your source:
<MsiProperty Name="ARPSYSTEMCOMPONENT" Value="0" />
Visible Attribute:
Ensure the Visible attibute is set to "yes" in the MsiElement:
<MsiPackage Id="MyMSI" Visible="yes" SourceFile="Test.msi" />
This setting will auto-magically handle the ARPSYSTEMCOMPONENT property writing. It seems to properly override anything specifically defined inside the third party MSI involved. Just did a smoke test.
Custom Actions: It is possible for custom actions to do something weird and set this property or write to this registry location.

How to pass AddLocal-Parameter from wix standard bootstrapper to a MsiPackage

With WIX Tools v3.10 I used to add a variable AddLocal to the bundle which I passed to the MsiProperty with the Name="ADDLOCAL" as described by BryanJ in "Pass parameters from bootstrapper to msi bundle package".
<Bundle>
...
<Variable Name="InstallLevel" Type="numeric" bal:Overridable="yes" Value="1"/>
<Variable Name="AddLocal" Type="string" bal:Overridable="yes" Value=""/>
<Chain>
<MsiPackage Id="Addin64bit_loc" Vital="yes" DisplayInternalUI="yes" ...
EnableFeatureSelection="yes" >
...
<MsiProperty Name="INSTALLLEVEL" Value="[InstallLevel]"/>
<MsiProperty Name="ADDLOCAL" Value="[AddLocal]"/>
</MsiPackage>
</Chain>
</Bundle>
Now after switching to v3.11 I get this warning which will turn to an error in v4:
Warning CNDL1149: The 'ADDLOCAL' MsiProperty is controlled by the bootstrapper and cannot be authored.
(Illegal properties are: 'ACTION', 'ADDLOCAL', 'ADDSOURCE', 'ADDDEFAULT', 'ADVERTISE', 'ALLUSERS', 'REBOOT', 'REINSTALL', 'REINSTALLMODE', or 'REMOVE'.)
Remove the MsiProperty element.
This restriction will be enforced as an error in WiX v4.0.
So what is the adequate way in v3.11 to pass an ADDLOCAL parameter from bootstrapper command line to the Msi?
you can influence on ADDLOCAL parameter in your custom bootstrapper project something like that:
_bootstrapper.PlanMsiFeature += (_, ea) =>
{
ea.State = (needToInstall) ? FeatureState.Local : FeatureState.Absent;
};
I ran into the same issue and ended up using a transform with only the ADDLOCAL property set.
Rather than using AddLocal, I found adding code like:
<Feature Id="FeatureB" Level="0">
<Condition Level="1">INSTALL_FEATUREB="1" OR FEATUREB_INSTALLED="1"
</Condition>
</Feature>
to my msi file behaved in a reasonable manner, allowing me to add/remove a feature.
Modified from:
using https://support.firegiant.com/hc/en-us/articles/230912227-Control-feature-states-for-silent-install-
I like using the 'Variable=X' syntax because I find it easier to read. Without the FEATUREB_INSTALLED test I found uninstall did not act as I wanted.
Well, you can always pass a value to a Variable from the Code behind like this.
Bootstrapper.Engine.StringVariables["AddLocal"] = "your value";

How do I use burn's new ability to ability to launch an elevated process after installation is complete?

The current set of samples on how to use wix's new ability to run an elevated process through the engine is very sparse, if it exists at all. From the WIP and the schema docs, I can see that I need a minimum of the following:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<Bundle Name="..." Version="1.0.0.0" Manufacturer="..." UpgradeCode="*">
<BootstrapperApplicationRef
Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication
LaunchTargetElevatedId="LaunchElevatedInstallProc"
LaunchArguments="/myarg=1"
LicenseFile="license.rtf" />
</BootstrapperApplicationRef>
<ApprovedExeForElevation
Id="LaunchElevatedInstallProc"
Key="SOFTWARE\Company\Product"
Value="PathToExeDeliveredByMSI" />
<Chain>
<MsiPackage SourceFile="Setup.msi" Compressed="yes" />
</Chain>
</Bundle>
</Wix>
The Key attribute of <ApprovedExeForElevation> makes sense; it's a registry path to the entry that was created in my msi. The Value attribute is the ValueName in the registry that I created, containing the path to the .exe that I delivered in my install:
<Component Id="Comp_Client_Service.exe" Guid="PUT-GUID-HERE">
<File Id="my.exe" Name="my.exe" Source="my.exe" KeyPath="yes" />
<RegistryValue
Root="HKLM"
Key="SOFTWARE\Company\Product"
Name="PathToExeDeliveredByMSI"
Value="[INSTALLFOLDER]my.exe"
Type="string"/>
</Component>
Yet, this does not appear to be working. My .exe never launches, and the .log file provides no information that it is even attempting to launch it.
What is this code missing?
EDIT
The only piece of information that the log provides is that it is setting variables:
Initializing string variable 'LaunchTargetElevatedId' to value 'LaunchElevatedInstallProc'
Initializing string variable 'LaunchArguments' to value '/s'
According to the documentation, the TargetPath attribute on the WixStandardBootstrapperApplication must also be set. WixStdBA falls back to launching the exe at this path unelevated if anything went wrong trying to launch it elevated.
Id of the target ApprovedExeForElevation element.
If set with LaunchTarget, WixStdBA will launch the application
through the Engine's LaunchApprovedExe method instead of through ShellExecute.
You also need a button on the Success page with the name LaunchButton in your theme.

WiX Burn: Reading LaunchTarget from Registry

I'm new with WiX, and I'm trying to have my Bootstrapper launch my installed application when it completes. To accomplish this, I'm using
<Variable Name="LaunchTarget" Value="path_to_exe"/>
However, it is not easy for me to get the path to the executable. The reason for this is because I'm using <Chain> to install some pre-requisites and then an msi that actually installs my exe.
So to do this, the msi is writting the path to a known location in the registry, and then the bootstrapper reads it and uses it.
The problem is that when the bootstrapper reads the registry, the msi hasn't run yet, so it is unable to run the executable at the end.
Here's my WiX, if it helps:
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Bundle Name="My Installation" UpgradeCode="a8964402-f3fc-4878-aafd-31ecda6b685e" Version="1.0.0.0">
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication LicenseFile="EULA.rtf"
ThemeFile="theme.xml"
SuppressOptionsUI="yes" />
</BootstrapperApplicationRef>
<Chain>
<PackageGroupRef Id="NetFx40Redist"/>
<ExePackage Id="OpenSSL" SourceFile="pre-requesite.exe" />
<MsiPackage Id="myInstall" SourceFile="mySetup.msi" />
</Chain>
<util:RegistrySearch Root="HKLM"
Key="Software\myProgram"
Value="myEXEPath"
Variable="myEXEPath"
Result="value"
Format="raw" />
<Variable Name="LaunchTarget" Value="[myEXEPath]"/>
</Bundle>
</Wix>
So, in short, I'm trying to have the RegistrySearch run AFTER the MsiPackage installs. Can this be done? If not, what alternatives do I have?
As I side note, if I manually fill in the registry value before installation, everything works fine. This means that besides the order things are running in, everything is working fine.
RegistrySearches run during the Detect operation. Custom BAs could run Detect after Apply, but that's not really an option since you're using the WixStandardBootstrapperApplication.
Lucky for you, WiX v3.9 added support for running the LaunchTarget already elevated, with the requirement that the path to the target .exe be in the registry under HKLM. So you would do this:
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication LicenseFile="EULA.rtf"
ThemeFile="theme.xml"
SuppressOptionsUI="yes"
LaunchTargetElevatedId="MyAEEId" />
</BootstrapperApplicationRef>
<ApprovedExeForElevation Id="MyAEEId"
Key="Software\myProgram" Value="myEXEPath" />
Edit:
It looks like you are required to set LaunchTarget as well. Why doesn't your bundle know where it will be? You can just put in gibberish for LaunchTarget (WixStdBA will try the registry location first), but can't you use built-in variables and/or MsiProperty elements to locate the exe?

How to select features from an MsiPackage contained in a Bundle element?

I have a exe I created using WiX Burn v3.8. Let's call it Bundle.exe. In this bundle, I have an MSI with 3 features, two are nested under the one. I want to call Bundle.exe from the command line and pass the selected features into my MSI. I should note that I have an existing UI that let's the user select which features to install, so I don't want to use the WiX Bootstrapper app.
//Fragment of my MSI.wxs
<Feature Id="One">
//ComponentRefs
<Feature Id='A' >
//ComponentRefs
</Feature>
<Feature Id="B" >
//ComponentRefs
</Feature>
</Feature>
//Fragment of my Bundle.wxs
<Bundle>
<Chain>
//List of MsiPackages
</Chain>
</Bundle>
In the default bootstrapper this is how we pass the arguments from command line:
<Wix>
<Bundle>
<Variable Name="CommandLineArgument" bal:Overridable="yes"/>
<Chain>
<MsiPackage>
<MsiProperty Name="CommandLineArgument" Value="[CommandLineArgument]"/>
</MsiPackage>
</Chain>
</Bundle>
</Wix>
Make a note of the BAL:Overridable. That's how I was able to make sure that we can pass the property value from command line. Don't forget to add the namespace declaration to the Wix element xmlns:bal="http://schemas.microsoft.com/wix/BalExtension", and link to the WixBalExtension.dll.
In your case, the MSI property that you should be assigning the feature value[s] should be "ADDLOCAL".
<MsiProperty Name="ADDLOCAL" Value="[CommandLineArgument]"/>
To execute the bundle from commandline do the following:
bundle.exe CommandLineArgument=One,A,B