PowerShell 配置器
类型:powershell
Packer 的 PowerShell 配置器在 Windows 机器上运行 PowerShell 脚本。它默认使用的通信器是 WinRM。然而,当与 SSH 通信器结合使用时,配置器可以同样工作(有一些注意事项)。有关详细信息,请参阅下面的部分。
注意:如果可能,尽量始终使用斜杠 /
作为路径分隔符,尤其是在处理相对路径时。反斜杠 \
可以用于 Windows,并且是官方的 Windows 路径分隔符,但是当从任何非 Windows 系统构建镜像时,Packer 只会将斜杠 /
视为路径分隔符,并将反斜杠视为纯文本。这可能会导致路径错误。
基础用法
HCL2:
provisioner "powershell" {
inline = ["dir c:/"]
}
Json:
{
"type": "powershell",
"inline": ["dir c:/"]
}
配置参数
下面列出了可用配置选项的参考。唯一必须的元素是 inline
或 script
,此外的其他参数都是可选的。
以下参数必须选一配置:
inline
(array of string)- 这是一组要执行的命令。这些命令由换行符连接起来并变成一个文件,因此它们都在相同的上下文中执行。这使得您可以在一个命令中更改目录,并在下一个命令中使用目录中的内容,依此类推。内联脚本是在机器内完成简单任务的最简单方法。script
(string) - 要上传到机器并执行的脚本的路径。此路径可以是绝对路径或相对路径。如果是相对路径,就是相对于Packer执行时的工作目录。scripts
(array of string)- 要执行的脚本数组。脚本将按照指定的顺序上传和执行。每个脚本都是独立执行的,因此一个脚本中的变量等状态不会传递到下一个脚本。
选填参数
binary
(boolean) - 如果为true
,则指定脚本是二进制文件,因此 Packer 不应将 Windows 行结尾转换为 Unix 行结尾(如果有的话)。默认为false
。valid_exit_codes
(整数列表)- 脚本的有效返回值。默认情况下是 0。debug_mode
- 如果配置该参数,则设置 PowerShell 的 PSDebug 模式以使脚本调试更容易。例如,将值设置为1
会将下面的命令添加到执行命令中:
Set-PSDebug -Trace 1
elevated_execute_command
(string)- 用于执行提权脚本的命令。默认情况下,如下所示:
powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"
由于配置器是一个模板引擎。因此,您可以在此字段中使用用户变量和模板函数。此外,您可以使用两个额外的变量:
- Path:要运行的脚本的路径
Vars:包含
environment_vars
列表的临时文件的位置(如果已配置)。Path
和Vars
的值都可以通过分别设置remote_path
和remote_env_var_path
的值来手动配置。如果您使用 SSH 通信器并更改了默认
shell
,您可能需要修改execute_command
以确保该命令有效且正确转义;默认将使用cmd
。
env
(map(string))- 在execute_command
之前注入的键/值对映射。 Packer 也会默认将一些环境变量注入到环境中,这将在下面的部分中介绍。重复的env
设置会覆盖environment_vars
中的设置。这不是启用 JSON 模板引擎的函数。 HCL 插值照常工作。environment_vars
([]string)- 在execute_command
之前注入的键/值对数组。格式应为key=value
。 Packer 也会默认将一些环境变量注入到环境中,这将在下面的部分中介绍。use_pwsh
(bool)- 运行pwsh.exe
而不是powershell.exe
。默认为false
。 该值是一个模板引擎。因此,您可以在此字段中使用用户变量和模板函数。如果您在 AWS、Azure、Google Compute 或 OpenStack 上运行并且想要访问 Packer 用于通过 WinRM 连接到实例的自动生成的密码,您可以使用构建模板引擎通过{ { build `Password` } }
注入密码。在 HCL 模板中,您可以通过访问构建变量来做同样的事情,例如:
HCL2:
provisioner "powershell" {
environment_vars = ["WINRMPASS=${build.Password}"]
inline = ["Write-Host \"Automatically generated aws password is: $Env:WINRMPASS\""]
}
Json:
{
"type": "powershell",
"environment_vars": ["WINRMPASS={ { build `Password` } }"],
"inline": ["Write-Host \"Automatically generated aws password is: $Env:WINRMPASS\""]
},
execute_command
(string) - 用于执行脚本的命令。默认情况下,如下所示:
powershell -executionpolicy bypass "& { if (Test-Path variable:global:ProgressPreference){$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit $LastExitCode }"
该值是一个模板引擎。因此,您可以在此字段中使用用户变量和模板函数。此外,您可以使用两个额外的变量:
Path
:要运行的脚本的路径Vars
:包含environment_vars
列表的临时文件的位置(如果已配置)。Path
和Vars
的值都可以通过分别设置remote_path
和remote_env_var_path
的值来手动配置。 如果您使用 SSH 通信器并更改了默认 shell,您可能需要修改execute_command
以确保该命令有效且正确转义;默认假定您没有将默认 shell 更改为cmd
。
elevated_user
和elevated_password
(string)- 如果指定,PowerShell 脚本将使用给定的 Windows 用户以提权模式运行。 该值是一个模板引擎。因此,您可以在此字段中使用用户变量和模板函数。如果您在 AWS、Azure、Google Compute 或 OpenStack 上运行并且想要访问 Packer 用于通过 WinRM 连接到实例的自动生成的密码,您可以使用构建模板引擎通过{ { build `Password` } }
注入密码。在 HCL 模板中,您可以通过访问构建变量来完成相同的功能,例如:HCL2:
provisioner "powershell" {
elevated_user = "Administrator"
elevated_password = build.Password
}
Json:
{
"type": "powershell",
"elevated_user": "Administrator",
"elevated_password": "{ { build `Password` } }",
...
},
如果您指定了空的 elevated_password
值,则 PowerShell 脚本将作为服务帐户运行。例如:
HCL2:
provisioner "powershell" {
elevated_user = "SYSTEM"
elevated_password = ""
}
Json:
{
"type": "powershell",
"elevated_user": "SYSTEM",
"elevated_password": "",
...
},
execution_policy
- 要在 Windows 上运行 PowerShell 脚本,Packer 默认将此设置为 "bypass" 并包装要运行的命令。将此设置为 "none" 将防止包装,允许在 Windows 上看到 Docker 的退出代码。可能的值为bypass
、allsigned
、default
、remotesigned
、restricted
、undefined
、unrestricted
和none
。remote_path
(string) - PowerShell 脚本将被上传到目标构建机器中的路径。默认为C:/Windows/Temp/script-UUID.ps1
,其中 UUID 替换为动态生成的唯一标识脚本的字符串。 此设置允许用户覆盖默认上传位置。该值必须是可写位置,并且所有父目录必须已经存在。remote_env_var_path
(string)- 通过 PowerShell 脚本中上传所需的环境变量到远程环境中,然后在通过“dot sourcing”脚本执行主命令或脚本。 环境变量脚本将上传到的路径默认为C:/Windows/Temp/packer-ps-env-vars-UUID.ps1
,其中 UUID 被替换为动态生成的唯一标识脚本的字符串。 此设置允许用户改写环境变量脚本上传到的位置。该值必须是可写位置,并且所有父目录必须已经存在。skip_clean
(bool) - 是否在执行配置器后清理脚本。默认为false
。当为true
时,任何由非提权的 Powershell 配置器创建的脚本都将从远程计算机中删除。无论为skip_clean
设置的值如何,提权的脚本以及规划的任务将始终被删除。start_retry_timeout
(string) - 尝试启动远程进程的延时。默认情况下,这是5m
或 5 分钟。此设置的存在是为了处理 SSH 可能重新启动的时间,例如系统重新启动。如果重新启动需要更长的时间,请将此设置为更高的值。pause_after
(string) - 配置 PowerShell 脚本后等待的时间,如果前面的所有步骤都成功了,则暂停。
所有配置器共有的参数:
pause_before
(duration) - 执行前休眠一段时间。max_retries
(int) - provisioner 在失败的情况下重试的最大次数。默认为零 (0)。零表示不会重试错误。only
(array of string) - 只运行列表中指定的的配置器程序。override
(object) - 使用特定配置器的不同设置覆盖配置器,例如:
HCL2:
source "null" "example1" {
communicator = "none"
}
source "null" "example2" {
communicator = "none"
}
build {
sources = ["source.null.example1", "source.null.example2"]
provisioner "shell-local" {
inline = ["echo not overridden"]
override = {
example1 = {
inline = ["echo yes overridden"]
}
}
}
}
Json:
{
"builders": [
{
"type": "null",
"name": "example1",
"communicator": "none"
},
{
"type": "null",
"name": "example2",
"communicator": "none"
}
],
"provisioners": [
{
"type": "shell-local",
"inline": ["echo not overridden"],
"override": {
"example1": {
"inline": ["echo yes overridden"]
}
}
}
]
}
timeout
(duration)- 如果配置器完成时间超过配置值(例如1h10m1s
或10m
),则配置器将超时并失败。
默认的环境变量
除了能够使用 environment_vars
配置自定义环境变量外,配置器还会自动定义某些常用的环境变量:
PACKER_BUILD_NAME
值为 Packer 正在运行的构建的名称。这在 Packer 进行多个构建并且您希望将它们彼此能有所区分时最有用。PACKER_BUILDER_TYPE
是用于创建运行脚本的机器的构建器类型。如果您只想在使用特定构建器构建的系统上运行脚本的特定部分,这将很有用。PACKER_HTTP_ADDR
如果使用为文件传输提供 HTTP 服务器的构建器(例如hyperv
、parallels
、qemu
、virtualbox
和vmware
),这将被设置为 HTTP 服务器地址。您可以在配置器中使用此地址通过 HTTP 下载大文件。如果您在使用默认文件配置器时遇到较慢的速度,这可能很有用。使用winrm
通信器的file
配置器可能会遇到这些类型的困难。
将 PowerShell Provisioner 与 SSH Communicator 相结合
先说好消息。如果您使用的是 Microsoft 的 OpenSSH 移植版本,那么配置程序应该会按预期工作 —— 不需要额外的配置工作。
下面是警告。如果您使用的是替代配置,并且您的 SSH 连接使您进入远程主机上的 *nix shell,那么您很可能需要手动设置 execute_command
; Packer 使用的默认 execute_command
对您不起作用。配置命令时,您需要确保相应地转义任何可能被远程 shell 错误解释的 $
符号或其他字符。
以下示例显示了如何重新配置标准 execute_command
以在安装了 Cygwin/OpenSSH 的远程系统上工作。 execute_command
对每个 $
符号反斜杠进行了转义,这样它就不会被远程 Bash shell 解释——Bash 是 Cygwin 环境的默认 shell。
HCL2:
provisioner "powershell" {
execute_command = "powershell -executionpolicy bypass \"& { if (Test-Path variable:global:ProgressPreference){\\$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit \\$LastExitCode }\""
inline = [ "Write-Host \"Hello from PowerShell\""]
}
Json:
"provisioners": [
{
"type": "powershell",
"execute_command": "powershell -executionpolicy bypass \"& { if (Test-Path variable:global:ProgressPreference){\\$ProgressPreference='SilentlyContinue'};. {{.Vars}}; &'{{.Path}}'; exit \\$LastExitCode }\"",
"inline": ["Write-Host \"Hello from PowerShell\""]
}
]
Packer 对 PowerShell 特殊字符的处理
PowerShell 中的转义字符是 backtick
(反引号),有时也称为 grave accent
(重音符)。何时以及何时不转义 PowerShell 的特殊字符可能最好通过一系列示例来说明。
需要转义的情况
当 PowerShell 特有的转义字符直接出现在 PowerShell 配置器的 inline
命令中,或者当它们直接出现在用户自己的脚本中时,用户需要处理 PowerShell 这些转义字符。请注意,如果 Json 模板中的双引号内出现双引号,则需要添加反斜杠转义才能正确解析。
HCL2:
provisioner "powershell" {
inline = [
"Write-Host \"A literal dollar `$ must be escaped\"",
"Write-Host \"A literal backtick `` must be escaped\"",
"Write-Host \"Here `\"double quotes`\" must be escaped\"",
"Write-Host \"Here `'single quotes`' don`'t really need to be\"",
"Write-Host \"escaped... but it doesn`'t hurt to do so.\"",
]
}
Json:
"provisioners": [
{
"type": "powershell",
"inline": [
"Write-Host \"A literal dollar `$ must be escaped\"",
"Write-Host \"A literal backtick `` must be escaped\"",
"Write-Host \"Here `\"double quotes`\" must be escaped\"",
"Write-Host \"Here `'single quotes`' don`'t really need to be\"",
"Write-Host \"escaped... but it doesn`'t hurt to do so.\""
]
}
]
上面的代码片段应该会在 Packer 控制台上产生以下输出:
==> amazon-ebs: Provisioning with Powershell...
==> amazon-ebs: Provisioning with PowerShell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner508190439
amazon-ebs: A literal dollar $ must be escaped
amazon-ebs: A literal backtick ` must be escaped
amazon-ebs: Here "double quotes" must be escaped
amazon-ebs: Here 'single quotes' don't really need to be
amazon-ebs: escaped... but it doesn't hurt to do so.
无需转义的情况
用户环境变量值以及 elevated_user
和 elevated_password
字段中出现的特殊字符将自动为用户处理。在这些情况下无需使用转义符。
HCL2:
variable "psvar" {
type = string
default = "My$tring"
}
build {
sources = ["source.amazon-ebs.example"]
provisioner "powershell" {
elevated_user = "Administrator"
elevated_password = "Super$3cr3t!"
inline = ["Write-Output \"The dollar in the elevated_password is interpreted correctly\""]
}
provisioner "powershell" {
environment_vars = [
"VAR1=A$Dollar",
"VAR2=A`Backtick",
"VAR3=A'SingleQuote",
"VAR4=A\"DoubleQuote",
"VAR5=${var.psvar}",
]
inline = [
"Write-Output \"In the following examples the special character is interpreted correctly:\"",
"Write-Output \"The dollar in VAR1: $Env:VAR1\"",
"Write-Output \"The backtick in VAR2: $Env:VAR2\"",
"Write-Output \"The single quote in VAR3: $Env:VAR3\"",
"Write-Output \"The double quote in VAR4: $Env:VAR4\"",
"Write-Output \"The dollar in VAR5 (expanded from a user var): $Env:VAR5\"",
]
}
}
Json:
{
"variables": {
"psvar": "My$tring"
},
...
"provisioners": [
{
"type": "powershell",
"elevated_user": "Administrator",
"elevated_password": "Super$3cr3t!",
"inline": "Write-Output \"The dollar in the elevated_password is interpreted correctly\""
},
{
"type": "powershell",
"environment_vars": [
"VAR1=A$Dollar",
"VAR2=A`Backtick",
"VAR3=A'SingleQuote",
"VAR4=A\"DoubleQuote",
"VAR5={{user `psvar`}}"
],
"inline": [
"Write-Output \"In the following examples the special character is interpreted correctly:\"",
"Write-Output \"The dollar in VAR1: $Env:VAR1\"",
"Write-Output \"The backtick in VAR2: $Env:VAR2\"",
"Write-Output \"The single quote in VAR3: $Env:VAR3\"",
"Write-Output \"The double quote in VAR4: $Env:VAR4\"",
"Write-Output \"The dollar in VAR5 (expanded from a user var): $Env:VAR5\""
]
}
]
...
}
上面的代码片段应该会在 Packer 控制台上产生以下输出:
==> amazon-ebs: Provisioning with Powershell...
==> amazon-ebs: Provisioning with PowerShell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner961728919
amazon-ebs: The dollar in the elevated_password is interpreted correctly
==> amazon-ebs: Provisioning with Powershell...
==> amazon-ebs: Provisioning with PowerShell script: /var/folders/15/d0f7gdg13rnd1cxp7tgmr55c0000gn/T/packer-powershell-provisioner142826554
amazon-ebs: In the following examples the special character is interpreted correctly:
amazon-ebs: The dollar in VAR1: A$Dollar
amazon-ebs: The backtick in VAR2: A`Backtick
amazon-ebs: The single quote in VAR3: A'SingleQuote
amazon-ebs: The double quote in VAR4: A"DoubleQuote
amazon-ebs: The dollar in VAR5 (expanded from a user var): My$tring