はじめに
複数のEC2インスタンスに対して一括でコマンド実行する方法を調べた際の手順を備忘として記載する。
方法
Systems ManagerのRunCommandを使用する。
Windowsの場合:AWS-RunPowerShellScript
Linuxの場合:AWS-RunShellScript
前提条件
- インスタンスでアウトバウンドのインターネットアクセスを許可します。この場合、インスタンスは、以下のエンドポイントへのHTTPS(ポート 443)アウトバウンドトラフィックも許可する必要があります。
- ssm.region.amazonaws.com
- ssmmessages.region.amazonaws.com
- ec2messages.region.amazonaws.com
- 対象EC2でSSM Agentがインストールされていること(Windows Server 2022やAmazon Linux 2023ではデフォルトでインストールされています。)
- 対象EC2でSystemsManagerがアクションを実行できるようにアクセスを許可します。
- AmazonSSMManagedInstanceCore ポリシー
検証
今回はAWS-RunPowerShellScriptを試してみます。
複数台のインスタンスのホスト名などを一括で変更する。
AWS-RunPowerShellScriptを選択後、以下のコマンドを「コマンドのパラメータ」に貼り付けます。
コマンドを実行したいインスタンスを選択し、「実行」をクリックします。
コマンドの出力結果をS3に保存することも可能なようです。
今回は複数台のEC2(Windows Server 2022)に対してホスト名や言語設定等を変更するコマンドを実行してみます。
メタデータを取得し、Nameタグの値から一部変更した値をホスト名にするように設定します。
※Windowsの場合、ホスト名は15文字制限があるため15文字以内に収まるように変更しています。
function Get-EC2MetadataWithToken {
param (
[string]$Path
)
try {
# トークンを取得(TTL: 21600秒 = 6時間)
$tokenParams = @{
Uri = "http://169.254.169.254/latest/api/token"
Method = "PUT"
Headers = @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"}
TimeoutSec = 5
ErrorAction = "Stop"
}
$token = Invoke-RestMethod @tokenParams
# トークンを使ってメタデータを取得
$metadataParams = @{
Uri = "http://169.254.169.254/latest/meta-data/$Path"
Headers = @{"X-aws-ec2-metadata-token" = $token}
TimeoutSec = 5
ErrorAction = "Stop"
}
$metadata = Invoke-RestMethod @metadataParams
return $metadata
}
catch {
Write-Host " - [警告] メタデータ取得失敗: $_"
return $null
}
}
$instanceId = Get-EC2MetadataWithToken -Path "instance-id"
if ($instanceId) {
Write-Host " - インスタンスID: $instanceId"
Write-Host " - 対象サーバ: " -NoNewline
$nameTag = (aws ec2 describe-tags --filters "Name=resource-id,Values=$instanceId" "Name=key,Values=Name" --query "Tags[0].Value" --output text)
Write-Host "$nameTag"
if ($nameTag -and $nameTag -match "test-windows-ec2-(.+)") {
$suffix = $matches[1]
$hostname = "test-ec2-$suffix"
Write-Host " - 検出されたNameタグ: $nameTag"
Write-Host " - 設定するホスト名: $hostname"
}
} else {
$hostname = "test-ec2-XX"
Write-Host " - 取得したNameタグがパターンに該当しませんでした。 $hostname"
}
Rename-Computer -NewName $hostname -Force
Set-WinSystemLocale -SystemLocale ja-JP
Set-WinUserLanguageList -LanguageList ja-JP -Force
Set-WinHomeLocation -GeoId 0x7A
Set-TimeZone -Id "Tokyo Standard Time"
Start-Sleep -Seconds 3
Restart-Computer -Force
コマンド実行が成功したようなので、S3上に保存されている出力結果も確認してみます。
stdoutを選択して「開く」をクリックして出力内容を確認してみます。
~出力結果~
- インスタンスID: i-0bfa72a4291ff4873
- 対象サーバ: test-windows-ec2-01
- 検出されたNameタグ: test-windows-ec2-01
- 設定するホスト名: test-ec2-01
警告: 変更は、コンピューター EC2AMAZ-U3T6GVG の再起動後に有効になります。
設定はうまくできていそうです。
Nameタグの値が「test-ec2」のものについては「取得したNameタグがパターンに該当しませんでした」と表示される想定でしたが、別のエラーが発生しているようでした。
こちらの原因についてはまた別機会に調査しようと思います。
Rename-Computer : パラメーター 'NewName の引数を確認できません。引数が null または空です。null または空でない引数を指定
して、コマンドを再度実行してください。
発生場所 C:\ProgramData\Amazon\SSM\InstanceData\i-0cdbdbc0b76b9994a\document\orchestration\dac02a4b-36d5-41e5-8fe7-60cf
6e7e4e0e\awsrunPowerShellScript\0.awsrunPowerShellScript\_script.ps1:55 文字:26
+ Rename-Computer -NewName $hostname -Force
+ ~~~~~~~~~
+ CategoryInfo : InvalidData: (:) [Rename-Computer]、ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,Microsoft.PowerShell.Commands.RenameComputerCommand
コマンド実行結果確認
設定コマンド実行時と同様にAWS-RunPowerShellScriptを選択後、以下のコマンドを「コマンドのパラメータ」に貼り付けます。
コマンドを実行したいインスタンスを選択し、「実行」をクリックします
複数台のインスタンスに対して実行するため、メタデータを取得して出力結果確認時にインスタンスIDとNameタグの値がわかるようにします。
# トークン取得
$token = Invoke-RestMethod `
-Headers @{"X-aws-ec2-metadata-token-ttl-seconds" = "21600"} `
-Method PUT `
-Uri http://169.254.169.254/latest/api/token
# インスタンスID
$instanceId = Invoke-RestMethod `
-Headers @{"X-aws-ec2-metadata-token" = $token} `
-Uri http://169.254.169.254/latest/meta-data/instance-id
# リージョン取得
$doc = Invoke-RestMethod `
-Headers @{"X-aws-ec2-metadata-token" = $token} `
-Uri http://169.254.169.254/latest/dynamic/instance-identity/document
$region = $doc.region
# Nameタグ取得
$nameTag = (aws ec2 describe-tags `
--filters "Name=resource-id,Values=$instanceId" "Name=key,Values=Name" `
--region $region `
--query "Tags[0].Value" `
--output text)
# 先頭行に出力
Write-Host "=========================================="
Write-Host "NameTag: $nameTag"
Write-Host "InstanceId: $instanceId"
Write-Host "=========================================="
# 1. ホスト名
Write-Host "=== ホスト名 ==="
hostname
Write-Host ""
# 2. タイムゾーン
Write-Host "=== タイムゾーン ==="
Get-TimeZone
Write-Host ""
# 3. 地域と言語(国または地域、言語)
Write-Host "=== 地域と言語 ==="
Get-Culture | Select-Object Name, DisplayName, LCID
Get-WinSystemLocale | Select-Object Name, DisplayName
Write-Host ""
コマンド実行が完了したためS3に保存されている出力結果を確認してみます。
~出力結果確認~
==========================================
NameTag: test-windows-ec2-01
InstanceId: i-0bfa72a4291ff4873
==========================================
=== ホスト名 ===
test-ec2-01
=== タイムゾーン ===
Id : Tokyo Standard Time
DisplayName : (UTC+09:00) 大阪、札幌、東京
StandardName : 東京 (標準時)
DaylightName : 東京 (夏時間)
BaseUtcOffset : 09:00:00
SupportsDaylightSavingTime : False
=== 地域と言語 ===
Name : ja-JP
DisplayName : 日本語 (日本)
LCID : 1041
Name : ja-JP
DisplayName : 日本語 (日本)
ホスト名変更や言語設定等ができていることを確認しました。
おわりに
SSM RunCommandを使用することで複数台のサーバに対して一括でコマンド実行ができ、作業の効率化が図れそうだと思いました。
今回は「AWS-RunPowerShellScript」のみを取り扱いましたが、SSM RunCommandには他にもコマンドドキュメントが存在するため、他のコマンドドキュメントではどういったことができるのかをいずれ検証したいと思います。






