如何在MSI安装Electron应用时运行带命令行参数的PowerShell脚本
解决Wix Toolset中MSI传递参数并执行PowerShell脚本的问题
问题场景
需通过命令行给Electron应用的MSI安装包传入USERID和APIKEY参数,示例命令:
msiexec /i "C:\example\filepath\ExampleAppInstaller.msi" USERID="1234" APIKEY="5678" /quiet
要求MSI安装时运行PowerShell脚本,将参数保存到用户APPDATA目录的JSON文件中,供应用首次启动读取。但使用Wix Toolset 5.0.1+2f00cbe6配置自定义动作后无法成功执行。
现有代码
PowerShell脚本(writeParams.ps1)
param( [string]$UserID, [string]$ApiKey ) # 动态定义文件夹和文件路径 $AppDataFolder = "$env:APPDATA\ExampleAppTest" $filePath = "$AppDataFolder\installParams.json" # 检查文件夹是否存在,不存在则创建 if (-not (Test-Path -Path $AppDataFolder)) { New-Item -Path $AppDataFolder -ItemType Directory } # 创建包含参数的JSON内容 $jsonContent = @{ userId = $UserID apiKey = $ApiKey } | ConvertTo-Json # 将JSON写入文件 $jsonContent | Out-File -FilePath $filePath # 退出并返回成功码 exit 0
Wix项目文件(ExampleAppProject.wixproj)
<Project Sdk="WixToolset.Sdk/5.0.1"> <PropertyGroup> <OutputType>Package</OutputType> <WixOutputName>ExampleAppInstaller</WixOutputName> <WixOutputType>MSI</WixOutputType> </PropertyGroup> <ItemGroup> <WixSource Include="Product.wxs" /> </ItemGroup> </Project>
Product.wxs文件
<?xml version="1.0"?> <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> <!-- 产品信息 --> <Product Id="*" Name="ExampleApp" Language="1033" Version="1.0.0.0" Manufacturer="Example" UpgradeCode="86a341fc-f2ff-4fc6-9627-8127bb1efc68"> <Package InstallerVersion="500" Compressed="yes" InstallScope="perMachine" /> <!-- 媒体元素定义cab文件 --> <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" /> <!-- 目录定义安装路径 --> <Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="ProgramFilesFolder"> <Directory Id="INSTALLFOLDER" Name="ExampleApp"/> </Directory> </Directory> <!-- 功能定义安装内容 --> <Feature Id="DefaultFeature" Level="1"> <ComponentGroupRef Id="ProductComponents"/> </Feature> </Product> <!-- 定义要安装的文件 --> <Fragment> <DirectoryRef Id="INSTALLFOLDER"> <Component Id="PowerShellComponent" Guid="1e20057b-3f79-4258-b054-27767beb202c"> <File Id="PowerShellScript" Source="writeParams.ps1" KeyPath="yes"/> </Component> </DirectoryRef> </Fragment> <!-- 组件组 --> <Fragment> <ComponentGroup Id="ProductComponents"> <ComponentRef Id="PowerShellComponent"/> </ComponentGroup> </Fragment> <!-- 定义执行PowerShell脚本的自定义动作 --> <Fragment> <CustomAction Id="RunPowerShellScript" Property="powershell.exe" ExeCommand="-ExecutionPolicy Bypass -File "[INSTALLFOLDER]writeParams.ps1" -UserID [USERID] -ApiKey [APIKEY]" Execute="deferred" Return="check" Impersonate="no"/> <!-- 在安装文件复制后运行自定义动作 --> <InstallExecuteSequence> <Custom Action="RunPowerShellScript" After="InstallFiles">NOT Installed</Custom> </InstallExecuteSequence> </Fragment> </Wix>
问题原因及修复步骤
核心问题
- 未声明公共属性:传入的
USERID和APIKEY未在Wix中定义为公共属性,MSI会忽略外部传入的未声明参数。 - 延迟动作无法访问即时属性:延迟执行的自定义动作默认无法直接读取
USERID这类即时属性,需要通过SetProperty动作传递参数。 - 权限与路径问题:设置
Impersonate="no"后,脚本以系统权限运行,$env:APPDATA指向系统账户目录,而非当前用户目录。
修复后的Product.wxs关键改动
1. 声明公共属性
在<Product>节点内添加:
<Property Id="USERID" Secure="yes" /> <Property Id="APIKEY" Secure="yes" />
Secure="yes"确保属性可在延迟动作中访问。
2. 添加参数传递动作
创建即时的SetProperty动作,将参数存入延迟动作的上下文:
<CustomAction Id="SetScriptParams" Property="RunPowerShellScript" Value="-ExecutionPolicy Bypass -File "[INSTALLFOLDER]writeParams.ps1" -UserID [USERID] -ApiKey [APIKEY]" Execute="immediate"/>
3. 调整自定义动作配置
修改原延迟动作的ExeCommand为空,参数通过SetProperty传递,并开启用户模拟:
<CustomAction Id="RunPowerShellScript" Property="powershell.exe" ExeCommand="" Execute="deferred" Return="check" Impersonate="yes"/>
4. 调整执行顺序
确保先执行参数设置动作,再执行脚本:
<InstallExecuteSequence> <Custom Action="SetScriptParams" Before="RunPowerShellScript">NOT Installed</Custom> <Custom Action="RunPowerShellScript" After="InstallFiles">NOT Installed</Custom> </InstallExecuteSequence>
完整修复后的Product.wxs
<?xml version="1.0"?> <Wix xmlns="http://wixtoolset.org/schemas/v4/wxs"> <Product Id="*" Name="ExampleApp" Language="1033" Version="1.0.0.0" Manufacturer="Example" UpgradeCode="86a341fc-f2ff-4fc6-9627-8127bb1efc68"> <Package InstallerVersion="500" Compressed="yes" InstallScope="perMachine" /> <!-- 声明公共属性,允许外部传入并在延迟动作中访问 --> <Property Id="USERID" Secure="yes" /> <Property Id="APIKEY" Secure="yes" /> <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" /> <Directory Id="TARGETDIR" Name="SourceDir"> <Directory Id="ProgramFilesFolder"> <Directory Id="INSTALLFOLDER" Name="ExampleApp"/> </Directory> </Directory> <Feature Id="DefaultFeature" Level="1"> <ComponentGroupRef Id="ProductComponents"/> </Feature> </Product> <Fragment> <DirectoryRef Id="INSTALLFOLDER"> <Component Id="PowerShellComponent" Guid="1e20057b-3f79-4258-b054-27767beb202c"> <File Id="PowerShellScript" Source="writeParams.ps1" KeyPath="yes"/> </Component> </DirectoryRef> </Fragment> <Fragment> <ComponentGroup Id="ProductComponents"> <ComponentRef Id="PowerShellComponent"/> </ComponentGroup> </Fragment> <Fragment> <!-- 即时动作:设置延迟动作的参数 --> <CustomAction Id="SetScriptParams" Property="RunPowerShellScript" Value="-ExecutionPolicy Bypass -File "[INSTALLFOLDER]writeParams.ps1" -UserID [USERID] -ApiKey [APIKEY]" Execute="immediate"/> <!-- 延迟动作:执行PowerShell脚本 --> <CustomAction Id="RunPowerShellScript" Property="powershell.exe" ExeCommand="" Execute="deferred" Return="check" Impersonate="yes"/> <InstallExecuteSequence> <Custom Action="SetScriptParams" Before="RunPowerShellScript">NOT Installed</Custom> <Custom Action="RunPowerShellScript" After="InstallFiles">NOT Installed</Custom> </InstallExecuteSequence> </Fragment> </Wix>
调试建议
- 启用MSI日志:运行安装命令时添加
/L*V "install.log"参数,查看日志中自定义动作的执行细节和错误信息。 - 单独测试脚本:手动运行
powershell.exe -ExecutionPolicy Bypass -File writeParams.ps1 -UserID 1234 -ApiKey 5678,确认脚本本身功能正常。
内容的提问来源于stack exchange,提问作者Benson Craft
相关产品推荐
相关产品推荐

