Why doesn't this silent launch work in WIX? - wix

I have the following command running at the end of my package install for an application.
<Property Id="WixShellExecTarget" Value="[INSTALLDIR]RCR.VDS.exe" />
<CustomAction Id="LaunchApplication" BinaryKey="WixCA"
DllEntry="WixShellExec" Impersonate="no" />
I can't use [#myApplication] because I run heat on my output folder on my build server so I don't know the auto generated id of my application. Any ideas on how to silently run my application after the install?
The log file shows this for the command line section
******* CommandLine: **********
MSI (c) (30:74) [09:47:14:156]: Note: 1: 2203 2: VDSInstall.msi 3: -2147287038
MSI (c) (30:74) [09:47:14:156]: MainEngineThread is returning 2

Please see: How To: Run the Installed Application After Setup
If you want the custom action called during a silent install add:
<InstallExecuteSequence>
<Custom Action="LaunchApplication" After="InstallFinalize">SOMECONDITION</Custom>
</InstallExecuteSequence>
Note SOMECONDITION should be an expression that checks the EXE is installed and the user wants the program to be launched.

The are a copy things you can consider:
The identifier from heat.exe will be stable. So you can use the ugly identifer in your [#UglyFileId1234abcef45612345asdf] custom action.
a. You could also apply a XSLT to transform the heat output for the executable file's Id to something nicer than the ugly identifier. Depends how readable you want the launch custom action to be.
If you want the executable launched silently then you'll probably want the Quite Execution custom action instead of the Shell execute custom action that "LaunchApplication" uses.

Related

WiX: Custom Actions don't run when using msiexec /i Setup.msi /qn (quiet mode installation without UI)

Our problem is that custom actions don't run when using msiexec /i Setup.msi /qn (quiet mode installation without UI). They only run with normal installation with UI.
In our Product.wxs for example, we have defined the following:
<Binary Id="SetupCustomAction" SourceFile="$(var.SetupCustomActions.TargetDir)$(var.SetupCustomActions.TargetName).CA.dll" />
<CustomAction Id="UPDATE_CONFIG" BinaryKey="SetupCustomAction" DllEntry="UpdateConfiguration" Execute="commit" Return="check" Impersonate="no" />
<InstallExecuteSequence>
...
<Custom Action="UPDATE_CONFIG" After="InstallFiles"><![CDATA[NOT Installed AND USEIMPERSONATE="0"]]></Custom>
...
</InstallExecuteSequence>
Do we have to use "Quiet Execution Custom Action", trying this out didn't help though!
Please help!
The obvious explanation is that USEIMPERSONATE has the value 1 so the custom action will not run, but I assume perhaps you are setting it to 0 on the command line.
Apart from that it would be useful to know if the install actually succeeds, because if it normally requires elevation with a UAC prompt then this UAC dialog will not be shown, so the custom action will not run elevated and it will fail. The install might succeed because Commit custom actions run after the install, so "check" is not relevant because the install cannot roll back. If you configure that CA as an install custom action it might fail and roll back the install. So after InstallFiles is also not relevant because it's a Commit CA.
The log should show something.
Okay, I have found the cause of the error and a fix for it: The ALLUSERS OR PREVIOUSINSTALLSCOPE (read from the registry) Properties must be set to "1". That way, the DISABLE_IMPERSONATE Custom Action gets run and sets the USEIMPERSONATE Property to "0". Then UPDATE_CONFIG and other Custom Actions get run.
To sum up, the solution is:
Change DISABLE_IMPERSONATE Property to this: <Custom Action="DISABLE_IMPERSONATE" After="AppSearch"><![CDATA[ALLUSERS=1 OR PREVIOUSINSTALLSCOPE="1"]]></Custom>
Call msiexec like this: msiexec /i Bechtle.A365.Office.Client.msi /qn ALLUSERS=1
Thanks to #Ritmo2k, #Brian Sutherland and #PhilDW for pointing me to the right direction.

Executing wix msi custom actions as system

I am using WIX to build a an MSI that will be executed as a regular user but with system privileges (AlwaysInstallElevated=1). I have defined two Custom Actions that execute net.exe.
The net.exe commands are not getting executed as a regular user. I have also tested executing this msi as an Administrator and the net.exe commands are getting executed.
I have logged the msi output and I see error codes that lead me to believe that the net.exe commands are not being executed elevated. I'm reaching out to the community to see if
What I'm trying to do is possible
Do I need to instead use an exe as a custom action in order for the exe to install elevated.
Thanks in advance for the feedback.
<CustomAction Directory="TARGETDIR" ExeCommand="[SystemFolder]net.exe user TestUser /add" Return="ignore" Execute="deferred" HideTarget="no" Impersonate="no" Id="Command1">Command1</CustomAction>
<CustomAction Directory="TARGETDIR" ExeCommand="[SystemFolder]net.exe localgroup Administrators TestUser /add" Return="ignore" Execute="deferred" HideTarget="no" Impersonate="no" Id="Command2">Command2</CustomAction>
<InstallExecuteSequence>
<Custom Action="Command1" After="PublishProduct">NOT Installed</Custom>
<Custom Action="Command2" After="Command1">NOT Installed</Custom>
</InstallExecuteSequence>
Machine Policy and User policy allows for msis to be executed as system.
MSI (c) (DC:F8) [09:17:39:438]: Machine policy value 'AlwaysInstallElevated' is 1
MSI (c) (DC:F8) [09:17:39:438]: User policy value 'AlwaysInstallElevated' is 1
MSI (c) (DC:F8) [09:17:39:438]: Running product '{34ED8E61-40EA-47CE-95E7-8EE3CDBCB1E8}' with elevated privileges: All apps run elevated.
Errors
MSI (s) (8C:8C) [20:39:18:989]: Executing op: ActionStart(Name=Command1,,)
MSI (s) (8C:8C) [20:39:18:989]: Executing op: CustomActionSchedule(Action=Command1,ActionType=3170,Source=C:\,Target=C:\WINDOWS\SysWOW64\net.exe user TestUser /add,)
CustomAction Command1 returned actual error code 2 but will be translated to success due to continue marking
MSI (s) (8C:8C) [20:39:19:535]: Executing op: ActionStart(Name=Command2,,)
MSI (s) (8C:8C) [20:39:19:535]: Executing op: CustomActionSchedule(Action=Command2,ActionType=3170,Source=C:\,Target=C:\WINDOWS\SysWOW64\net.exe localgroup Administrators TestUser /add,)
CustomAction Command2 returned actual error code 1 but will be translated to success due to continue marking
Even in an install started by an administrator the impersonated custom actions run without elevation. So the answer is your number 2. start the install from an elevated process with a CreateProcess-type of initiation. Having said that, it's not clear to me why you can't run the CA deferred with no impersonation because there seems to be nothing that requires the user to be an actual user as opposed to the system account. So the failure might not be elevation, and that's the issue with passing the task off to a program that isn't going to give you good error messages. So....
I've seen boilerplate code to do this kind of thing, and I believe WiX has it anyway, the Util User element, that may be the way to go.
Like Phil says, don't use net.exe to create users. Use WiX's built in features to do so (I should have found a better sample but don't have time right now):
http://wixtoolset.org/documentation/manual/v3/xsd/util/user.html
https://www.firegiant.com/wix/tutorial/com-expression-syntax-miscellanea/new-user-on-the-block/
My first instinct would be that the AlwaysInstallElevated policy would be misconfigured, but judging from the log file it is set correctly. I am rusty, but the impersonation looks like it is correctly set to "no" Phil? And the scheduling is deferred and seemingly placed right before InstallFinalize - seems OK off the top of my head.
Could it be that net.exe cannot be run properly as LocalSystem? Why then would it work when the installation is kicked off as Administrator? One would think LocalSystem had all required privileges. Isn't the current user's access token attached to the msiexec.exe process somehow? (for logging purposes or something). Or could it be a privilege that the Administrator account has that LocalSystem does not? How would that privilege apply if there is no impersonation? Did you try to manually launch net.exe as a regular user? What errors do you get when attempting to create a user when running as a regular user?
In either case I wouldn't waste my time running EXE custom actions if there is an alternative. I don't remember the last time I did. I normally use VBScript, C++ and earlier I used Installscript - with all its archaic syntax. Just switch to the built-in WiX constructs and you should be fine.

Remove popups that are caused by custom actions - Wix

Newbie to wix, I am learning it. I had initially set up some custom actions for installing/ uninstalling/ rollback actions. These custom actions cause unintended popups during installation. I am trying to remove the same using SetProperty, DllEntry and BinaryKey. This is my original code:
<CustomAction Id="InstallStorageService"
Directory="ProductAppDataFolder"
ExeCommand='[ProductAppDataFolder]bin\install_service.bat "[InstallationFolder]" "[ProductAppDataFolder]" "$(var.StorageServiceName)"'
Execute="deferred"
Impersonate="no"
Return="check"/>
This is what I have changed it to:
<SetProperty Id="InstallStorageService"
Value="cmd.exe /c [PRODUCTAPPDATAFOLDER]bin\install_service.bat "[InstallationFolder]" "[ProductAppDataFolder]" "$(var.StorageServiceName)""
After="CostFinalize"/>
<CustomAction Id="InstallStorageService"
BinaryKey="WixCA"
Execute="deferred"
Return="check"
DllEntry="CAQuietExec"
Impersonate="yes"/>
I have done similarly for removing and for rollback actions. I do not get any errors or issues while I run the .bat file to create the msi file, but once the msi is created, I am having trouble installing it. I can share the log file if required, but there are fatal errors with not much of verbose about it.
Any help would be greatly appreciated.
You can use the Quiet Execution Custom Action pattern to invoke out of process exe's and scripts. The pattern will capture stderr and stdout to the Windows Installer log.
However it would be better to not use a .BAT as self registration (in all forms) is not a windows installer best practice. See Zataoca: Custom actions are (generally) an admission of failure.

WiX/MSI: Redirect stdout to file, type 50 custom action

I have a WiX installer all rigged up to run SqlPackage.exe to deploy some installed .dacpac-packaged SQL applications to a database. Actually deploying the database files as follows will succeed:
<Property Id="CONNSTRING" Value="Data Source=localhost;Integrated Security=True;Initial Catalog=MPQS-DACPAC" />
<Property Id="SQLPACKAGEPATH" Value="C:\Program Files (x86)\Microsoft SQL Server\110\DAC\bin\SqlPackage.exe" />
<CustomAction Id="DeployDatabase" Property="SQLPACKAGEPATH"
ExeCommand='/Action:Publish /tcs:"[CONNSTRING]" /sf:"[#My.Database.dacpac]" /p:BackupDatabaseBeforeChanges=True /p:RegisterDataTierApplication=True'
Return="check" Execute="deferred" Impersonate="yes" />
<InstallExecuteSequence>
<Custom Action="DeployDatabase" After="DuplicateFiles">NOT REMOVE</Custom>
</InstallExecuteSequence>
...and I can watch the output in the presented console window, mid-install.
However, it doesn't always succeed; for example, CONNSTRING can be specified in a dialog and may be incorrect. If there are errors, they appear for an instant, then the console closes and I get a 1722 error in the logs.
To capture the console output, I have tried:
<CustomAction Id="DeployDatabase" Property="SQLPACKAGEPATH"
ExeCommand='/Action:Publish /tcs:"[CONNSTRING]" /sf:"[#My.Database.dacpac]" /p:BackupDatabaseBeforeChanges=True /p:RegisterDataTierApplication=True > "[DBLogs]test.log"'
Return="check" Execute="deferred" Impersonate="yes" />
The > "[DBLogs]test.log" on the end should (theoretically) redirect output to a file at that location, but instead, the installer fails out at the moment the console window is shown. It appears that no text is displayed in the console in the instant it is presented.
The kicker is: I can copy the command that is logged with the error (with the > properly resolved to >), paste it into my own cmd window, and it will execute and log.
What am I doing wrong?
And more importantly: what can I do to execute this command and save stdout+stderr to a logfile?
Note: I have also tried this with the type 34 syntax (this way resolves to a type 50). Both exhibit the same behavior.
EXE custom actions have a number of concerns. Read:
Integration Hurdles for EXE Custom Actions
To address several of these issues, including stderr/stdout, Wix includes the Quiet Execution Custom Action.
I have had the same problem where I wanted to log the output of SqlPackage.exe during a WIX MSI Install, so I created a WIX binary extension that handles getting the standard output/error and logging it to a file for sqlpackage.exe.
Check it out at https://wixdacpacinstaller.codeplex.com/.
I made it free and open source.
Quick Snippet from the docs to show how to use it:
<!-- first, add the binary extension. Be sure to specify the source file as WixDacPacExtension.CA.dll. -->
<Binary
Id="WixDacPacExtensionBinary"
SourceFile="<Path to your file>\WixDacPacExtension.CA.dll"/>
<!-- Create a custom action to run first and set up all the parameters that are -->
<!-- passed to the Wix DacPac Extension. The property name MUST MATCH -->
<!-- the name of the custom action that executes the binary defined above. -->
<!-- The parameters in the Value property are semi-colon delimited. -->
<CustomAction
Id="SetupDacPacWIXDacPacInstallerExampleCustomAction"
Property="DacPacWIXDacPacInstallerExampleCustomAction"
Value="ShowUI=True;SqlPackagePath=c:\Program Files (x86)\Microsoft SQL Server\120\DAC\bin\SqlPackage.exe;DacPacPath=[INSTALLFOLDER]WIXDacPacInstallerExample.dacpac;LogFilePath=[TempFolder]\WIXDacPacInstallerExample.dacpac.log;TargetServerName=[DATABASESERVER];TargetDatabaseName=WIXDacPacInstallerExample;OtherParameters=/p:RegisterDataTierApplication=True /p:BlockWhenDriftDetected=False /p:BlockOnPossibleDataLoss=False"
/>
<!--
This custom action will execute the extension with the parameters from Step #1.
NOTE: the Id of this custom action matches the Property of the custom action
from Step #1.
-->
<CustomAction
Id="DacPacWIXDacPacInstallerExampleCustomAction"
BinaryKey="WixDacPacExtensionBinary"
DllEntry="Execute"
Execute="deferred"
Return="check"
/>
I believe there is something about SQLPackage.exe which routes the output (both standard and error) in a non-standard way. I encountered difficulties when running SQLPackage.exe from PowerShell and also had difficulties. No matter what I did, I could not get PowerShell to capture the output from SQLPackage.exe. Ultimately I was able to resolve the problem by using Start-Process cmdlet instead of Invoke-Expression to run SQLPackage.exe, and pass in -RedirectStandardOutput $out and -RedirectStandardError $errorLog. In this way I was at least able to capture the output, but I did notice that even when an error occurred, it wasn't redirected along with the Error redirect, but rather it was redirected to the standard output stream. I don't know exactly why this happens, but it seems like this would be relevant to the results you had in WiX.
I would love to see more about how you were able to incorporate SQLPackage into a WiX installation. Do you have any further information you can share, or resources on how you approached this?

Set environment variable before running a custom action in WiX

I have to build an MSI-based installer using WiX and I need to set environment MY_HOME before running a command action.
I have a component:
<Component Id="SEMYHOME"
Guid="*my guid*">
<CreateFolder />
<Environment Id="MY_HOME"
Action="set"
Part="all"
Name="MY_HOME"
Permanent="no"
System="yes"
Value="[APPLICATIONPATH]myapp"/>
</Component>
Then I have a custom action:
<CustomAction Id="InstallMyService"
Directory="INSTALLDIR"
ExeCommand='"[INSTALLDIR]myapp\install_service.bat" install'
Execute="immediate"
Return="ignore"/>
<InstallExecuteSequence>
<Custom Action="InstallMyService"
After="InstallFinalize"/>
</InstallExecuteSequence>
NOTE: This action need the MY_HOME variable to be set before running.
When install this MSI, I got a log showing that the MY_HOME variable is set before running the custom action "InstallMyService", but the command to install my service still fails. I found that the cause is when command called, MY_HOME still not set.
After an install is finished, MY_HOME was set as expected, but the custom action fails :(
How can I fix this problem?
Windows Installer and Custom Actions are hosted via the Service Control Manager which has a long history of not respecting broadcast messages that are sent announcing Environment changes. So even if you fix the immeadiate / deferred problem that Yan mentions you'll find that your custom action still doesn't have the environment variable.
Why don't just just pass "[APPLICATIONPATH]myapp" to your .bat file and fetch it in as %2?
BTW I also don't reccomend calling batch files from an installer. It's fragile and embarrassing to see installs that run popping up little black windows.
You CA is immediate. This means that it runs immediately when Windows Installer is processing your MSI package. And this obviously happens before the component containing <Environment/> is installed. Modify it to be deferred (Execute="deferred") and schedule before InstallFinalize.