Silently executing a PowerShell script from WiX Ha

2019-02-12 16:10发布

问题:

Note: This question is also posted on the WiX Users mailing list.

I am trying to silently execute a PowerShell script from a WiX produced MSI. However, anytime I run the installer PowerShell hangs. Interestingly enough, according to the installer logs the PowerShell script appears to run successfully. Additionally, if I kill the PowerShell process via Task Manager, the installer cancels the installation and rolls back any changes.

PowerShell Script Contents

# @param website The website under which the module should be compiled and registered.
# @param name The name of the module to be registered.
# @param assembly The assembly name, version, culture and public key token to be compiled.
# @param assemblyType The fully qualified assemebly type to be registered.

param([string]$website = "website", [string]$name = "name", [string]$assembly = "assembly", [string]$assemblyType= "assemblyType")

import-module webadministration
add-webconfiguration /system.web/compilation/assemblies "IIS:\sites\$website" -Value @{assembly="$assembly"}
new-webmanagedmodule -Name "$name" -Type "$assemblyType" -PSPath "IIS:\sites\$website"

WiX Custom Action Contents : Attempt 1

My first attempt at this was to use the & special character to execute the script.

<CustomAction Id="RegisterHttpModulePSCmd"
              Property="RegisterHttpModulePowerShellProperty"
              Value="&quot;C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe&quot; &amp;'C:\Program Files (x86)\My Company\Scripts\register-httpmodule.ps1' -website 'Default Web Site' -name 'MyCustomModule' -assembly 'MyCompany.Product.Feature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxxxxxxxxxx' -assemblyType 'MyCompany.Product.Feature.MyModule'"
              Execute="immediate" />

<CustomAction Id="RegisterHttpModulePowerShellProperty"
              BinaryKey="WixCA" 
              DllEntry="CAQuietExec64" 
              Execute="deferred"
              Return="check" 
              Impersonate="no" />

<InstallExecuteSequence>
   <Custom Action="RegisterHttpModulePSCmd" After="CostFinalize">NOT  Installed</Custom>
   <Custom Action="RegisterHttpModulePowerShellProperty" After="InstallFiles">NOT Installed</Custom>
</InstallExecuteSequence>

WiX Custom Action Contents : Attempt 2

My second attempt was to use the -File argument to execute the script.

<CustomAction Id="RegisterHttpModulePSCmd"
              Property="RegisterHttpModulePowerShellProperty"       
              Value="&quot;C:\Windows\system32\WindowsPowerShell\v1.0\powershell.exe&quot; -NoLogo -NonInteractive -NoProfile -File &quot;C:\Program Files (x86)\My Company\Scripts\register-httpmodule.ps1&quot; -website &quot;Default Web Site&quot; -name &quot;MyCustomModule&quot; -assembly &quot;MyCompany.Product.Feature, Version=1.0.0.0, Culture=neutral, PublicKeyToken=xxxxxxxxxxxxxxxx&quot; -assemblyType &quot;MyCompany.Product.Feature.MyModule&quot;"
              Execute="immediate" />

<CustomAction Id="RegisterHttpModulePowerShellProperty"
              BinaryKey="WixCA" 
              DllEntry="CAQuietExec64" 
              Execute="deferred"
              Return="check" 
              Impersonate="no" />

<InstallExecuteSequence>
   <Custom Action="RegisterHttpModulePSCmd" After="CostFinalize">NOT  Installed</Custom>
   <Custom Action="RegisterHttpModulePowerShellProperty" After="InstallFiles">NOT Installed</Custom>
</InstallExecuteSequence>

Both approaches seem to work as they make modifications to the desired web.config file, however, both approaches hang PowerShell and thus the installer.

Additional Information

I modified the PowerShell script to print out the version information and not perform any other actions. The MSI log files then display the following:

MSI (s) (D4:78) [10:26:31:436]: Hello, I'm your 32bit Elevated custom action server.
CAQuietExec64:  
CAQuietExec64:  
CAQuietExec64:  Name             : ConsoleHost
CAQuietExec64:  Version          : 2.0
CAQuietExec64:  InstanceId       : 62b0349c-8d16-4bd1-94e5-d1fe54a9ff54
CAQuietExec64:  UI               : System.Management.Automation.Internal.Host.InternalHostUserI
CAQuietExec64:                     nterface
CAQuietExec64:  CurrentCulture   : en-US
CAQuietExec64:  CurrentUICulture : en-US
CAQuietExec64:  PrivateData      : Microsoft.PowerShell.ConsoleHost+ConsoleColorProxy
CAQuietExec64:  IsRunspacePushed : False
CAQuietExec64:  Runspace         : System.Management.Automation.Runspaces.LocalRunspace

It is at this point that the installer appears to have stopped as PowerShell does not exit. When I kill PowerShell manually with Task Manager the next few log messages are:

CAQuietExec64:  Error 0x80070001: Command line returned an error.
CAQuietExec64:  Error 0x80070001: CAQuietExec64 Failed CustomAction RegisterHttpModulePowerShellProperty returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox) Action ended 10:27:10: InstallFinalize. Return value 3.

How do I silently execute a PowerShell script from Wix without hanging PowerShell?

回答1:

I saw several posts like this one while searching on an unrelated issue and found an answer. Bottom line: include the flag -InputFormat None in your command line.



回答2:

Have you tried adding the keyword exit to the end of the script?

I came across a similar situation with a C# project I've been working on. After building the project, I invoke PowerShell in the <AfterBuild> target using MSBuild's <Exec> task, specifying the script to run. If the script did not include the exit keyword, VS2010 "hangs" - which is to say it's actually waiting for PowerShell to complete its task, while PowerShell waits for user input.

If you open up Task Manager or SysInternals Process Explorer, you will see powershell.exe running as if nothing's wrong. If you kill the process, VS2010 (i.e. MSBuild) throws an error.

So you will need to tell PowerShell that you are done with it by adding exit to the script it runs, and all should be well again.