How can I optionally install IIS virtual directory with WiX Toolset? - wix

I'm trying to optionally install a virtual directory if IIS is installed. If it's not installed, then just skip it.
I've got this check:
<Fragment>
<Property Id="IIS_MAJOR_VERSION">
<RegistrySearch Id="CheckIISVersion"
Root="HKLM"
Key="SOFTWARE\Microsoft\InetStp"
Name="MajorVersion"
Type="raw" />
</Property>
<iis:WebSite Id='DefaultWebSite' Description='Default Web Site' Directory='INSTALLFOLDER'>
<iis:WebAddress Id="AllUnassigned" Port="80" />
</iis:WebSite>
</Fragment>
and based on the IIS_MAJOR_VERSION being present, I install the feature:
<Feature Id="ProductFeature2" Title="Setup" Level="1">
<ComponentRef Id="AppIIS" />
<Condition Level="0">NOT IIS_MAJOR_VERSION</Condition>
</Feature>
This part seems to work, however, the iis:WebSite node is causing issues. I only want to locate it if IIS_MAJOR_VERSION is present as well.
If I move the iis:WebSite node into the component group it works, but then iis:WebSite is not in 'locator' mode and gets installed and uninstalled (which is bad).
Is there a way I can conditionally run the check for iis:WebSite?

When you add any element from IIS extension (like <iis:WebSite>), a special custom action called ConfigureIIs is added to the InstallExecuteSequence table. This custom action is a so-called entry point to everything related to IIS management with the help of WiX IIS extension.
Fortunately, ConfigureIIs custom action is conditioned by default the way to skip it if need be. If you open the resulting MSI package with Orca and navigate to InstallExecuteSequence table on the left pane, you'll see the condition uses SKIPCONFIGUREIIS property. Thus, the idea is to set it to something (e.g. 1) in case you don't need to perform any IIS related activities.
It can be done with SetProperty element:
<SetProperty Id="SKIPCONFIGUREIIS" Value="1">NOT IIS_MAJOR_VERSION</SetProperty>

Related

VC redistributable fails to install when executed within an MSI [duplicate]

I have an application compiled in VS 2015 and requires the VC++ Redistributable package in order to run properly. Prior to this latest build, we were using an older version of VS and simply used a merge module to handle the installation of the appropriate redist files. However, I noticed that when using the latest version of the merge modules for 2015 (Microsoft_VC140_CRT_x64.msm) that my application still wouldn't work out of the box. I did some digging and it appears that some things have changed with the latest version of the merge modules. It appears that Microsoft is now recommending to install the vcredist_x64.exe package directly instead of using merge modules.
So, I'm attempting to create a custom action to do this. I'm following a similar tutorial here, although adapting it for the VC Redistributable executable. The first thing I need to do is setup where the .exe file is going to be placed once installed:
<Directory Id='APPLICATIONROOTDIRECTORY' Name='MyApp'>
<Directory Id="VCREDISTDIR" Name="VCRedist">
</Directory>
</Directory>
Then, I need to add my files into a component group which will be installed as part of a hidden feature (as I want this to be automatically installed).
<ComponentGroup Id="VCRedist" Directory="VCREDISTDIR">
<Component Id="vcredist_x64.exe" Guid="-INSERT-GUID-HERE-" Win64="yes">
<File Id="VCREDISEXE" Name="vcredist_x64.exe" KeyPath="yes" Source="$(var.VCRedistSourceDir)" Checksum="yes"></File>
</Component>
</ComponentGroup>
And...
<Feature Id="VCRedistributable" Title="Visual C++ Runtime" AllowAdvertise="no" Display="hidden" Level="1">
<ComponentGroupRef Id="VCRedist" />
</Feature>
At this point, the vcredist_x64.exe should be copied to the end user's machine. Now, I need to create a custom action to launch the executable after the installation.
<CustomAction Id="InstallVCRedistributable"
FileKey="VCREDISEXE"
Execute="deferred"
ExeCommand="/silent"
Impersonate="no"
Return="check"/>
<InstallExecuteSequence>
<Custom Action="InstallVCRedistributable" Before="InstallFinalize">
<![CDATA[NOT REMOVE]]>
</Custom>
</InstallExecuteSequence>
I also include a status message to my UI so that I can see when the executable is being executed.
<UI>
<ProgressText Action="InstallVCRedistributable">Installing Visual C++ Redistributable for Visual Studio 2015</ProgressText>
</UI>
Now, when I run my installer it should launch the vcredist_x64.exe... and it does... but then during the installation of that executable it gets hung up. I get a popup message that says there is a problem with this Windows Installer Package and that a program run as part of the setup did not complete. It then rolls-back my main application installation and never gets installed. Can anyone explain why this is happening and how to fix it? Thanks!
I found this question and tried it myself, being in the same situation. I found the installer error you're running into was/is Error 1618: "Another installation is already in progress." It seems that running the vc_redist installer inside your own installer simply won't work.
Your other options seem to be creating a bootstrapper as Patrick Allwood suggests above, or simply asking users to install the vc_redist package on their own before running your own installer. You can detect if the Universal C Runtime is already present by checking for ucrtbase.dll in C:\Windows\System32:
<Property Id="UCRTINSTALLED">
<DirectorySearch Id="UCRTSystemSearch" Path="[WindowsFolder]System32" Depth="0">
<FileSearch Id="UCRTFileSearch" Name="ucrtbase.dll" MinVersion="10.0.10240.16389" />
</DirectorySearch>
</Property>
If you only have a 32-bit installer, you can also use the [SystemFolder] property directly.
EDIT: As Kevin Smyth mentioned, the version of ucrtbase.dll is giving weird issues - reporting version 2.X to some tools, and version 10.Y to other tools. You can remove the MinVersion property if you just want to check for the existence of ucrtbase.dll.
I think the correct approach to take when having prerequisites that have their own installers is to create a WiX bootstrapper bundle, which runs through each installer in turn. This handles things like rollbacks on install failures, etc, which running custom actions from within an installer does not.
A barebones sample can be seen here, you add <MsiPackage> and <ExePackage> in the Chain element in the order you need them to install.
I was facing a similar problem (fully described in this closed question, which actually redirected me here). I was able to solve it, inspired by this entry about running the application after setup.
The key part is basically to add a final step to the UI that launches the vcredist installer:
<UI Id="UI_Main">
<!-- ...... -->
<Publish Dialog="ExitDialog"
Control="Finish"
Event="DoAction"
Value="InstallVCRedistributable">1</Publish>
</UI>
Regarding the custom action:
<CustomAction Id="InstallVCRedistributable"
FileKey="VCREDISEXE"
ExeCommand="/install /passive /norestart"
Impersonate="yes"
Return="asyncNoWait" />

WIX run vcredist_x64.exe on install

I have an application compiled in VS 2015 and requires the VC++ Redistributable package in order to run properly. Prior to this latest build, we were using an older version of VS and simply used a merge module to handle the installation of the appropriate redist files. However, I noticed that when using the latest version of the merge modules for 2015 (Microsoft_VC140_CRT_x64.msm) that my application still wouldn't work out of the box. I did some digging and it appears that some things have changed with the latest version of the merge modules. It appears that Microsoft is now recommending to install the vcredist_x64.exe package directly instead of using merge modules.
So, I'm attempting to create a custom action to do this. I'm following a similar tutorial here, although adapting it for the VC Redistributable executable. The first thing I need to do is setup where the .exe file is going to be placed once installed:
<Directory Id='APPLICATIONROOTDIRECTORY' Name='MyApp'>
<Directory Id="VCREDISTDIR" Name="VCRedist">
</Directory>
</Directory>
Then, I need to add my files into a component group which will be installed as part of a hidden feature (as I want this to be automatically installed).
<ComponentGroup Id="VCRedist" Directory="VCREDISTDIR">
<Component Id="vcredist_x64.exe" Guid="-INSERT-GUID-HERE-" Win64="yes">
<File Id="VCREDISEXE" Name="vcredist_x64.exe" KeyPath="yes" Source="$(var.VCRedistSourceDir)" Checksum="yes"></File>
</Component>
</ComponentGroup>
And...
<Feature Id="VCRedistributable" Title="Visual C++ Runtime" AllowAdvertise="no" Display="hidden" Level="1">
<ComponentGroupRef Id="VCRedist" />
</Feature>
At this point, the vcredist_x64.exe should be copied to the end user's machine. Now, I need to create a custom action to launch the executable after the installation.
<CustomAction Id="InstallVCRedistributable"
FileKey="VCREDISEXE"
Execute="deferred"
ExeCommand="/silent"
Impersonate="no"
Return="check"/>
<InstallExecuteSequence>
<Custom Action="InstallVCRedistributable" Before="InstallFinalize">
<![CDATA[NOT REMOVE]]>
</Custom>
</InstallExecuteSequence>
I also include a status message to my UI so that I can see when the executable is being executed.
<UI>
<ProgressText Action="InstallVCRedistributable">Installing Visual C++ Redistributable for Visual Studio 2015</ProgressText>
</UI>
Now, when I run my installer it should launch the vcredist_x64.exe... and it does... but then during the installation of that executable it gets hung up. I get a popup message that says there is a problem with this Windows Installer Package and that a program run as part of the setup did not complete. It then rolls-back my main application installation and never gets installed. Can anyone explain why this is happening and how to fix it? Thanks!
I found this question and tried it myself, being in the same situation. I found the installer error you're running into was/is Error 1618: "Another installation is already in progress." It seems that running the vc_redist installer inside your own installer simply won't work.
Your other options seem to be creating a bootstrapper as Patrick Allwood suggests above, or simply asking users to install the vc_redist package on their own before running your own installer. You can detect if the Universal C Runtime is already present by checking for ucrtbase.dll in C:\Windows\System32:
<Property Id="UCRTINSTALLED">
<DirectorySearch Id="UCRTSystemSearch" Path="[WindowsFolder]System32" Depth="0">
<FileSearch Id="UCRTFileSearch" Name="ucrtbase.dll" MinVersion="10.0.10240.16389" />
</DirectorySearch>
</Property>
If you only have a 32-bit installer, you can also use the [SystemFolder] property directly.
EDIT: As Kevin Smyth mentioned, the version of ucrtbase.dll is giving weird issues - reporting version 2.X to some tools, and version 10.Y to other tools. You can remove the MinVersion property if you just want to check for the existence of ucrtbase.dll.
I think the correct approach to take when having prerequisites that have their own installers is to create a WiX bootstrapper bundle, which runs through each installer in turn. This handles things like rollbacks on install failures, etc, which running custom actions from within an installer does not.
A barebones sample can be seen here, you add <MsiPackage> and <ExePackage> in the Chain element in the order you need them to install.
I was facing a similar problem (fully described in this closed question, which actually redirected me here). I was able to solve it, inspired by this entry about running the application after setup.
The key part is basically to add a final step to the UI that launches the vcredist installer:
<UI Id="UI_Main">
<!-- ...... -->
<Publish Dialog="ExitDialog"
Control="Finish"
Event="DoAction"
Value="InstallVCRedistributable">1</Publish>
</UI>
Regarding the custom action:
<CustomAction Id="InstallVCRedistributable"
FileKey="VCREDISEXE"
ExeCommand="/install /passive /norestart"
Impersonate="yes"
Return="asyncNoWait" />

How can I put a condition on a feature that disables it (instead of hiding it)?

How can I have a Feature depend on a system dependency (e.g. powershell), but still indicate to users that this feature is available in the installer.
Currently features are listed as follows (screenshot):
Feature List
My current idea is to put a condition on the feature:
<Property Id="POWERSHELL_3_INSTALLED">
<RegistrySearch Id="Powershell3Installed"
Root="HKLM"
Key="SOFTWARE\Microsoft\PowerShell\3"
Type="raw"
Name="Install" />
</Property>
<Feature Id="TestFeature"
Title="Test Feature"
Description="Test Feature Description. Note: This feature requires Powershell 3 or higher."
Level="1"
Absent="allow"
InstallDefault="local"
AllowAdvertise="no">
<Condition Level="0">
<![CDATA[(POWERSHELL_3_INSTALLED <> "#1") AND NOT REMOVE]]>
</Condition>
</Feature>
This does hide TestFeature for users without powershell installed, preventing them to install it, but this way users are not aware that this extra feature would be available if they would install powershell.
Any ideas how to achieve this?
The SelectionTree control in Windows Installer does not support showing disabled features. You would have to reimplement that -- for example, using checkboxes.

Remove registry keys under HKCU on a per machine installation

I build a perMachine installer using WiX 3.6 to install a software I had not developed. Unfortunately the software creates some registry keys under HKCU during execution.
On uninstall, the self created keys should also be removed. It seems not so easy to remove these keys. I am "fighting" with ICE57 and/or ICE38. Both complaining the mix between perUser and perMachine data.
Hopefully you can point me in the right direction on fixing this issue.
To overcome ICEs you should move Per-User registry to separate components and use some registry entry as keyPath for that component, i.e.:
<Component Id='PerUserRegistry' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPAth" KeyPath="yes" Root="HKCU" Key="Software\[Manufacturer]\[ProductName]\[ProductCode]\PerUserRegistry" Name="[PackageCode]" Value="[ProductVersion]" Type="string" />
<!--Other Per-user registry goes here-->
</Component>
I completely agree with Christopher: It is common practice to leave per-user data on uninstall, but if removal is necessary, then Active Setup is the only real option.
First I propose you to remove them on Install or Re-Install instead of uninstall, you just need add RemoveRegirty entry and Active Setup, i.e. with this WiX code:
<Component Id='ActiveSetup' Guid='*'>
<RegistryValue Id="ActiveSetup00" Root="HKLM" KeyPath="yes" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Name="StubPath" Value="msiexec /fup [ProductCode] /qb-!" Type="string" />
<RegistryValue Id="ActiveSetup01" Root="HKLM" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Value="[ProductName] [ProductVerion] Configuration" Type="string" />
</Component>
<Component Id='PerUserRegistryCleanup' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPath" Root="HKCU" KeyPath="yes" Key="SOFTWARE\SOFTWARE\Microsoft\Active Setup\Installed Components\[PackageCode]\" Name="StubPath" Value="msiexec /fup [ProductCode] /qb-!" Type="string" />
<RemoveRegistryKey Id='PerUserRegCleanup' Root='HKCU' Action='removeOnInstall' Key='Key\To\Be\Removed'/>
</Component>
Note: [PackageCode] use in ActiveSetup is very recommended, so with each new version (build) of MSI package you add separate entry (also see my final note). I used per-user active setup registry as key-path on purpose, so you don't run it for current user twice.
As for removing them after uninstall,
Now, hopefully you need to remove entire key, and not just some values. In either case, I would create custom action to add Registry entry for Active Setup during uninstall (or if there are many such keys/values, create and deploy .CMD file with those and launch it on uninstall, before RemoveFiles action, to add all of them to registry).
Note: that I would strongly recommend adding deleting this registry during install, or you might end up removing per-user values when software is yet installed.
So here's WiX code for all of this:
<CustomAction Id="CA_UninstallRegistryCleanUp" Directory="SystemFolder" ExeCommand="REG.exe ADD "HKLM\SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp" /v StubPath /d "reg add ^"HKCU\Key\To\Be\Removed^" /va /f" /f" Return="ignore" />
<InstallExecuteSequence>
<Custom Action='CA_UninstallRegistryCleanUp' After='RemoveRegistryValues'>REMOVE~="ALL"</Custom>
</InstallExecuteSequence>
<Component Id='RegCleanup_Remover' Guid='*'>
<RegistryValue Id="PerUserRegistry_KeyPAth" Root="HKLM" KeyPath="yes" Key="SOFTWARE\[Manufacturer]\[ProductName]\[ProductCode]\" Name="DummyKey" Value="[ProductVersion]" Type="string" />
<RemoveRegistryKey Id='RegCleanup_Remover' Root='HKLM' Action='removeOnInstall' Key='SOFTWARE\Microsoft\Active Setup\Installed Components\MySoftName_CleanUp'/>
</Component>
Final notes:
There just two small issues with all this Active Setup stuff: be careful on Windows Terminal Servers; and once active setup was run for one user for current .MSI, it will not run again if you decide to reinstall same package, unless you change its PackageConde or raise version under ActiveSetup registry key. These are topics for another day, let me know if need them clarified.
And don't forget to add all of above Components to some Feature.
The Windows Installer considers this user data and best practice is to not remove it. Either way, it's very difficult to try to remove it anyways since other user profiles are out of scope / context. It's theoretically possible to write a custom action to enumerate profiles and load registry hives but on some versions of Windows ( Vista ) that won't work due to restricted permissions granted to the windows installer service.
If you really, really must be able to remove custom action data on uninstall then take a look at:
Active Setup Explained
You are going to need to leave behind an program (exe for example ) by marking a component as permanent. Then you'll need a custom action to write a registry value during the uninstall (because Windows Installer doesn't support this).
The concept is during the install you lay down an EXE and during the uninstall you leave you. You then write to the ActiveSetup registry key telling it to run your EXE once for each subsequent user to logon to the machine. The EXE then deletes your registry values. Reboot (politely) if needed to unload the extensions from explorer.
But honestly, a better designed application wouldn't need all of this.

Registry not being read when using registrysearch in Wix

I have been searching the internet for an answer on this registry search issue.
I have a bigger wix file but i could not get multiple features working and its the conditioning of the features so I have created a basic test wix document to understand the features of wix but can not get the result i required.
The code is as follows:
<Property Id="BASICTEST" Secure="yes" >
<RegistrySearch Id="_Regsearch_Basic" Root="HKLM"
Key="SOFTWARE\TGSL\BasicInstaller" Name="BASIC1" Type="raw" >
</RegistrySearch>
</Property>
<Property Id="BASICTEST1" Secure="yes" >
<RegistrySearch Id="_Regsearch_Test" Root="HKLM"
Key="SOFTWARE\TGSL\BasicInstaller" Name="TEST1" Type="raw" >
</RegistrySearch>
</Property>
<Feature Id="BasicFeature" Title="BasicFeat" Level="0">
<Condition Level="1">NOT (BASICTEST="0")</Condition>
<ComponentRef Id="BasicTest"/>
</Feature>
<Feature Id="TestFeature" Title="TestFeat" Level="0" >
<Condition Level="1">NOT (BASICTEST1="0") </Condition>
<ComponentRef Id="BasicTest1"/>
</Feature>
I have set up four registry entries, all values are 1 (BASIC1=1 and TEST1=1) to test which registry it is using (either 2 in SOFTWARE\TGSL\BasicInstaller for 64bit or 2 in SOFTWARE\TGSL\BasicInstaller for 32bit)
I know it defaults to 32bit unless otherwise stated but still nothing. I was using process monitor to test to see if my .msi file was reading the registry...which it isnt.
I created a log file when installing the .msi and i get a error code when reading the registry:
AppSearch: Property: BARRIETEST, Signature: _Regsearch_BarrieTest1
Note: 1: 2262 2: Signature 3: -2147287038
Note: 1: 1402 2: HKEY_LOCAL_MACHINE32\SOFTWARE\TGSL\BasicInstaller 3: 2
The error code is not finding the file but it looks like it is looking in a directory that doesnt exist and when i change it to win64="yes" it takes away the 32 after the HKEY_LOCAL_MACHINE.
I have tried building this test script in wix 2.0 and it searches the registry fine and it changes the property to the value of the registry key "1" so i am in a quandary as to what im doing wrong??
Is there a difference between the registry search parameters between wix 2.0 and wix 3.5?
Can anyone suggest a possible fix or how i can get these features working?
Please help...thank in advance
For closure, as indicated in the question comments, this was a permissions issue where the user running the setup installer did not have enough privileges to access HKEY_LOCAL_MACHINE.