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

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";

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.

WiX - How to declare global variables in WiX bundle?

I am writing a WiX bundling project which involves two MSIs. My requirement is to declare a "global variable" in the Bundle context, so that it can be referenced anywhere in the wxs files of any of the two MSIs.
Is there a possible way to accomplish this?
P.S. I am building the project in WiX v3 using Visual Studio extension.
Declare a variable in the bundle and pass it to the msi's
For example in the bundle:
<Variable Name="InstallFolder" Type="string" Value="[ProgramFiles6432Folder]$(var.Manufacturer)\[WixBundleName]"/>
<MsiPackage Id="Product" SourceFile="$(var.Product.TargetPath)">
<MsiProperty Name="INSTALLFOLDER" Value="[InstallFolder]" />
</MsiPackage>

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

Passing command line args to MSI from WiX bundle

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" />

Not possible to pass WixBundleProviderKey variable to msipackage

I have a problem with the burn built-in variable WixBundleProviderKey. I need to pass the value of this variable to an msi package. My problem is that the value of this variable is not evaluated, and the msi will only receive an empty string. I have tested with other built in variable and it works as expected.
Any ideas why this is not working? Is there a workaround?
Example:
<Fragment>
<PackageGroup Id="Test" >
<MsiPackage Id="Test"
DisplayName="Test 4.10.0002"
DisplayInternalUI="no"
Visible="no"
SourceFile=".\Template\ProductsToInstall\Test\Test 4.10.msi"
Name="Test\Test 4.10.msi"
Cache="yes"
CacheId="Test 4.10"
Compressed="no"
Vital="yes"
Permanent="no">
<MsiProperty Name="BURN_WIXBUNDLEORIGINALSOURCE" Value="[WixBundleOriginalSource]" />
<MsiProperty Name="BURN_COMMONAPPDATAFOLDER" Value="[CommonAppDataFolder]" />
<MsiProperty Name="BURN_WIXBUNDLEPROVIDERKEY" Value="[WixBundleProviderKey]" />
</MsiPackage>
</PackageGroup>
</Fragment>
Thanks in advance
This is a bug that should be fixed in v3.10: http://wixtoolset.org/issues/4630/
Try this trick.
You can create new variable with name "BUNDLE_KEY" (for example)
<Variable Name="BUNDLE_KEY" Type="string" Value="[WixBundleProviderKey]" />
And then apply this variable to MsiProperty:
<MsiProperty Name="YOU_PROPERTY_IN_MSI" Value="[BUNDLE_KEY]" />
I hope it will help you.
Not exactly the answer to the question, but maybe it helps.
In my case I needed to pass the value of WixBundleProviderKey variable to msi to get the full path to my BundeSetup.exe, which is cached in "CommonAppDataFolder\Package Cache\WixBundleProviderKey" directory. To do that I created a property with FileSearch element in msi, providing to the full path of the searching file.
<Property Id="BUNDLECACHEPATH">
<DirectorySearch Id="BundleDirSearch" Path="[CommonAppDataFolder]Package Cache" Depth="1">
<FileSearch Name="BundleSetup.exe" />
</DirectorySearch>
</Property>
Seems like the only way to pass WixBundleProviderKey value in Standard Bootstrapper Application is to pass it through InstallFolder variable:
<Variable Name="InstallFolder" Value="[WixBundleProviderKey]" />
The other solution is to pass it inside the path to the bundle setup temp files through DirectorySearch element variable:
<util:DirectorySearch Path="[TempFolder][WixBundleProviderKey]" Variable="KeyPath" />
<MsiProperty Name="BUNDLE_KEY" Value="[KeyPath]" />
The way to get WixBundleProviderKey in your msi from [BUNDE_KEY] property value is to implement C# Custom Action using String.Substring() method. And put it inside InstallUISequence before AppSearch event - if you want to use the obtained value inside RegistrySearch element.