WiX Installer - Environment Variable Removed with Reinstall/Repair - installation

I’m creating a WiX installer for a Petrel plugin using WiX 3.11.1. The Product.wxs is essentially the following one with a couple modifications:
https://github.com/davidbcc/DeCompactPlugIn/blob/dev/FaciesDecompactorInstaller/Product.wxs
I added a page in the wizard where the user can specify a license server in an edit box. From this information, I create and/or update an environment variable:
<!-- Get the current environment variable if it exists -->
<SetProperty Id="LICENSE_SERVER_ENV_VAR" Value="[%LIC_HOST]" After="LaunchConditions" Sequence="first"></SetProperty>
<snip>
<!-- Validate that the license server name is not empty before proceeding. -->
<Control Type="PushButton" Id="Next" X="239" Y="243" Width="56" Height="17" Default="yes" Text="Next">
<Publish Event="SpawnDialog" Value="ServerNameErrorDlg"><![CDATA[LICENSE_SERVER_ENV_VAR = ""]]></Publish>
<Publish Event="NewDialog" Value="ngenDialog"><![CDATA[LICENSE_SERVER_ENV_VAR <> ""]]></Publish>
</Control>
<snip>
<!-- Install the plugin and set the environment variable -->
<Fragment>
<ComponentGroup Id="PluginComponents" Directory="INSTALLLOCATION">
<Component Id="PetrelPluginPip" Guid="120AF5B9-E751-43F4-AF4C-7DED33C8BEB4">
<Environment Id="LicenseServerEnVar" Action="set" Name="LIC_HOST" System="yes" Permanent="yes" Value="[LICENSE_SERVER_ENV_VAR]"/>
<File Id="PetrelPluginPippip" Source="../OceanPluginPip/bin/$(var.OceanPluginPip.Platform)/$(var.OceanPluginPip.Configuration)/PetrelPluginPip.pip" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
Everything seems to run fine on initial install and when operating through Add/Remove Programs. If I run repair through there, it runs silently and the environment variable remains.
However, after installation, if I right-click on the installer (the actual .msi file), select “Install”, and then select the “Repair” option in the Maintenance dialog, I go through the wizard again. The page correctly pulls the license server information just like on initial install but after completing the repair, the environment variable is removed from the system.
I have tried:
setting "Sequence” on SetProperty to “both”
putting the “Environment” tag into its own Component
creating a CustomAction for setting the license server that is then used in the InstallExecuteSequence
None of these have worked.
Does anyone know why repair through the MaintenanceDialog is resulting in the removal of the environment variable? Thanks.
EDIT:
After adding verbose logging, the repair output shows the following which seems relevant:
MSI (s) (60:78) [11:42:25:420]: PROPERTY CHANGE: Adding RestrictedUserControl property. Its value is '1'.
MSI (s) (60:78) [11:42:25:420]: PROPERTY CHANGE: Adding PETRELINSTALLLOCATION property. Its value is 'C:\Program Files\Schlumberger\Petrel 2022\'.
MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property INSTALLLOCATION
MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property LICENSE_SERVER_ENV_VAR
MSI (s) (60:78) [11:42:25:420]: Ignoring disallowed property TARGETDIR
Action start 11:42:25: LaunchConditions.
Action ended 11:42:25: LaunchConditions. Return value 1.
MSI (s) (60:78) [11:42:25:468]: Doing action: SetLICENSE_SERVER_ENV_VAR
MSI (s) (60:78) [11:42:25:468]: Note: 1: 2205 2: 3: ActionText
Action start 11:42:25: SetLICENSE_SERVER_ENV_VAR.
MSI (s) (60:78) [11:42:25:469]: Skipping action due to msidbCustomActionTypeFirstSequence option.
Action ended 11:42:25: SetLICENSE_SERVER_ENV_VAR. Return value 0.
Why is the property disallowed on repair? I'm not seeing that on initial installation. But I still don't see where the environment variable is getting removed.

After investigating what "Ignoring disallowed property" meant, I came across the following post indicating that likely the property is not propagating to the execute sequence:
https://stackoverflow.com/a/39227065/4460247
By adding a Property definition and marking it as "Secure" before populating it, the property is set and the environment variable no longer gets removed.
<Property Id="LICENSE_SERVER_ENV_VAR" Secure="yes"></Property>
<SetProperty Id="LICENSE_SERVER_ENV_VAR" Value="[%LIC_HOST]" After="LaunchConditions" Sequence="first"></SetProperty>

Related

RemoveRegistryKey not removing registry keys

I have a set of registry values that were set by a previous version of my application. It was set permanently (from c++ code) and will not be removed when the application is uninstalled. Now I am trying to edit the wix installation file to remove those registry keys on new installation of the application but it is not working. Here is my code -
<Component Id="RemoveOldRegKeys" Guid="9xxxxxx" KeyPath="yes">
<RemoveRegistryKey Id="RemoveAppInit64" Root="HKLM" Key="SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs" Action="removeOnInstall"/>
</Component>
I have a feature where this component is referred -
<Feature Id="SmartCardFeature" Level="1">
<ComponentRef Id="RemoveOldRegKeys" />
</Feature>
I checked the install logs and it seems to be executing fine. These are the lines I am getting -
MSI (s) (A8:44) [14:00:43:435]: Executing op: RegOpenKey(Root=-2147483646,Key=SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs,,BinaryType=1,,)
MSI (s) (A8:44) [14:00:43:435]: Executing op: RegRemoveKey()
MSI (s) (A8:44) [14:00:43:436]: Note: 1: 1402 2: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows\AppInit_DLLs 3: 2
I am just wondering if what I am doing is possible and if yes, what am I missing or doing wrong?
Thanks in advance for the help.
AppInit_DLLs is a value (under the SOFTWARE\Microsoft\Windows NT\CurrentVersion\Windows key), not a key itself. You want RemoveRegistryValue instead.

Check for Terminal Server in WiX

Recently I had to "pre-select" an feature inside an WiX product. If the target machine is an Terminal-Server, the Feature should be selected for install.
To check, if the machine realy is used as Terminal-Server or not isn't required, since the installing user can still deselect the feature later.
One way to check for Terminal-Server (and not just an machine with RDP enabled) is to use GetVersionEx-API to check the wSuiteMask.
How to check that in WiX?
First we had to link WixUtilExtension.dll (Project-References->Add Reference)
Then use INSTALLLEVEL (as per mrnx's advice) to switch between different Features. We default it to "2" (All below 2 will be selected in feature-selection-screen, all above 2 will be de-selected):
<!--Default Features: All with levl 1-->
<Property Id="INSTALLLEVEL" Value="2" />
Use feature-selection-UI-template (Maybe you have to reference WixUiExtension.dll)
<UI>
<UIRef Id="WixUI_FeatureTree" />
</UI>
Now reference the properties, which we want to know:
<!--Terminal-Server?-->
<PropertyRef Id="WIX_SUITE_TERMINAL" />
<!--On Terminal-Server this property will be null, if multiple RDP-sessions are allowed-->
<PropertyRef Id="WIX_SUITE_SINGLEUSERTS" />
And finally in our Feature-list we have to use the properties inside a condition. The Feature should be de-selected per default, so we set it to one Level higher than the default "2" --> "3".
<Feature Id="TerminalServerServiceFeature" Level="3"
Title="(Feature-Title, i.E.)Terminal-Server-Service"
AllowAdvertise='no'
InstallDefault='local'
Absent='allow'
Description="Some description for the user, when he clicks on the feature" Display="expand"
ConfigurableDirectory='APPLICATIONFOLDER'
>
<!--Reference to the component (or componentgroup) we want to install-->
<ComponentRef Id="TerminalServerServiceComponent" />
<!--This sets this feature to installlevel 1, if the condition evals to true-->
<Condition Level="1">(WIX_SUITE_TERMINAL="1") AND NOT (WIX_SUITE_SINGLEUSERTS)</Condition>
</Feature>
Testing:
To check, why the condition fails, you have to check the installer log (msiexec /i YourMsi.msi /l*v "log.log").
Something along the lines
MSI (c) (8C!98) [11:18:27:663]: PROPERTY CHANGE: Adding
WIX_SUITE_SINGLEUSERTS property. Its value is '1'.
for a machine with RDP but without multi-rdp-session-support and
MSI (c) (4C!E0) [11:26:15:422]: PROPERTY CHANGE: Adding
WIX_SUITE_TERMINAL property. Its value is '1'.
for a machine with RDP and multi-rdp-session-support.

Wix Cab error code 1

I am getting the following error in the log file:
Action start 12:11:52: CreateIisConfigs.
MSI (s) (0C:7C) [12:11:52:731]: Invoking remote custom action. DLL: C:\WINDOWS\Installer\MSIFD80.tmp, Entrypoint: CreateIisConfigs
MSI (s) (0C:E8) [12:11:52:731]: Generating random cookie.
MSI (s) (0C:E8) [12:11:52:733]: Created Custom Action Server with PID 10316 (0x284C).
MSI (s) (0C:F0) [12:11:52:751]: Running as a service.
MSI (s) (0C:F0) [12:11:52:753]: Hello, I'm your 32bit Impersonated custom action server.
SFXCA: Extracting custom action to temporary directory: C:\WINDOWS\Installer\MSIFD80.tmp-\
SFXCA: Failed to extract to temporary directory. Cabinet error code 1.
CustomAction CreateIisConfigs returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
Action ended 12:11:52: CreateIisConfigs. Return value 3.
Action ended 12:11:52: INSTALL. Return value 3.
I am using <MediaTemplate EmbedCab="yes" /> and WIX Toolset 3.10.
Thanks for your time.
You have a security/permission issue.
Check the line before this issue.
Also it could be related to exe file you are using in your CA.
Hope it helped.
Okay so i sort this issue out.In my specific case i have a post-build action that copies the msi file to the Resources folder of C# class library project.Somehow the msi got corrupted and thats why i had this Cabinet error code 1 .After i manually copy paste the msi the error is gone.

CMD window remain open after wix installation runs application

Using Wix installer (win 8), I have a custom action that runs the application after successful installation, using Wix:
<CustomAction Id='LaunchFile'
Directory='TARGETDIR'
Impersonate="no"
Execute="immediate"
ExeCommand='[SystemFolder]cmd.exe start CMD /c ""[TARGETDIR]ManagerAndControl.exe""'
Return="asyncNoWait" />
This works great, but for some reason, the CMD window remains open, and when the application is closed it is closed too.
I couldn't find anything similar in google, anyone encounterd a similar problem?
Thank you
EDIT:
I'm trying, as #Rolo suggested, the QtExecCmdLine:
<Property Id="QtExecCmdLine" Value='C:\Users\User\Desktop\tests.exe'/>
<CustomAction Id="QtExecExample" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="immediate" Return="check"/>
And also:
<Publish Event='DoAction' Value='QtExecExample'>(NOT Installed) AND (LAUNCHPRODUCT = 1)
</Publish>
But nothing happens, and the log says:
Action start 11:02:49: QtExecExample.
MSI (c) (E0:20) [11:02:49:911]: Invoking remote custom action. DLL: C:\Users\User\AppData\Local\Temp\MSIAD42.tmp, Entrypoint: CAQuietExec
MSI (c) (E0:EC) [11:02:49:913]: Cloaking enabled.
MSI (c) (E0:EC) [11:02:49:913]: Attempting to enable all disabled privileges before calling Install on Server
MSI (c) (E0:EC) [11:02:49:913]: Connected to service for CA interface.
MSI (c) (E0!00) [11:02:49:944]: PROPERTY CHANGE: Deleting QtExecCmdLine property. Its current value is 'C:\Users\User\Desktop\tests.exe'.
Action ended 11:02:49: QtExecExample. Return value 3.
DEBUG: Error 2896: Executing action QtExecExample failed.
The installer has encountered an unexpected error installing this package. This may indicate a problem with this package. The error code is 2896. The arguments are: QtExecExample, ,
Action ended 11:02:49: FinishedForm. Return value 3.
Action ended 11:02:49: INSTALL. Return value 1.
Filling lost here
Use the "Quiet Execution Custom Action" instead.
http://wixtoolset.org/documentation/manual/v3/customactions/qtexec.html
Update:
I'll have to update my answer. You should use the WixShellExec custom action. It works pretty similar to Quiet Execution CA, but it will allow you to launch the app without waiting for it to close.
However it can only be used as an immediate custom action.
There is a full example of the implementation you need here:
http://wixtoolset.org/documentation/manual/v3/howtos/ui_and_localization/run_program_after_install.html
http://wixtoolset.org/documentation/manual/v3/customactions/shellexec.html
Edit your execommand like this
> ExeCommand='[SystemFolder]cmd.exe start CMD /c ""[TARGETDIR]ManagerAndControl.exe"" & exit'
EDIT
> ExeCommand='"[TARGETDIR]ManagerAndControl.exe"'
I've just tried this for me and it's worked after I recreated your original problem. However, where you have [TARGETDIR] I use [INSTALLDIR] - I assumed that this was referencing your install directory. You need to be aware of your use of inverted commas.
Thanks for your help, finally I solved it:
<Property Id="WixShellExecTarget" Value='[TARGETDIR]ManagerAndControl.exe' />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA" DllEntry="WixShellExec" Impersonate="yes" />
<!-- UI code here -->
<Publish Event='DoAction' Value='LaunchApplication'>(NOT Installed) AND (LAUNCHPRODUCT = 1)</Publish>

Wix CAQuietExec - Path gets prefixed with 'C:\Windows\SysWOW64\'

I provided a path like this as the Property Value: [INSTALLFOLDER]Program Scripts\Script1.rss
where INSTALLFOLDER is C:\Program Files (x86)\ABCCompany\DEFProductInstaller\
But it somehow gets interpreted like this:
C:\Windows\SysWOW64\C:\Program Files (x86)\ABCCompany\DEFProductInstaller\Program Scripts\Script1.rss
This is the Property and the associated CustomAction
<Property Id="CreateDataSources"
Value=""rs.exe" -i "[INSTALLFOLDER]Program Scripts\Script1.rss""/>
<CustomAction Id="CreateDataSources" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="no"/>
This is the log:
Property(S): SystemFolder = C:\Windows\SysWOW64\
...
MSI (s) (8C:44) [14:41:41:202]: Executing op: CustomActionSchedule(Action=CreateDataSources,ActionType=3073,Source=BinaryData,Target=CAQuietExec,CustomActionData="rs.exe" -i "[INSTALLFOLDER]Program Scripts\Script1.rss" -s http://localhost/ReportServer -v DataSourcePath="" -v DBServer="." -v InitialCatalog="MyDB" -v UserId="" -v Password="" -v IntegratedSecurity="True")
MSI (s) (8C:78) [14:41:41:211]: Invoking remote custom action. DLL: C:\Windows\Installer\MSIFB.tmp, Entrypoint: CAQuietExec
MSI (s) (8C:90) [14:41:41:211]: Generating random cookie.
MSI (s) (8C:90) [14:41:41:213]: Created Custom Action Server with PID 16716 (0x414C).
MSI (s) (8C:C4) [14:41:41:237]: Running as a service.
MSI (s) (8C:C4) [14:41:41:238]: Hello, I'm your 32bit Impersonated custom action server.
CAQuietExec: Could not find a part of the path 'C:\Windows\SysWOW64\C:\Program Files (x86)\ABCCompany\DEFProductInstaller\Program Scripts\Script1.rss'.
CAQuietExec: Error 0x80070001: Command line returned an error.
CAQuietExec: Error 0x80070001: CAQuietExec Failed
Any idea as to what I'm doing wrong?
UPDATE Changing the <Property> value to an absolute path fixes this issue.
<Property Id="CreateDataSources"
Value='"rs.exe" -i "C:\Program Files (x86)\ABCCompany\DEFProductInstaller\Program Scripts\Script1.rss"/>
But I need it to work with INSTALLFOLDER
The log isn't failing the way I expect it to fail (perhaps there has been a recent WiX change) but in my experience the call to rs.exe has to not only be wrapped in quotes but it has to be an absolute path. "[SystemFolder]rs.exe"
BTW, it seems you are using RS.exe to deploy reporting services changes. I don't believe that file is legally redistributable. I was working for a company about 6 years ago where I wrote a table driven C#/DTF custom action that consumed the SSRS web service to publish directories, reports and datasources. I never implemented rollback though. Also this is one type where Impersonate=No may end poorly. This is due to the fact that in some situations the logged on user might have writes to the SSRS web service and the SYSTEM account may not.
You need to provide a full path to the .exe you want to run. CreateProcess does not use the system path: http://msdn.microsoft.com/en-us/library/windows/desktop/ms682425%28v=vs.85%29.aspx

Resources