使用WixQuietExec静默执行PowerShell脚本失败求助
问题描述
我是WixToolset新手,尝试通过WixQuietExec执行PowerShell脚本。脚本直接用PowerShell运行正常,但通过WixQuietExec执行时失败,报错Error 0x80070007,最终导致安装返回1603错误。
我的WXS代码
<Property Id="POWERSHELLEXE"> <RegistrySearch Id="POWERSHELLEXE" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" Name="Path" /> </Property> <SetProperty Id="SysShell" Before="SysShell" Sequence="execute" Value ="&quot;[POWERSHELLEXE]&quot; -NoProfile -NonInteractive -InputFormat None -ExecutionPolicy Bypass -Command &quot;&amp; '[#CreateEventLogPS1]' ; exit $$($Error.Count)&quot;" /> <CustomAction Id="SysShell" BinaryKey="WixCA" DllEntry="WixQuietExec" Execute="deferred" Return="check" Impersonate="no" /> <InstallExecuteSequence> <Custom Action="SysShell" Before="InstallFinalize"> <![CDATA[NOT Installed]]> </Custom> </InstallExecuteSequence>
错误日志
MSI (s) (E8:C4) [13:41:56:992]: Executing op: ActionStart(Name=SysShell,,) MSI (s) (E8:C4) [13:41:56:992]: Executing op: CustomActionSchedule(Action=SysShell,ActionType=3073,Source=BinaryData,Target=WixQuietExec,CustomActionData="C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -NonInteractive -InputFormat None -ExecutionPolicy Bypass -Command "& 'C:\Program Files\UpdateFile\EventLog.ps1' ; exit $($Error.Count)") MSI (s) (E8:C4) [13:41:57:000]: Creating MSIHANDLE (2) of type 790536 for thread 10436 MSI (s) (E8:50) [13:41:57:000]: Invoking remote custom action. DLL: C:\Windows\Installer\MSIC226.tmp, Entrypoint: WixQuietExec MSI (s) (E8:1C) [13:41:57:000]: Generating random cookie. MSI (s) (E8:1C) [13:41:57:017]: Created Custom Action Server with PID 4160 (0x1040). MSI (s) (E8:C8) [13:41:57:098]: Running as a service. MSI (s) (E8:C8) [13:41:57:098]: Hello, I'm your 32bit Elevated Non-remapped custom action server. MSI (s) (E8!E4) [13:42:03:824]: Creating MSIHANDLE (3) of type 790531 for thread 14820 WixQuietExec: Error 0x80070007: Command line returned an error. MSI (s) (E8!E4) [13:42:03:825]: Closing MSIHANDLE (3) of type 790531 for thread 14820 MSI (s) (E8!E4) [13:42:03:825]: Creating MSIHANDLE (4) of type 790531 for thread 14820 WixQuietExec: Error 0x80070007: QuietExec Failed MSI (s) (E8!E4) [13:42:03:825]: Closing MSIHANDLE (4) of type 790531 for thread 14820 MSI (s) (E8!E4) [13:42:03:826]: Creating MSIHANDLE (5) of type 790531 for thread 14820 WixQuietExec: Error 0x80070007: Failed in ExecCommon method MSI (s) (E8!E4) [13:42:03:827]: Closing MSIHANDLE (5) of type 790531 for thread 14820 CustomAction SystemShell returned actual error code 1603 (note this may not be 100% accurate if translation happened inside sandbox) MSI (s) (E8:50) [13:42:03:828]: Closing MSIHANDLE (2) of type 790536 for thread 10436 Action ended 13:42:03: InstallFinalize. Return value 3.
已尝试的方法
已查阅相关技术资料,但问题仍未解决,恳请提供技术指导。
解决方案建议
1. 修复PowerShell架构匹配问题
从日志看,当前获取到的是32位PowerShell路径(C:\Windows\SysWOW64\...),如果你的MSI是32位包,RegistrySearch默认会重定向到HKLM\SOFTWARE\Wow6432Node,导致拿到32位PowerShell。若脚本需要64位环境执行,修改RegistrySearch添加Win64="yes":
<Property Id="POWERSHELLEXE"> <RegistrySearch Id="POWERSHELLEXE" Type="raw" Root="HKLM" Key="SOFTWARE\Microsoft\PowerShell\1\ShellIds\Microsoft.PowerShell" Name="Path" Win64="yes" /> </Property>
此配置会获取64位PowerShell路径(C:\Windows\System32\...),避免32位进程访问64位目录的权限或路径解析问题。
2. 简化PowerShell命令行参数
用-File参数替代-Command直接执行脚本,减少引号转义错误,同时提升可读性:
<SetProperty Id="SysShell" Before="SysShell" Sequence="execute" Value='"[POWERSHELLEXE]" -NoProfile -NonInteractive -InputFormat None -ExecutionPolicy Bypass -File "[#CreateEventLogPS1]"; exit $$($Error.Count)' />
-File参数会直接运行指定脚本,无需处理&符号的转义,降低命令行出错概率。
3. 添加脚本日志排查细节
在命令中添加日志输出,将脚本执行的所有输出写入文件,便于定位具体错误:
<SetProperty Id="SysShell" Before="SysShell" Sequence="execute" Value='"[POWERSHELLEXE]" -NoProfile -NonInteractive -InputFormat None -ExecutionPolicy Bypass -Command "& '[#CreateEventLogPS1]' *>&1 | Out-File 'C:\temp\ps_script_log.txt' ; exit $$($Error.Count)"' />
注意:需确保C:\temp目录存在,可在脚本开头添加New-Item -Path "C:\temp" -ItemType Directory -Force创建目录。
4. 检查系统账户执行兼容性
由于CustomAction设置了Impersonate="no",脚本会以SYSTEM账户执行,需验证:
- 脚本访问的文件/目录是否给SYSTEM账户分配了读写权限
- 脚本中的Event Log操作是否在SYSTEM权限下可完成(自定义Event Log需确保已提前创建)
- 脚本是否依赖当前用户的环境变量或配置(SYSTEM账户的环境与普通用户不同)
5. 临时禁用错误退出码判断
若怀疑是脚本的非终止错误导致$Error.Count不为0,可临时移除exit $$($Error.Count),测试脚本是否能正常执行:
<SetProperty Id="SysShell" Before="SysShell" Sequence="execute" Value='"[POWERSHELLEXE]" -NoProfile -NonInteractive -InputFormat None -ExecutionPolicy Bypass -File "[#CreateEventLogPS1]"' />
如果安装成功,再逐步排查脚本中的错误来源,调整错误处理逻辑。
内容的提问来源于stack exchange,提问作者im_sam39

