启动时在 Windows 实例上运行命令
当您使用 Amazon EC2 启动 Windows 实例时,可以将用户数据传递到可用于执行自动配置任务或在实例启动后运行脚本的实例。实例用户数据被视为不透明数据;需要由实例来解释。在 Windows Server 2022 上,用户数据由 EC2Launch v2 处理;在 Windows Server 2016 及 2019 上,用户数据由 EC2Launch 处理;在 Windows Server 2012 R2 及更早版本上,用户数据由 EC2Config 处理。
有关 UserData
模板中 AWS CloudFormation 属性的程序集示例,请参阅 Base64 编码 UserData 属性和带 AccessKey 和 SecretKey 的 Base64 编码 UserData 属性。
有关启动时在 Linux 实例上运行命令的信息,请参阅 Amazon EC2 用户指南(适用于 Linux 实例) 中的启动时在 Linux 实例上运行命令。
有关在使用生命周期挂钩的 Auto Scaling 中的实例上运行命令的示例,请参阅《Amazon EC2 Auto Scaling 用户指南》中的教程:配置用户数据以通过实例元数据检索目标生命周期状态。
用户数据脚本
要让 EC2Config 或 EC2Launch 运行脚本,在将脚本添加到用户数据中时,您必须将脚本封装在特殊标签中。您使用的标签取决于命令是在命令提示符窗口(批处理命令)中还是使用 Windows PowerShell 运行。
如果同时指定批处理脚本和 Windows PowerShell 脚本,则批处理脚本先运行,然后运行 Windows PowerShell 脚本,不论这些脚本在实例用户数据中的显示顺序如何。
如果您在用户数据脚本中使用 AWS API(包括 AWS CLI),则在启动实例时必须使用实例配置文件。实例配置文件提供用户数据脚本执行 API 调用所需的适当 AWS 凭证。有关更多信息,请参阅实例配置文件。您分配给 IAM 角色的权限取决于您使用 API 调用的服务。有关更多信息,请参阅 Amazon EC2 的 IAM 角色。
批处理脚本的语法
使用 script
标签指定批处理脚本。使用换行符分隔命令,如以下示例所示。
<script> echo Current date and time >> %SystemRoot%\Temp\test.log echo %DATE% %TIME% >> %SystemRoot%\Temp\test.log </script>
默认情况下,用户数据脚本在您启动实例时运行一次。要在每次重新引导或启动实例时运行用户数据脚本,请将 <persist>true</persist>
添加到用户数据。
<script> echo Current date and time >> %SystemRoot%\Temp\test.log echo %DATE% %TIME% >> %SystemRoot%\Temp\test.log </script> <persist>true</persist>
EC2Launch v2 代理
要在 EC2Launch v2 executeScript 任务处于 UserData
阶段时将 XML 用户数据脚本作为分离的进程运行,请在您的用户数据中添加以下标签。
<detach>true</detach>
注意
以前的启动代理不支持分离标签。
<script> echo Current date and time >> %SystemRoot%\Temp\test.log echo %DATE% %TIME% >> %SystemRoot%\Temp\test.log </script> <detach>true</detach>
Windows PowerShell 脚本的语法
AWS Windows AMI 包括 AWS Tools for Windows PowerShell
使用 <powershell>
标签指定 Windows PowerShell 脚本。使用换行符分隔命令。<powershell>
标签区分大小写。
例如:
<powershell> $file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm") New-Item $file -ItemType file </powershell>
默认情况下,用户数据脚本在您启动实例时运行一次。要在每次重新引导或启动实例时运行用户数据脚本,请将 <persist>true</persist>
添加到用户数据。
<powershell> $file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm") New-Item $file -ItemType file </powershell> <persist>true</persist>
EC2Launch v2 代理
要在 EC2Launch v2 executeScript 任务处于 UserData
阶段时将 XML 用户数据脚本作为分离的进程运行,请在您的用户数据中添加以下标签。
<detach>true</detach>
注意
以前的启动代理不支持分离标签。
<powershell> $file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm") New-Item $file -ItemType file </powershell> <detach>true</detach>
YAML 配置脚本的语法
如果使用 EC2Launch v2 运行脚本,则可以使用 YAML 格式。要查看 EC2Launch v2 的配置任务、详细信息和示例,请参阅 EC2Launch v2 任务配置。
使用 executeScript
任务指定 YAML 脚本。
运行 PowerShell 脚本的 YAML 语法示例
version: 1.0 tasks: - task: executeScript inputs: - frequency: always type: powershell runAs: localSystem content: |- $file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm") New-Item $file -ItemType file
运行批处理脚本的 YAML 语法示例
version: 1.1 tasks: - task: executeScript inputs: - frequency: always type: batch runAs: localSystem content: |- echo Current date and time >> %SystemRoot%\Temp\test.log echo %DATE% %TIME% >> %SystemRoot%\Temp\test.log
Base64 编码
如果使用的是 Amazon EC2 API 或不对用户数据执行 base64 编码的工具,则您必须自行对用户数据进行编码。否则,系统会记录找不到要运行的 script
或 powershell
标签的错误。下面是使用 Windows PowerShell 进行编码的示例。
$UserData = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($Script))
下面是一个使用 PowerShell 进行解码的示例。
$Script = [System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($UserData))
有关 base64 编码的更多信息,请参阅 https://www.ietf.org/rfc/rfc4648.txt
用户数据执行
默认情况下,所有 AWS Windows AMI 均已为初次启动启用了用户数据执行。您可以指定用户数据脚本在下次实例重新引导或重启时运行。此外,您可以指定用户数据脚本在每次实例重新引导或重启时运行。
注意
默认情况下不会使用户数据在首次启动后运行。要使用户数据在实例重启或启动时运行,请参阅后续重新引导或启动。
生成随机密码之后,从本地管理员账户运行用户数据脚本。否则,从系统账户运行用户数据脚本。
实例启动
实例用户数据中的脚本在实例的初次启动期间运行。如果找到 persist
标签,则为后续重新引导或启动启用用户数据执行。EC2Launch v2、EC2Launch 和 EC2Config 的日志文件包含源自标准输出和标准错误流的输出。
EC2Launch v2
EC2Launch v2 的日志文件为 C:\ProgramData\Amazon\EC2Launch\log\agent.log
。
注意
C:\ProgramData
文件夹可能已隐藏。要查看该文件夹,您必须显示隐藏的文件和文件夹。
执行用户数据时将记录以下信息:
-
Info: Converting user-data to yaml format
– 如果用户数据是以 XML 格式提供的 -
Info: Initializing user-data state
– 用户数据执行开始 -
Info: Frequency is: always
– 如果每次启动时都运行用户数据任务 -
Info: Frequency is: once
– 如果用户数据任务只运行一次 -
Stage: postReadyUserData execution completed
– 用户数据执行结束
EC2Launch
EC2Launch 的日志文件为 C:\ProgramData\Amazon\EC2-Windows\Launch\Log\UserdataExecution.log
。
C:\ProgramData
文件夹可能已隐藏。要查看该文件夹,您必须显示隐藏的文件和文件夹。
执行用户数据时将记录以下信息:
-
Userdata execution begins
– 用户数据执行开始 -
<persist> tag was provided: true
– 找到持久标签时 -
Running userdata on every boot
– 找到持久标签时 -
<powershell> tag was provided.. running powershell content
– 如果找到 PowerShell 标签 -
<script> tag was provided.. running script content
– 如果找到脚本标签 -
Message: The output from user scripts
– 如果运行用户数据脚本,则会记录其输出
EC2Config
EC2Config 的日志文件为 C:\Program
Files\Amazon\Ec2ConfigService\Logs\Ec2Config.log
。执行用户数据时将记录以下信息:
-
Ec2HandleUserData: Message: Start running user scripts
– 用户数据执行开始 -
Ec2HandleUserData: Message: Re-enabled userdata execution
– 找到持久标签时 -
Ec2HandleUserData: Message: Could not find <persist> and </persist>
– 如果未找到持久标签 -
Ec2HandleUserData: Message: The output from user scripts
– 如果运行用户数据脚本,则会记录其输出
后续重新引导或启动
在您更新实例用户数据后,重新引导或启动实例时不会自动运行用户数据脚本。不过,您可以启用用户数据执行,这样用户数据脚本在您重新引导或启动实例时运行一次,或者在每次重新引导或启动实例时执行。
如果您选择使用 Sysprep 关闭选项,则用户数据脚本将在下一次实例启动或重新引导时运行,即使您没有为后续的重新引导或启动启用用户数据执行,也是如此。在后续重新引导或启动时,将不执行用户数据脚本。
使用 EC2Launch v2(预览 AMI)支持用户数据执行
-
要在首次启动时对用户数据运行任务,请将
frequency
设置为once
。 -
要在每次启动时都对用户数据运行任务,请将
frequency
设置为always
。
使用 EC2Launch(Windows Server 2016 或更高版本)支持用户数据执行
-
连接到您的 Windows 实例。
-
打开 PowerShell 命令窗口,并运行以下命令:
C:\ProgramData\Amazon\EC2-Windows\Launch\Scripts\InitializeInstance.ps1 –Schedule
-
从 Windows 实例断开连接。要在下次实例启动时运行更新后的脚本,请停止实例并更新用户数据。有关更多信息,请参阅查看和更新实例用户数据。
使用 EC2Config(Windows Server 2012 R2 及更低版本)支持用户数据执行
-
连接到您的 Windows 实例。
-
打开
C:\Program Files\Amazon\Ec2ConfigService\Ec2ConfigServiceSetting.exe
。 -
对于用户数据,选择 Enable UserData execution for next service start (为下次服务启动启用用户数据执行)。
-
从 Windows 实例断开连接。要在下次实例启动时运行更新后的脚本,请停止实例并更新用户数据。有关更多信息,请参阅查看和更新实例用户数据。
用户数据和控制台
您可在启动实例时指定实例用户数据。如果实例的根卷是 EBS 卷,您还可以停止实例并更新其用户数据。
启动时指定实例用户数据
按照启动实例的程序进行操作。User data(用户数据)字段位于启动实例向导的 高级详细信息 部分。在用户数据字段中输入您的 PowerShell 脚本,然后完成实例启动程序。
在用户数据字段的屏幕截图中,示例脚本在 Windows 临时文件夹中创建文件,在文件名中使用当前日期和时间。当您包括 <persist>true</persist>
时,每次重新引导或启动实例时将运行脚本。如果将用户数据已执行 base64 编码复选框保留为空,Amazon EC2 控制台将执行 base64 编码。

查看和更新实例用户数据
您可以查看任何实例的实例用户数据,也可以更新已停止实例的实例用户数据。
使用控制台更新实例的用户数据
-
通过以下网址打开 Amazon EC2 控制台:https://console.aws.amazon.com/ec2/
。 -
在导航窗格中,选择实例。
-
选择所需实例,然后依次选择操作、实例状态、停止实例。
警告
当您停止某个实例时,任何实例存储卷上的数据都将被擦除。要保留实例存储卷中的数据,请确保将其备份到持久性存储中。
-
当系统提示您确认时,选择 Stop。停止实例可能需要几分钟时间。
-
在实例仍被选中的情况下,依次选择操作、实例设置和编辑用户数据。如果实例正在运行,您不能更改用户数据,但是可以查看。
-
在 Edit user data (编辑用户数据) 对话框中,更新用户数据,然后选择 Save (保存)。要在每次重新引导或启动实例时运行用户数据脚本,请添加
<persist>true</persist>
,如下例中所示。 -
启动实例。如果为后续重新引导或启动启用了用户数据运行,则在实例启动过程中执行更新后的用户数据脚本。
用户数据和 Tools for Windows PowerShell
您可以使用 Tools for Windows PowerShell 指定、修改和查看实例的用户数据。有关使用实例元数据从实例查看用户数据的信息,请参阅检索实例用户数据。有关用户数据和 AWS CLI 的信息,请参阅 Amazon EC2 用户指南(适用于 Linux 实例)中的用户数据和 AWS CLI。
示例:启动时指定实例用户数据
使用实例用户数据创建一个文本文件。要在每次重新引导或启动实例时运行用户数据脚本,请添加 <persist>true</persist>
,如下例中所示。
<powershell> $file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm") New-Item $file -ItemType file </powershell> <persist>true</persist>
要在启动实例时指定实例用户数据,请使用 New-EC2Instance 命令。该命令不会对用户数据进行 base64 编码。使用以下命令在名为 script.txt
的文本文件中对用户数据进行编码。
PS C:\>
$Script = Get-Content -Raw
script.txt
PS C:\>
$UserData = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($Script))
使用 -UserData
参数可将用户数据传递到 New-EC2Instance 命令。
PS C:\>
New-EC2Instance -ImageId
ami-abcd1234
-MinCount1
-MaxCount1
-InstanceTypem3.medium
\ -KeyNamemy-key-pair
-SubnetIdsubnet-12345678
-SecurityGroupIdssg-1a2b3c4d
\ -UserData $UserData
示例:更新已停止实例的实例用户数据
您可以使用 Edit-EC2InstanceAttribute 命令修改已停止的实例的用户数据。
使用新脚本创建一个文本文件。使用以下命令在名为 new-script.txt
的文本文件中对用户数据进行编码。
PS C:\>
$NewScript = Get-Content -Raw
new-script.txt
PS C:\>
$NewUserData = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($NewScript))
使用 -UserData
和 -Value
参数可指定用户数据。
PS C:\>
Edit-EC2InstanceAttribute -InstanceId
i-1234567890abcdef0
-Attribute userData -Value $NewUserData
示例:查看实例用户数据
要检索实例的用户数据,请使用 Get-EC2InstanceAttribute 命令。
PS C:\>
(Get-EC2InstanceAttribute -InstanceId
i-1234567890abcdef0
-Attribute userData).UserData
下面是示例输出。请注意,用户数据已编码。
PHBvd2Vyc2hlbGw+DQpSZW5hbWUtQ29tcHV0ZXIgLU5ld05hbWUgdXNlci1kYXRhLXRlc3QNCjwvcG93ZXJzaGVsbD4=
使用以下命令可将已编码的用户数据存储在变量中,然后对其进行编码。
PS C:\>
$UserData_encoded = (Get-EC2InstanceAttribute -InstanceId
i-1234567890abcdef0
-Attribute userData).UserDataPS C:\>
[System.Text.Encoding]::UTF8.GetString([System.Convert]::FromBase64String($UserData_encoded))
下面是示例输出。
<powershell>
$file = $env:SystemRoot + "\Temp\" + (Get-Date).ToString("MM-dd-yy-hh-mm")
New-Item $file -ItemType file
</powershell>
<persist>true</persist>
示例:重命名实例以匹配标签值
要读取标签值、在首次启动时重命名实例以匹配标签值并重新启动,您可以使用 Get-EC2Tag 命令。要成功运行此命令,您必须将具有 ec2:DescribeTags
权限的角色附加到实例上,因为标签信息通过 API 调用检索。有关使用 IAM 角色的设置权限的更多信息,请参阅将 IAM 角色附加到实例。
注意
此脚本在 Windows Server 2008 之前的版本上将失败。
<powershell>
$instanceId = (invoke-webrequest http://169.254.169.254/latest/meta-data/instance-id -UseBasicParsing).content
$nameValue = (get-ec2tag -filter @{Name="resource-id";Value=$instanceid},@{Name="key";Value="Name"}).Value
$pattern = "^(?![0-9]{1,15}$)[a-zA-Z0-9-]{1,15}$"
#Verify Name Value satisfies best practices for Windows hostnames
If ($nameValue -match $pattern)
{Try
{Rename-Computer -NewName $nameValue -Restart -ErrorAction Stop}
Catch
{$ErrorMessage = $_.Exception.Message
Write-Output "Rename failed: $ErrorMessage"}}
Else
{Throw "Provided name not a valid hostname. Please ensure Name value is between 1 and 15 characters in length and contains only alphanumeric or hyphen characters"}
</powershell>
您还可以使用实例元数据中的标签对实例进行重命名,前提是您的实例配置为从实例元数据访问标签。
注意
此脚本在 Windows Server 2008 之前的版本上将失败。
<powershell>
$nameValue = Get-EC2InstanceMetadata -Path /tags/instance/Name
$pattern = "^(?![0-9]{1,15}$)[a-zA-Z0-9-]{1,15}$"
#Verify Name Value satisfies best practices for Windows hostnames
If ($nameValue -match $pattern)
{Try
{Rename-Computer -NewName $nameValue -Restart -ErrorAction Stop}
Catch
{$ErrorMessage = $_.Exception.Message
Write-Output "Rename failed: $ErrorMessage"}}
Else
{Throw "Provided name not a valid hostname. Please ensure Name value is between 1 and 15 characters in length and contains only alphanumeric or hyphen characters"}
</powershell>