Run PowerShell script from WiX installer

11

I have found a couple of examples showing how to run a PowerShell script from WiX but have not been successful running either of them. So, I'd like to post what I have with the hope that someone can point out what I am doing wrong.

<!--Install the PowerShell script-->
<DirectoryRef Id="INSTALLFOLDER">
  <Component Id="cmp_ShutdownIExplore" Guid="{4AFAACBC-97BB-416f-9946-68E2A795EA20}" KeyPath="yes">
    <File Id="ShutdownIExplore" Name="ShutdownIExplore.ps1" Source="$(var.ProjectDir)Source\PowerShell\ShutdownIExplore.ps1" Vital="yes" />
  </Component>
</DirectoryRef>

<!--Define the CustomAction for running the PowerShell script-->
<CustomAction Id="RunPowerShellScript" BinaryKey="WixCA" DllEntry="CAQuietExec" Execute="deferred" Return="check" Impersonate="yes" />

<InstallExecuteSequence>

  <!--Invoke PowerShell script -->
  <Custom Action="RunPowerShellScript" After="InstallFiles"><![CDATA[NOT Installed]]></Custom>
</InstallExecuteSequence>

<!-- Define custom action to run a PowerShell script-->
<Fragment>
  <!-- Ensure PowerShell is installed and obtain the PowerShell executable location -->
  <Property Id="POWERSHELLEXE">
    <RegistrySearch Id="POWERSHELLEXE"
                    Type="raw"
                    Root="HKLM"
                    Key="SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell"
                    Name="Path" />
  </Property>
  <Condition Message="This application requires Windows PowerShell.">
    <![CDATA[Installed OR POWERSHELLEXE]]>
  </Condition>

  <!-- Define the PowerShell command invocation -->
  <SetProperty Id="RunPowerShellScript"
           Before ="InstallFiles"
           Sequence="execute"
           Value ="&quot;[POWERSHELLEXE]&quot; -Version 2.0 -NoProfile -NonInteractive -InputFormat None -ExecutionPolicy Bypass -Command &quot;&amp; '[#ShutdownIExplore.ps1]' ; exit $$($Error.Count)&quot;" />
</Fragment>

When I run the installer I have created I get the following error (from log):

MSI (s) (DC:F8) [11:21:46:424]: Executing op: ActionStart(Name=RunPowerShellScript,,)
Action 11:21:46: RunPowerShellScript. 
MSI (s) (DC:F8) [11:21:46:425]: Executing op: CustomActionSchedule(Action=RunPowerShellScript,ActionType=1025,Source=BinaryData,Target=CAQuietExec,)
MSI (s) (DC:9C) [11:21:46:459]: Invoking remote custom action. DLL: C:\Windows\Installer\MSI8228.tmp, Entrypoint: CAQuietExec
CAQuietExec:  Error 0x80070057: failed to get command line data
CAQuietExec:  Error 0x80070057: failed to get Command Line
CustomAction RunPowerShellScript returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox)
Action ended 11:21:46: InstallFinalize. Return value 3.

I am not at all clear what this error is trying to say. Are my internal references bad? Is the command to execute the script bad? Something else?

Any help is most appreciated and thanks in advance.

powershell
wix
windows-installer
asked on Stack Overflow Dec 26, 2012 by Greg Prosch • edited Dec 27, 2012 by Yan Sklyarenko

3 Answers

6

Looks like you have scheduled the CAQuietExec action as deferred. In this case you have to pass the command line to be executed via a CustomActionData property called QtExecDeferred which is written to the execution script. The deferred action can then access the property from the script.

More details at http://wixtoolset.org/documentation/manual/v3/customactions/qtexec.html

answered on Stack Overflow Dec 27, 2012 by Stephen Connolly • edited Feb 10, 2015 by dcharles
3

I didn't understand Stephen's answer, however I eventually got it working with the help of this blog post.

Here's a summary of the change I made to Greg's code to get it to work:

  • I changed CAQuietExec to WixQuietExec (I'm not sure if this was necessary).

  • In SetProperty I changed the value of the Before attribute from InstallFiles to the Id of the custom action; in Greg's case it would be RunPowerShellScript.

  • Although unrelated to the question, I ended up needing to change the -Version of powershell to 3.0 from 2.0 to prevent an error when running my script.

Here was my actual working code:

<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:iis="http://schemas.microsoft.com/wix/IIsExtension" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
    <Product Id="*" Name="..." Language="1033" Version="..." Manufacturer="..." UpgradeCode="...">
        <Property Id="POWERSHELLEXE">
        <RegistrySearch Id="POWERSHELLEXE"
            Type="raw"
            Root="HKLM"
            Key="SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell"
            Name="Path" />
        </Property>
        <Condition Message="This application requires Windows PowerShell.">
            <![CDATA[Installed OR POWERSHELLEXE]]>
        </Condition>

        <SetProperty Id="InstallMongoDB"
            Before ="InstallMongoDB"
            Sequence="execute"
            Value="&quot;[POWERSHELLEXE]&quot; -Version 3.0 -NoProfile -NonInteractive -InputFormat None -ExecutionPolicy Bypass -Command &quot;&amp; '[#MONGODB_INSTALL.PS1]' ; exit $$($Error.Count)&quot;" />

        <CustomAction Id="InstallMongoDB" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="deferred" Return="check" Impersonate="yes" />

        <InstallExecuteSequence>
            <Custom Action="InstallMongoDB" Before="InstallFinalize"><![CDATA[NOT Installed]]></Custom>
        </InstallExecuteSequence>


        <Component Id="MONGODB_INSTALL.PS1" Guid="..." DiskId="1">
            <File Id="MONGODB_INSTALL.PS1" Name="mongodb-install.ps1" Source="mongodb-install.ps1"/>
        </Component>
    </Product>
    <Fragment>
        <Directory Id="TARGETDIR" Name="SourceDir">
            <Directory Id="ProgramFilesFolder">
                <Directory Id="APPLICATIONFOLDER" Name="...">
                    <Directory Id="InstallScripts" Name="InstallScripts">
                        <Component Id="MONGODB_INSTALL.PS1" Guid="..." DiskId="1">
                            <File Id="MONGODB_INSTALL.PS1" Name="mongodb-install.ps1" Source="mongodb-install.ps1"/>
                        </Component>
                    </Directory>
                </Directory>
            </Directory>
        </Directory>
    </Fragment>
</Wix>
answered on Stack Overflow Sep 28, 2017 by Jesus is Lord
0

Only the following example helped me https://github.com/damienbod/WiXPowerShellExample/blob/master/SetupWithPowerShellScripts/Product.wxs

you need to add smth similar into your 'Product.wxs'. the 'Value' property of the first 'CustomAction' contains a ps script (create and run a windows service in my case).

<!-- assign the string (ps command) to RegisterPowerShellProperty -->
<CustomAction Id="RegisterWindowsService"
                        Property="RegisterPowerShellProperty"
                        Value="&quot;C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe&quot; -NoLogo -NonInteractive -InputFormat None -NoProfile sc.exe create MyService binpath= 'C:\Program Files (x86)\My service\MyService.exe';sc.exe start MyService"
                        Execute="immediate" />

<!-- Deferred execution of the above script -->
<CustomAction Id="RegisterPowerShellProperty"
          BinaryKey="WixCA"
          DllEntry="CAQuietExec64"
          Execute="deferred"
          Return="check"
          Impersonate="no" />

<InstallExecuteSequence>
  <!-- On installation we register and start a windows service -->
  <Custom Action="RegisterWindowsService" After="CostFinalize">NOT  Installed</Custom>
  <Custom Action="RegisterPowerShellProperty" After="InstallFiles">NOT Installed</Custom>
</InstallExecuteSequence>

you will need to add a reference to 'WixUtilExtension' in order to run the script.

answered on Stack Overflow Nov 3, 2020 by Razor23 Donetsk

User contributions licensed under CC BY-SA 3.0