Unable to update "PATH" environment variable using WIX - installation

I have used the following wix fragment to update "PATH" environment variable.
<DirectoryRef Id="MyDir">
<Component Id ="setEnviroment"
Guid=" xxxxx">
<CreateFolder />
<Environment Id="SET_ENV"
Action="set"
Name="PATH"
Part="last"
Permanent="no"
System="yes"
Value="[INSTALLLOCATION]" />
</Component>
</DirectoryRef>
<Feature Id="Feature3" Title="3Feature"
Level="1"
Absent="disallow"
AllowAdvertise="no">
<ComponentRef Id="setEnviroment"/>
</Feature>
<InstallExecuteSequence>
<WriteEnvironmentStrings/>
<InstallExecuteSequence/>
This was working initially but now it doesn't update the environment variable.
The Verbose log shows the execution of this action and return value 1.
Checked after restarting machine.
In the log for action FeaturePublish For Feature3 there is garbage value but Installation is successful.
Request your help in this......
Thanks a lot....

I think you are using INSTALLLOCATION where you mean to use INSTALLDIR. Here is a working example which updates the PATH environment var with the installation directory of the new app.
<Environment
Id="PATH"
Name="PATH"
Value="[INSTALLDIR]"
Permanent="yes"
Part="last"
Action="set"
System="yes" />
If do intend to use INSTALLLOCATION, and have it defined elsewhere, then please post the rest of your code and we will go further down the rabbit hole.

I needed to use INSTALLFOLDER instead, to get it working.
<Environment
Id="PATH"
Name="PATH"
Value="[INSTALLFOLDER]"
Permanent="yes"
Part="last"
Action="set"
System="yes" />

Related

Wix - Only Install Package via Custom Action when a specific registry doesnt exist

I have tried for 10 hours million things but I don't get it to work. Here is my code (extract):
<Fragment>
<util:RegistrySearch Id="VC_REDIST_Version"
Root="HKCR"
Variable="VCREDIST143431931"
Key="Installer\Dependencies\VC,redist.x86,x86,14.34,bundle"
Format="raw"
Value="Version"
Result="value" />
<ComponentGroup Id="ThirdPartyComponents" Directory="ExtSources">
<Component Id="Component_VC_redist_x86" Guid="2B80F89A-990A-438E-A475-9E72d8A0198A" >
<File Id="ExtSources_VC_redist.x86.exe" Name="VC_redist.x86.exe" Source="$(var.xxxxx_TargetDir)ExtSources\VC_redist.x86.exe" />
</Component>
</ComponentGroup>
<CustomAction Id="Install_VC_redist_x86"
Execute="immediate"
Impersonate="no"
Return="asyncNoWait"
FileKey="ExtSources_VC_redist.x86.exe"
ExeCommand="" />
<InstallExecuteSequence>
<Custom Action="Install_VC_redist_x86" After="InstallFinalize">NOT VCREDIST143431931</Custom>
</InstallExecuteSequence>
</Fragment>
But the problem is that the Custom action is executed always, independent from the state.
Any Idea what might be wrong?
UPDATE:
This is now how I did it and it works including skipping calling the installer when there is already a newer or same version of vc distrib installed:
<Fragment>
<Property Id="VCREDISTINSTALLED">
<RegistrySearch Id="VCRedistInstalledSearch"
Root="HKCR"
Key="Installer\Dependencies\VC,redist.x86,x86,14.34,bundle"
Name="Version"
Type="raw"
Win64="no"/>
</Property>
<ComponentGroup Id="ThirdPartyComponents" Directory="ExtSources">
<Component Id="Component_VC_redist_x86" Guid="2B80F89A-990A-438E-A475-9E72d8A0198A" >
<File Id="ExtSources_VC_redist.x86.exe" Name="VC_redist.x86.exe" Source="$(var.xxxxx_TargetDir)ExtSources\VC_redist.x86.exe" />
</Component>
</ComponentGroup>
<CustomAction Id="Install_VC_redist_x86"
Execute="immediate"
Return="asyncNoWait"
FileKey="ExtSources_VC_redist.x86.exe"
ExeCommand="/quiet /norestart" />
<InstallExecuteSequence>
<Custom Action="Install_VC_redist_x86" After="InstallFinalize"><![CDATA[VCREDISTINSTALLED < "14.34.31931.0" AND NOT REMOVE]]></Custom>
</InstallExecuteSequence>
</Fragment>
You'll want to use RegistrySearch instead of util:RegistrySearch. The util:RegistrySearch is only recognized in Bundles. In WiX v4, there is a error message but in WiX v3 it is silently ignored.

Adding environment variable in WiX bootstrapper

I have Wix bootstrapper that installs few MSI packages.
Is there any way I can add to path install folder one of these packages INSIDE this bootstrapper?
Something like this:
<Environment Id="PATH" Name="PATH" Value="[INSTALLDIR]" Permanent="yes" Part="last" Action="set" System="no" />
Or I have to add it inside one of these packages as component?
Bootstrapper projects are not supposed to change the state of the system (outside of the individual packages).
You would need to add it to one of the MSI projects.
This code block works for me. Note CreateFolder is necessary to ensure the block is executed.
<Component Id="pathComponent" Guid="*" KeyPath="yes">
<CreateFolder />
<Environment Id="PATH" Name="PATH" Value="[INSTALLDIR]" Permanent="no" Part="last" Action="set" System="yes" />
</Component>

How do you add multiple entries to the `PATH` Envirnoment Variable using WiX?

I'm creating a MSI installer and need to add more than one entry to the PATH environment variable. Per the MSDN documentation:
Each row can contain only one value. For example, the entry Value;Value;[~] is more than one value and should not be used because it causes unpredictable results. The entry Value;[~] is just one value.
My installer source code looks like this currently (note, this is a per-machine installation), which is a violation of the above documentation:
<!-- NOTE: These two features are mutually exclusive -->
<Feature Id="Feature1" Level="1000" Absent="allow" AllowAdvertise="no" InstallDefault="local" TypicalDefault="install">
<Component Directory="INSTALLFOLDER">
<RegistryValue Action="write" Type="int" Root="HKLM" Key="SOFTWARE\MyProduct" Name="MyPathEntry1" Value="1" KeyPath="yes" />
<Environment Id="AddPathEntry1" Name="PATH" Value="[INSTALLFOLDER]SubDir1" Action="set" Permanent="yes" Part="last" System="yes" />
</Component>
</Feature>
<Feature Id="Feature2" Level="1000" Absent="allow" AllowAdvertise="no" InstallDefault="local" TypicalDefault="install">
<Component Directory="INSTALLFOLDER">
<RegistryValue Action="write" Type="int" Root="HKLM" Key="SOFTWARE\MyProduct" Name="MyPathEntry2" Value="1" KeyPath="yes" />
<Environment Id="AddPathEntry2" Name="PATH" Value="[INSTALLFOLDER]SubDir1;[INSTALLFOLDER]SubDir2;[INSTALLFOLDER]SubDir3" Action="set" Permanent="yes" Part="last" System="yes" />
</Component>
</Feature>
Now even though the above is "technically" a violation according to the MSDN documentation, it seems to work. I've tested fresh installations, modifying an installation, and upgrading. All seem to work with no hitch. But one thing I've learned with MSI is whenever possible, it's best to follow the rules to avoid messing up people's machines.
The natural solution of adding independent (i.e. not mutually exclusive) features containing only individual path components won't work because with MSI, you cannot guarantee the order in which features and/or components are installed. However, in this case, the order in which path components are added to the PATH environment variable is important due to how the PATH variable is used when finding unqualified executables.
The other question that may come to mind is, why am I using features? I want to give installers of the product the option to change their installation choice at a later date in time via the standard Add/Remove Programs or Program and Features Control Panel applet.
So, how can I add more than one path entry to the PATH environment variable in a deterministic order while following the recommended guidance from the MSDN? Or is the guidance from MSDN outdated and what I'm currently doing is perfectly fine?
I figured a way to do this which does not violate the guidance at MSDN for my particular situation.
The exact situation is I have a main program executable that installers may or may not want to be able to run from a Windows Command Shell. Additionally, there are other utilities that also installers may or may not wish to run from a Windows Command Shell.
The way this was originally modeled was as a set of 3 mutually exclusive features using radio buttons to decide how to update the system PATH environment variable. The 3 features boiled down to:
Don't modify the system's PATH environment variable (i.e. the program and optional tools can't be run from a Windows Command Shell by simply typing the name of the executable at any directory location).
Update the system's PATH environment variable so that only the main executable can be run from a Windows Command Shell at any given path.
Update the system's PATH environment variable to also add additional utility tool paths.
What I came to realize is that there are really only 2 features here, and they're not even mutually exclusive, but one is dependent on the other. The first radio button listed above is not really a feature--it's a no-op; it doesn't install anything! The second radio button represents the "main" feature in that the primary executable's directory is added to the system's PATH. The 3rd radio button depends upon the second: if the main executable is added to the PATH, then you can additionally add other utilities to the PATH as well.
This results in a much simpler UI. Instead of radio buttons, use checkboxes, and the second checkbox is disabled unless the first checkbox is checked. This also results in a much simpler implementaion for ensuring that the combination of features selected (say, for a command-line installation) is valid.
In a nutshell, here's what the WiX XML will boil down to in my particular case. I'm sure that this can be generalized (or modified) to suit other similar scenarios.
<Feature Id="AddExeToPath" Level="1" Absent="allow" AllowAdvertise="no" InstallDefault="local" TypicalDefault="install">
<Component Id="ExePath" Guid="{YOURGUID-HERE-0000-0000-00000000}" Directory="INSTALLFOLDER">
<CreateFolder />
<Environment Id="ExePath" Name="MY_PATHS" Value="[INSTALLFOLDER]SubDir1" Action="set" Part="first" System="yes" />
</Component>
<Component Directory="INSTALLFOLDER">
<RegistryValue Action="write" Type="integer" Root="HKLM" Key="SOFTWARE\MyProduct" Name="AddExeToPath" Value="1" KeyPath="yes" />
<Environment Id="AddToPath" Name="PATH" Value="%MY_PATHS%" Action="set" Part="last" System="yes" />
</Component>
<Component Id="RemoveExeFromPathOnUninstall" Guid="{YOURGUID-HERE-0000-0000-00000000}" Directory="INSTALLFOLDER">
<Condition>REMOVE><AddExeToPath OR REMOVE="ALL"</Condition>
<Environment Id="RemoveFromPath" Name="PATH" Value="%MY_PATHS%" Action="remove" />
</Component>
</Feature>
<Feature Id="AddToolsToPath" Level="1000" Absent="allow" AllowAdvertise="no" InstallDefaut="local" TypicalDefault="install">
<Component Id="SubDir2" Guid="{YOURGUID-HERE-0000-0000-00000000}" Directory="INSTALLFOLDER">
<CreateFolder />
<Environment Id="SubDir2" Name="MY_TOOLS" Value="[INSTALLFOLDER]SubDir2" Action="set" Part="first" System="yes" />
</Component>
<Component Id="SubDir3" Guid="{YOURGUID-HERE-0000-0000-00000000}" Directory="INSTALLFOLDER">
<CreateFolder />
<Environment Id="SubDir3" Name="MY_TOOLS" Value="[INSTALLFOLDER]SubDir3" Action="set" Part="last" System="yes" />
</Component>
<Component Directory="INSTALLFOLDER">
<RegistryValue Action="write" Type="integer" Root="HKLM" Key="SOFTWARE\MyProduct" Name="AddToolsToPath" Value="1" KeyPath="yes" />
<Environment Id="AddToolsToPath" Name="MY_PATHS" Value="%MY_TOOLS%" Action="set" Part="last" System="yes" />
</Component>
</Feature>
<CustomAction Id="InvalidPathFeatureSelection" Error="25000" Execute="firstSequence" />
<InstallExecuteSequence>
<Custom Action="InvalidPathFeatureSelection" Before="InstallValidate">
<![CDATA[NOT (REMOVE="ALL" OR (&AddToolsToPath >= 3 IMP &AddExeToPath >= 3))]]>
</Custom>
</InstallExecuteSequence>
This set of features and components results in the following:
If the feature AddExeToPath is selected for installation, the following components of the feature result in:
An environment variable named MY_PATHS is created and contains the path to the main executable.
The environment variable PATH is updated, placing %MY_PATHS% at the end its current value.
If the feature AddToolsToPath is selected, 3 components are installed:
The environment variable MY_TOOLS is created/set, and [INSTALLFOLDER]SubDir2 is put at the front of the variable's existing value (if any).
The environment variable MY_TOOLS is created/set and [INSTALLFOLDER]SubDir3 is put at the end of the variable's existing value (if any).
Note
These two components defined the way that they are ensure that the paths added to MY_TOOLS are added in the appropriate order.
The environment variable MY_PATHS is updated, placing %MY_TOOLS% at the end of the exisiting variable; again, this preserves the correct ordering of paths.
And so what you end up with is:
MY_TOOLS = [INSTALLFOLDER]SubDir2;[INSTALLFOLDER]SubDir3
MY_PATHS = [INSTALLFOLDER]SubDir1;%MY_TOOLS%
PATH = <existing_PATH_value>;%MY_PATHS%

Unable to start Service with WiX Installer

I'm trying to do a WiX installer with a service install for my C# project. It's the first time I try and I don't understand why it doesn't work.
I have set a ServiceInstall but when I run the setup, I'm blocked in this page :
After a few seconds I got the error :
I created the WiX install from a Visual Studio Installer with the same parameters. There is the code :
<Product ... />
<Feature Id="ProductFeature" Title="$(var.product)" Level="1">
<ComponentRef Id ="MyService"/>
</Feature>
<UIRef Id="WixUI_InstallDir"/>
<!-- Set install directory -->
<Property Id="WIXUI_INSTALLDIR" Value="INSTALLFOLDER"/>
</Product>
<Fragment>
<Directory Id="ProgramFilesFolder">
<Directory Id="INSTALLFOLDER" Name="$(var.product)">
<Component Id="MyService" Guid="{GUID-HERE}" KeyPath="yes">
<!-- service will need to be installed under Local Service -->
<ServiceInstall
Id="MyService"
Type="ownProcess"
Vital="yes"
Name="MyService"
DisplayName="Service"
Description=""
Start="auto"
Account="NT AUTHORITY\LocalService"
ErrorControl="normal"/>
<ServiceControl Id="StartDDService" Name="MyService" Start="install" Wait="no" />
<ServiceControl Id="StopDDService" Name="MyService" Stop="both" Wait="yes" Remove="uninstall" />
</Component>
</Directory>
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="ProductComponents">
<Component Id="ProductComponent" Guid="{}" Directory="INSTALLFOLDER">
<File Id="MyService.exe" Source="$(var.MyService.TargetDir)\MyService.exe"/>
</Component>
</ComponentGroup>
</Fragment>
The "failure to start" error could be a privilege issue, but the message is just a default message whether it it's privilege or not.
These cases are usually the service itself or a dependency:
A missing dependent Dll (or dependency of a dependency etc) has not been installed. That includes the .NET framework.
The service depends on an assembly being installed to the GAC, and these assemblies are not actually committed when services are started, so that's a special case of a missing dependency.
"Failure to start" is basically that the start code in the service didn't complete. A crash in your OnStart code could cause this. IMO Services should always have tracing available to trace the path and significant values to provide diagnostics.

Unresolved reference to symbol 'WixComponentGroup:MyWebWebComponents' in section

I was following the below code which is product.wxs files.But I am facing an error as below:
Error 5 Unresolved reference to symbol 'WixComponentGroup:MyWebWebComponents' in section 'Product:{}'
<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
xmlns:util="http://schemas.microsoft.com/wix/UtilExtension"
xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension">
<Product Id="702881b5-9a64-4ab8-ab47-f3babcd950a2"
Name="WixApplication" Language="1033"
Version="1.0.0.0"
Manufacturer="HexWireless"
UpgradeCode="42b7872b-78c8-4a0b-abcd-28a30c9804ab">
<Package InstallerVersion="200" Compressed="yes" Platform="x64" InstallScope="perMachine"/>
<!--<Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />-->
<!--Find the Path to the sqlcmd.exe by performing a registry search. This is hardcoded for SQL 2012.
Change 110 to 100 for 2008. Might need to change the script too.-->
<Property Id="SQLBINDIR">
<RegistrySearch Id="SqlBinDir"
Root="HKLM" Key="SOFTWARE\Microsoft\Microsoft SQL Server\110\Tools\ClientSetup"
Name="Path"
Type="raw"
Win64="yes"/>
</Property>
<Condition Message="Microsoft SQL Server 2012 needs to be installed before this installer can run">
<![CDATA[SQLBINDIR]]>
</Condition>
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="INSTALLLOCATION" Name="Database">
<Component Id="Database" Guid="a8dc2Fcd-087d-e393-b059-c67877e51b8a">
<File Id="DatabaseScript" Source="SQLScripts\HexWireless.sql"/>
<RemoveFile Id ="RemoveInstall.log" Name="Install.log" On="uninstall" />
</Component>
</Directory>
<Directory Id="INSTALLDIR" Name="PFiles">
<Directory Id="WixService" Name="Service">
<Component Id="WixWindowsServiceComponent" DiskId="1" Guid="6f51c0f3-776c-4aec-a200-1f199352c6c3" Win64="yes">
<File Id="WixService.exe" Name="WixService.exe" Source="$(var.WixService.TargetDir)\WixService.exe"/>
<ServiceInstall Id="InstallWixService" DisplayName="WixService" Name="WixService.exe" Description="WixService" Account="NT Authority\Network Service" ErrorControl="normal" Start="demand" Type="ownProcess" Vital="yes" />
<ServiceControl Id="ControlWixService" Name="WixService.exe" Stop="uninstall" Remove="uninstall" />
</Component>
</Directory>
</Directory>
<Directory Id="INSTALLFOLDER" Name="Publish">
</Directory>
</Directory>
<Feature Id="ProductFeature" Title="WebApplication" Level="1">
<Feature Id="Database" Title="Database" Description="DatabaseScript" Level="1" Display="expand"
AllowAdvertise="no" ConfigurableDirectory="INSTALLLOCATION" Absent="allow">
<Feature Id="WixWindowsServiceComponent" Title="Service" Description="WixService" Level="1" Display="expand"
AllowAdvertise="no" ConfigurableDirectory="INSTALLDIR" Absent="allow">
<ComponentGroupRef Id="WixWebsiteIssConfiguration" />
<ComponentRef Id="Database"/>
<ComponentRef Id="WixWindowsServiceComponent"/>
<ComponentGroupRef Id="MyWebWebComponents"/>
</Feature>
</Feature>
</Feature>
<Property Id="INSTALLDIR" Value="D:" />
<Media Id="1" Cabinet="WixWindowsServiceComponent.cab" EmbedCab="yes" />
<InstallExecuteSequence>
<!--If the database feature is selected these actions will run to install the DB-->
<Custom Action="Database.cmd" After="InstallFiles" >
<![CDATA[NOT Installed]]>
</Custom>
<!--Ensure this runs after the custom action to set up the properties for its cmd line-->
<Custom Action="Database" After="Database.cmd">
<![CDATA[NOT Installed]]>
</Custom>
</InstallExecuteSequence>
<UI>
<UIRef Id="GUI"/>
<UIRef Id="WixUI_ErrorProgressText" />
</UI>
<!--This is the sequence script. Best way to understand this is by running sqlcmd -?
Use "property" Custom action to get variable substitution working-->
<CustomAction Id="Database.cmd" Property="Database"
Value=""[SQLBINDIR]sqlcmd.exe" -E -S "[SQLSERVER]" -i "[#DatabaseScript]" -o "[INSTALLLOCATION]HexWireless.log""/>
<!-- Note that the cmd line and args will come from a property with the same name as the custom action, this has been set by the custom action above -->
<CustomAction Id="Database" BinaryKey="WixCA" DllEntry="CAQuietExec" Return="check" Execute="deferred" Impersonate="yes" />
</Product>
</Wix>
Thanks In Advance.
I am not sure if your issue is sorted or not, I just faced the same issue even though i have created a few of these msi files with Wix.
In my case, it wasn't finding the "HeatedComponents" that I am generating automatically within the project. I had to load this file into the project, (these files or folders may be inside your project folder but in most cases VS does not load them automatically).
You have to Right Click on the project -> Add -> Existing Item; and select the file/item that is required.

Resources