使用包支持框架运行脚本

使用 MSIX 打包应用程序后,脚本使 IT 专业人员能够根据用户环境动态自定义应用程序。 例如,你可以使用脚本来配置数据库、设置 VPN、装载共享驱动器或动态执行许可证检查。 脚本提供了很大的灵活性。 它们可能会更改注册表项,或者根据计算机或服务器配置执行文件修改。

可以使用包支持框架 (PSF) 在打包的应用程序可执行文件运行之前运行一个 PowerShell 脚本,并在应用程序可执行文件运行后运行一个 PowerShell 脚本以清理。 应用程序清单中定义的每个应用程序可执行文件都可以具有自己的脚本。 你可以将脚本配置为仅在第一次应用启动时运行一次,且不显示 PowerShell 窗口,这样用户就不会错误地过早结束脚本。 还有其他选项可配置脚本的运行方式,如下所示。

先决条件

要使脚本能够运行,需要将 PowerShell 执行策略设置为 RemoteSigned。 可以运行以下命令来执行此操作:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

需要同时为 64 位 PowerShell 可执行文件和 32 位 PowerShell 可执行文件设置执行策略。 请确保打开每个版本的 PowerShell 并运行上面所示的其中一个命令。

以下是每个可执行文件的位置。

  • 64 位计算机:
    • 64 位可执行文件:%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe
    • 32 位可执行文件:%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
  • 32 位计算机:
    • 32 位可执行文件:%SystemRoot%\system32\WindowsPowerShell\v1.0\powershell.exe

有关 PowerShell 执行策略的详细信息,请参阅本文

🚩 确保还在包中包含 StartingScriptWrapper.ps1 文件,并将其放置在与可执行文件相同的文件夹中。 可以从 PSF NuGet 包PSF Github 存储库复制此文件。

启用脚本

要指定将为每个打包的应用程序可执行文件运行的脚本,需要修改 config.json 文件。 要告知 PSF 在执行打包的应用程序之前运行脚本,请添加称为 startScript 的配置项目。 要告知 PSF 在打包的应用程序完成之后运行脚本,请添加称为 endScript 的配置项目。

脚本配置项目

以下是可用于脚本的配置项目。 结束脚本将忽略 waitForScriptToFinishstopOnScriptError 配置项目。

项名 值类型 必需? 默认 说明
scriptPath 字符串 空值 包含名称和扩展名的脚本路径。 如果指定,则路径相对于应用程序的工作目录,否则,它从包的根目录开始。
scriptArguments string empty 空格分隔的参数列表。 PowerShell 脚本调用的格式相同。 此字符串会追加到 scriptPath 进行有效的 PowerShell.exe 调用。
runInVirtualEnvironment boolean 指定脚本是否应在打包的应用程序运行的同一虚拟环境中运行。
runOnce boolean 指定脚本是否应按每个版本每个用户运行一次。
showWindow boolean false 指定是否显示 PowerShell 窗口。
stopOnScriptError boolean false 指定在启动脚本失败时是否退出应用程序。
waitForScriptToFinish boolean 指定打包的应用程序是否应在开始之前等待启动脚本完成。
timeout DWORD INFINITE 允许脚本执行的时间长度。 时间过后,脚本将停止。

注意

不支持示例应用程序的设置 stopOnScriptError: truewaitForScriptToFinish: false。 如果同时设置这两个配置项目,PSF 将返回错误 ERROR_BAD_CONFIGURATION。

示例配置

以下是使用两个不同的应用程序可执行文件的示例配置。

{
  "applications": [
    {
      "id": "Sample",
      "executable": "Sample.exe",
      "workingDirectory": "",
      "stopOnScriptError": false,
      "startScript":
      {
        "scriptPath": "RunMePlease.ps1",
        "scriptArguments": "\\\"First argument\\\" secondArgument",
        "runInVirtualEnvironment": true,
        "showWindow": true,
        "waitForScriptToFinish": false
      },
      "endScript":
      {
        "scriptPath": "RunMeAfter.ps1",
        "scriptArguments": "ThisIsMe.txt"
      }
    },
    {
      "id": "CPPSample",
      "executable": "CPPSample.exe",
      "workingDirectory": "",
      "startScript":
      {
        "scriptPath": "CPPStart.ps1",
        "scriptArguments": "ThisIsMe.txt",
        "runInVirtualEnvironment": true
      },
      "endScript":
      {
        "scriptPath": "CPPEnd.ps1",
        "scriptArguments": "ThisIsMe.txt",
        "runOnce": false
      }
    }
  ],
  "processes": [
    ...(taken out for brevity)
  ]
}