如何在 MSI 安装期间运行接受命令行参数的 PowerShell 脚本

问题描述 投票:0回答:1

从命令行安装电子应用程序时,我需要将 2 个参数传递给 MSI。例如:

msiexec /i "C:\example\filepath\ExampleAppInstaller.msi" USERID="1234" APIKEY="5678" /quiet

我希望 MSI 运行一个 powershell 脚本,在安装过程中的某个时间将这些参数保存在用户计算机上的临时文件中。当应用程序在安装后首次运行时,它将从临时文件中读取并使用应用程序中的参数。

我遇到问题的部分是在 MSI 中创建自定义操作,该操作将运行创建临时文件的 PowerShell 脚本。我尝试过使用 Wix 工具集,但无法让它工作。我有Wix版本5.0.1+2f00cbe6。

这是我在 MSI 安装期间尝试运行的 PowerShell 脚本(名为“writeParams.ps1”):

param(
    [string]$UserID,
    [string]$ApiKey
)

# Define the folder and file paths dynamically using the environment variable
$AppDataFolder = "$env:APPDATA\ExampleAppTest"
$filePath = "$AppDataFolder\installParams.json"

# Check if the folder exists, if not, create it
if (-not (Test-Path -Path $AppDataFolder)) {
    New-Item -Path $AppDataFolder -ItemType Directory
}

# Create the JSON content with the provided parameters
$jsonContent = @{
    userId = $UserID
    apiKey = $ApiKey
} | ConvertTo-Json

# Write the JSON content to the file
$jsonContent | Out-File -FilePath $filePath

# Exit with a success code
exit 0

我尝试使用 .wixproj 文件构建 MSI。这是我的 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 Information -->
  <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" />

    <!-- Media element defines the cabinet file -->
    <Media Id="1" Cabinet="media1.cab" EmbedCab="yes" />

    <!-- Directories define the installation path -->
    <Directory Id="TARGETDIR" Name="SourceDir">
      <Directory Id="ProgramFilesFolder">
        <Directory Id="INSTALLFOLDER" Name="ExampleApp"/>
      </Directory>
    </Directory>

    <!-- Feature defines what will be installed -->
    <Feature Id="DefaultFeature" Level="1">
      <ComponentGroupRef Id="ProductComponents"/>
    </Feature>
  </Product>

  <!-- Define the files to be installed -->
  <Fragment>
    <DirectoryRef Id="INSTALLFOLDER">
      <Component Id="PowerShellComponent" Guid="1e20057b-3f79-4258-b054-27767beb202c">
        <File Id="PowerShellScript" Source="writeParams.ps1" KeyPath="yes"/>
      </Component>
    </DirectoryRef>
  </Fragment>

  <!-- ComponentGroup for grouping components -->
  <Fragment>
    <ComponentGroup Id="ProductComponents">
      <ComponentRef Id="PowerShellComponent"/>
    </ComponentGroup>
  </Fragment>

  <!-- Define the custom action to run the PowerShell script -->
  <Fragment>
    <CustomAction Id="RunPowerShellScript"
                  Property="powershell.exe"
                  ExeCommand="-ExecutionPolicy Bypass -File &quot;[INSTALLFOLDER]writeParams.ps1&quot; -UserID [USERID] -ApiKey [APIKEY]"
                  Execute="deferred"
                  Return="check"
                  Impersonate="no"/>

    <!-- Run the custom action after the installation files are copied -->
    <InstallExecuteSequence>
      <Custom Action="RunPowerShellScript" After="InstallFiles">NOT Installed</Custom>
    </InstallExecuteSequence>
  </Fragment>

</Wix>

我已经被困在这个问题上有一段时间了,所以任何帮助将不胜感激!

wix windows-installer
1个回答
0
投票

tl;dr: 您的 PowerShell 脚本引用了特定于用户的环境变量

$env:APPDATA
,但自定义操作的运行没有 模拟。这会导致您的脚本在本地系统用户的上下文中运行,将 JSON 写入与预期不同的路径。

修补程序将在自定义操作上设置

Impersonate="yes"
,但由于您的产品是为所有用户安装的 (
InstallScope="perMachine"
),因此该修补程序仅适用于安装用户与安装用户相同的特定用例。将实际使用该软件(在由管理员安装软件的公司环境中,甚至在多人使用同一台计算机时的家庭使用中,通常情况并非如此)。

更改为实际的每用户安装 (

InstallScope="perUser"
) 可能是更明智的解决方案。


以下建议旨在帮助您将来更轻松地诊断 PowerShell 自定义操作问题。

PowerShell 自定义操作

对于运行 PowerShell 脚本,我强烈建议使用 安静执行自定义操作(请注意 WiX v3 和 v4/5 的不同操作名称)。

优点:

  1. 防止控制台窗口短暂弹出 - 即使使用参数
    -WindowStyle hidden
    powershell.exe
    ,该问题仍然存在。
  2. 将所有 PowerShell 输出重定向到 MSI 日志,因此可以通过简单的
    Write-Host
    语句完成日志记录。

PowerShell 脚本建议

PowerShell 脚本的最佳实践是在脚本中尽早设置

$ErrorActionPreference = 'Stop'
,这样错误就不会被忽视。其效果是,任何错误都会自动转变为脚本终止错误,这会导致 PowerShell 退出代码不为零,因此 Windows Installer 可以检测并报告错误。

如果您想要有选择地抑制脚本终止错误(通常是为了在条件下进行显式测试),您可以将

-ErrorAction Continue
(报告错误并继续)或
-ErrorAction SilentlyContinue
(继续而不报告)传递给各个命令。

将所有必需参数指定为强制,以检测参数传递中的错误。

param(
    [Parameter(Mandatory=$true)
    [string]$UserID,

    [Parameter(Mandatory=$true)
    [string]$ApiKey
)

$ErrorActionPreference = 'Stop'

# The logging automatically ends up in the MSI log
Write-Host "PowerShell script received these args: UserId=$UserID, ApiKey=$ApiKey"

# remaining code

写入详细的 MSI 日志

使用参数

/l*v LOGPATH
调用 msiexec 以写入详细日志,其中将包括 PowerShell 脚本的日志消息:

msiexec /i "C:\example\filepath\ExampleAppInstaller.msi" USERID="1234" APIKEY="5678" /quiet /l*v "c:\example\filepath\ExampleAppInstaller.log"
© www.soinside.com 2019 - 2024. All rights reserved.