How to set install privileges conditionally in Wix - wix

I'm using Wix 3.11 and trying to set the install privileges of my package conditionally.
What I'm trying to do is:
<?if Privileged = 0 ?>
<Package InstallerVersion="405" Compressed="yes" InstallScope="perUser" InstallPrivileges="limited" />
<?else ?>
<Package InstallerVersion="405" Compressed="yes" InstallScope="perMachine" InstallPrivileges="elevated" />
<?endif ?>
However this doesn't work. When installing, the one with elevated privileges is always picked.
Also, I've tried to create a variable in a .wxi file and set it like this:
.wxi file:
<?if Privileged = 0 ?>
<?define myScope = "perUser" ?>
<?define myPrivileges = "limited" ?>
<?else?>
<?define myScope = "perMachine" ?>
<?define myPrivileges = "elevated" ?>
<?endif?>
.wxs file:
<Package InstallerVersion="405" Compressed="yes" InstallScope="$(var.myScope)" InstallPrivileges="$(var.myPrivileges)" />
But the same happens again: elevated privileges are always picked.
I did my tests on 2 different machines, with non-admin users.
I did not find any solution on the internet so I'm wondering: is it possible to set up a package conditionally?
Thanks for your time.
EDIT:
I have found the AdminUser property, which seems to be exactly what I need.
I changed my wxs file accordingly to have AdminUser set:
<Package InstallerVersion="500" Compressed="yes" />
<SetProperty Id="MSIUSEREALADMINDETECTION" Value="1" Sequence="first"/>
<SetProperty Id="ALLUSERS" Value="2" Sequence="first"/>
<SetProperty Id="MSIINSTALLPERUSER" Value="1" Sequence="first"> <![CDATA[NOT AdminUser]]> </SetProperty>
When reading the log file of the installation, I noticed AdminUser was set before MSIUSEREALADMINDETECTION, and setting MSIUSEREALADMINDETECTION wouldn't trigger a reset for AdminUser.
I scheduled my SetProperties to the most prior action I could find, which was "FindRelatedProducts", however AdminUser is set even before that (actually before both installExecuteSequence and installUISequence), I was unable to get MSIUSEREALADMINDETECTION set first.
I believe there is no way to determine wether you are running your installation under an admin or a standard session.
If anyone know a solution, please feel free to advise.
Thank you Michael and Brian for your time.

Related

Wix: Creating Bootstrap .exe for .msp causes original version to uninstall

I am trying to create a Wix Bootstrap executable that contains an .msp patch file. I have generated the patch file using pyro.exe and the patch itself works absolutely fine and updates the required files correctly when ran by itself.
However we package all our .msi's in a Wix Bootstrap project with a custom user interface, which I have cloned for the patch files. However when running the executable this way it removes all the files from the install directory.
Has anyone experienced this issue before or am I doing something wrong? Thank you in advance, let me know if you need further code examples.
BootstrapBundle.wxs
<?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"
xmlns:vi="http://schemas.visualinstaller.de/VisualInstallerWixExtension">
<Bundle Name="MyProgram" Version="1.0.0.1"
Manufacturer="Test"
UpgradeCode="GUID"
SplashScreenSourceFile="Resources\splash.bmp"
IconSourceFile="Resources\icon.ico">
<Update Location="http://test.laika42.com/UpdateInfo.xml"/>
<BootstrapperApplicationRef Id='ManagedBootstrapperApplicationHost'>
<PayloadGroupRef Id='VisualInstallerRuntimeFiles'/>
</BootstrapperApplicationRef>
<Variable Name="INSTALLFOLDER" bal:Overridable='yes'
Value='[ProgramFilesFolder]Test\MyProgram\'/>
<Chain>
<PackageGroupRef Id='NetFx45Web' /> <!-- Fails to build without this? -->
<MspPackage Id='PatchMsp' SourceFile='C:\Patches\Patch.msp' />
</Chain>
</Bundle>
</Wix>
Just had this problem myself. It seems that the UpgradeCode for the bundle must be different to the UpgradeCode for the MSI - the bundle will remove anything older with the same Bundle UpgradeCode, including the original full MSI. I have to say I find the Wix documentation less than illuminating. Bdum-tsh.
The important bits seem to be having different UpgradeCodes for the MSI, the MSI bootstrapper bundle and the patch bootstrapper bundle but keeping each one of the three the same going forward, and the RelatedBundle element.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
<?include $(var.SolutionDir)\Installer\ProductDefs.wxi?>
<?include $(var.SolutionDir)\Installer\version.wxi?>
<!-- A DIFFERENT UpgradeCode to the main bundle, but consistent for all patches. I think. -->
<?define PatchBundleUpgradeCode = "AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA"?>
<!-- The UpgradeCode of the Bundle that was used to deploy the MSI originally. -->
<?define MSIBundleUpgradeCode = "BBBBBBBB-BBBB-BBBB-BBBB-BBBBBBBBBBBB"?>
<!-- ... both of which are different to the MSI UpgradeCode. -->
<Bundle Name="$(var.ProductName) $(var.ProductVersion)"
ParentName="$(var.ProductName)"
Version="$(var.ProductVersion)"
Manufacturer="$(var.Manufacturer)"
UpgradeCode="$(var.PatchBundleUpgradeCode)"
IconSourceFile="$(var.SolutionDir)\Installer\MyIcon.ico"
AboutUrl="https://www.somecompany.com/"
HelpUrl="https://www.somecompany.com/support/"
>
<BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.RtfLicense">
<bal:WixStandardBootstrapperApplication
LicenseFile="$(var.SolutionDir)\Bootstrapper\license.rtf"
LogoFile="$(var.SolutionDir)\Bootstrapper\Logo.jpg"
ShowVersion="yes"
SuppressOptionsUI="yes"
/>
</BootstrapperApplicationRef>
<OptionalUpdateRegistration Classification="Update" Name="$(var.ProductName) $(var.ProductVersion)"/>
<RelatedBundle Id="$(var.MSIBundleUpgradeCode)" Action="Patch" />
<Chain>
<MspPackage SourceFile="$(var.ProjectDir)\Release\$(var.ProductName) $(var.ProductVersion) Patch.msp" DisplayInternalUI="yes"/>
</Chain>
</Bundle>
</Wix>
Also, if you want to apply more than one minor patch, make sure your PatchMetadata element (in the patch.wxs, not the bundle.wxs) contains the following attribute otherwise the first patch will apply but subsequent ones won't.
MinorUpdateTargetRTM="1"

In Wix MSI: Killing a process upon uninstallation

I added a custom action that should kill my application using taskkill CMD when someone tries to uninstall it using the add/remove in the control panel using the following code :
<Property Id="TASKKILL">
<DirectorySearch Id="SysDir" Path="[SystemFolder]" Depth="1">
<FileSearch Id="taskkillExe" Name="taskkill.exe" />
</DirectorySearch>
</Property>
<CustomAction Id="ServerKill" Property="TASKKILL" Execute="immediate" Impersonate="yes" Return="ignore" ExeCommand="/F /FI "IMAGENAME EQ App.exe""/>
<InstallExecuteSequence>
<Custom Action="ServerKill" After="FindRelatedProducts"/>
</InstallExecuteSequence>
However this does not work. If someone can tell me how to fix it or even share a better/easier way to kill my app process I would be grateful.
p.s
also tried to use WMIC using cmd. That really didn't work and the installation itself did not finish at all because of this.
Perhaps you can try the CloseApplication feature from the Util schema:
http://wixtoolset.org/documentation/manual/v3/xsd/util/closeapplication.html
See here for an example code snippet: https://sourceforge.net/p/wix/mailman/message/20186650/
UPDATE: I ran some tests and this element works a little differently from what I expected. The first thing you need to add is the reference to the wixUtilExtension file. On the command line this is:
candle -ext WiXUtilExtension Test.wxs
light -ext WixUtilExtension Test.wixobj
In Visual Studio I think you simply add a project reference to WixUtilExtension.dll.
Then you simply add something like this to your wxs source file:
<util:CloseApplication Id="CloseNotepad" Target="notepad.exe"
CloseMessage="yes" RebootPrompt="no">
</util:CloseApplication>
And add this at the top of your wxs file:
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
It looks like Wix takes care of the rest (custom actions and a custom table in your MSI with the list of processes to kill).
Here is my full test file:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
<Product Id="*" UpgradeCode="12345678-1234-1234-1234-111111111111"
Name="Example Product Name" Version="0.0.1" Manufacturer="Example Company Name" Language="1033">
<Package InstallerVersion="200" Compressed="yes" Comments="Windows Installer Package"/>
<Media Id="1" Cabinet="product.cab" EmbedCab="yes"/>
<Directory Id="TARGETDIR" Name="SourceDir">
<Component Id="ApplicationFiles" Guid="*">
</Component>
</Directory>
<Feature Id="DefaultFeature" Level="1">
<ComponentRef Id="ApplicationFiles"/>
</Feature>
<util:CloseApplication Id="CloseNotepad" Target="notepad.exe" CloseMessage="yes" RebootPrompt="no"></util:CloseApplication>
</Product>
</Wix>
Links: Some related or marginally related links for easy retrieval.
Windows Installer-Avoid FileinUse dialog box when Installing a package
Reboot on install, Don't reboot on uninstall
How to kill a process upon uninstall using WiX
Wix's util:CloseApplication extension doesn't seem to work
Alternatively a simple VBScript scheduled to run on uninstall should do the job:
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process Where Name = 'Notepad.exe'")
For Each objProcess in colProcessList
objProcess.Terminate()
Next

Wix ProgramFiles64Folder is still

I am having a problem very similar to the one described here: ProgramFiles64Folder is installing to \Program Files (x86)\ in WIX Installer
However, the solution there does not work for me. Wix still generates a .msi that installs to C:\Program Files (x86)
I placed the following code in my Product.wxs file:
<?if $(var.Platform) = x64 ?>
<?define Win64 = "yes" ?>
<?define PlatformProgramFilesFolder = "ProgramFiles64Folder" ?>
<?define ConfigFolder = "Release" ?>
<?else ?>
<?define Win64 = "no" ?>
<?define PlatformProgramFilesFolder = "ProgramFilesFolder" ?>
<?define ConfigFolder = "Release_x86" ?>
<?endif?>
Then later I try to specify installation folder as follows:
<Directory Name="SourceDir" Id="TARGETDIR">
<Directory Name="$(var.PlatformProgramFilesFolder)" Id="$(var.PlatformProgramFilesFolder)">
...
I verified that var.Platform is set properly because it copies source files from the correct ConfigFolder. However, it seems that both ProgramFiles64Folder and ProgramFilesFolder are set to C:\Program Files (x86)
I verified that candle.exe is invoked with -dPlatform=x64 option.
I even tried to specify platform in my Package tag
<Package InstallerVersion="200" Compressed="yes" InstallScope="perMachine" Platform="x64" />
Nothing helps, it still tries to install to C:\Program Files (x86)
Any idea what else I can try?
Thank you.
I am using WiX version 3.9
It turned out that a different .wxs file was messing with WixPerUserFolder and other related variables.
The following code fix the problem:
<CustomAction Id="Overwrite_WixSetDefaultPerMachineFolder" Property="WixPerMachineFolder"
Value="[ProgramFiles64Folder][ApplicationFolderName]" Execute="immediate" />
<InstallUISequence>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
</InstallExecuteSequence>
BTW, I created a project to simplify the configuration of wix. Hope it can help: https://github.com/xinnj/WiXCover
The only thing I can think of is that the components you are installing to that location are 32-bit components, so they get redirected to the x86 location. A 64-bit package can have 32 and 64-bit components, so you may need to mark them explicitly as Win64='yes'
Follow the sample in this blog and release a new 64 bit package and you will have your installation in Program Files folder.
http://msdn.microsoft.com/en-us/library/gg513929.aspx
Using WixUI_Advanced? This doesn't set the correct default folder on x64.
Workaround is to add this to the Product item:
<!-- Workaround Wix Bug: https://github.com/wixtoolset/issues/issues/2165 -->
<CustomAction Id="Overwrite_WixSetDefaultPerMachineFolder" Property="WixPerMachineFolder"
Value="[$(var.PlatformProgramFilesFolder)][ApplicationFolderName]" Execute="immediate" />
<InstallUISequence>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
</InstallUISequence>
<InstallExecuteSequence>
<Custom Action="Overwrite_WixSetDefaultPerMachineFolder" After="WixSetDefaultPerMachineFolder" />
</InstallExecuteSequence>
<SetProperty Id="ARPINSTALLLOCATION" Value="[APPLICATIONFOLDER]" After="CostFinalize" />
For the bug description and the workaround source look here:
https://github.com/wixtoolset/issues/issues/2165

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: Conditionally including UpgradeCode in WiX file

I'm using WiX to build an installation package for a product at my company and I want to be able to build two slightly different versions of the .msi depending on if it is meant to be used internally in the company for testing or externally for customers.
The internal version should be built with no UpgradeCode, so that we can have several versions installed at the same time for comparison. The external version should have a static UpgradeCode.
WiX does not allow me to have UpgradeCode auto generated by doing this:
<?if $(var.Configuration) = "Internal Release"?>
<?define UpgradeCode = "*"?>
<?else?>
<?define UpgradeCode = "[REALGUID]"?>
<?endif?>
<Product ... UpgradeCode="$(var.UpgradeCode)">
To have the UpgradeCode "auto generated" you have to completely ommit the UpgradeCode attribute.
Anyone have any suggestions on how to accomplish this?
Probably you can't use * for Upgrade Code (i'm not sure) but you could pass it as property through msbuild which i do for ProductCode conditionaly (if we are building patches or not)
<UpgradeCode Condition="$(InternalRelease)==1">{$([System.Guid]::NewGuid().ToString().ToUpper())}</UpgradeCode>
In your msbuild.proj add that property in your Target/msbuild project/Properties.
Add UpgradeCode=$(UpgradeCode) in you constants (wixproj)
Then in your main wxs add something like this:
<?if $(var.UpgradeCode)=""?>
<?define UpgradeCode=your-static-upgradecode ?>
<?endif?>
So if the project receives the upgrade code then it will use that one otherwise will be your fixed upgrade code in defined.
And finally to generated the guid call the msbuild.proj with /p:InteralRelease=1
Adding this answer as an alternative solution for other users with the same challenge.
Altough IlirB's answer probably would work as expected (I haven't tried it as I solved the problem with my own solution before the answer was provided), I solved the problem by conditionally including one of 2 different versions of the Product-tag. Of which only one had the UpgradeCode defined.
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?include Config.wxi?>
<?if $(var.IsExternalRelease) = yes?>
<Product Id="$(var.ProductID)" Name="$(var.ProductName)" Language="1033" Version="$(var.Version)" Manufacturer="$(var.Manufacturer)" UpgradeCode="$(var.UpgradeCode)">
<Package Id="$(var.PackageID)" InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MajorUpgrade AllowSameVersionUpgrades="yes" DowngradeErrorMessage="A newer version of [ProductName] is already installed." />
<MediaTemplate EmbedCab="yes"/>
<PropertyRef Id="AllProperties"/>
<UIRef Id="CUSTOM_UI"/>
<FeatureRef Id="F_AllFeatures"/>
</Product>
<?else?>
<Product Id="$(var.ProductID)" Name="$(var.ProductName)" Language="1033" Version="$(var.Version)" Manufacturer="$(var.Manufacturer)">
<Package Id="$(var.PackageID)" InstallerVersion="200" Compressed="yes" InstallScope="perMachine" />
<MediaTemplate EmbedCab="yes"/>
<PropertyRef Id="AllProperties"/>
<UIRef Id="CUSTOM_UI"/>
<FeatureRef Id="F_AllFeatures"/>
</Product>
<?endif?>
</Wix>
Because I made an effort in splitting the wix code into several pieces and referring them from the Product tag, there was not much duplication of code.