はじめに
AWS CLIを使ってEC2 Windows ServerのグローバルIPアドレスを取得し、
リモートデスクトップ接続(.rdpファイル)のプロパティを自動的に変更する処理を紹介します。
AWS EC2 の Windows Server を検証用に利用している場合、ElasticIP(固定IPアドレス)を利用せず、動的IPアドレスで必要な時にだけ起動して運用している方も多いかと思います。
しかし、動的IPアドレスで運用している場合は、クライアント側のリモートデスクトップ接続(RDP)ファイルの接続先も毎回変更しなければならず、不便に感じていたため、グローバルIPアドレスを取得してRDPファイルのプロパティを変更する処理をPowerShellで作成してみました。
GitHubにて、ソースコードも公開しています。
https://github.com/gx3n-inue/ec2_win_set_rdp
aws ec2コマンドでグローバルIPアドレスを取得する
AWS EC2のグローバルIPアドレスは、PowerShellからaws ec2 describe-instances
コマンドを実行して取得します。
aws ec2
の出力フォーマット[^1]には、json
, text
, table
の3種類がありますが、ここではtext
形式とjson
形式のそれぞれに対応したスクリプトを紹介します。
text形式の場合(aws ec2 describe-instances --query
で検索する)
aws ec2 describe-instances --query
コマンドの出力結果をtext
形式で取得し、InstanceIdが一致するレコードのPublicIpAddressフィールドの値を出力します。
param( $InstanceId )
if (-Not($InstanceId)) {
Write-Host "Usage : "$MyInvocation.MyCommand.Name" InstanceId" -ForegroundColor Red
exit
}
<#
aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId, PublicIpAddress]' --output text |
%{if ($_.split("`t")[0] -match $InstanceId) { $_.split("`t")[1]; } }
# >
$res = & "aws" ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId, PublicIpAddress]' --output text
foreach ($var in $res) {
if ($var.split("`t")[0] -match $InstanceId) {
return $var.split("`t")[1]
}
}
return "None"
json形式の場合
aws ec2 describe-instances
コマンドの出力結果は、起動中のインスタンスごとにブロックが分かれているので、インスタンス番号を探し、さらにそのブロック内にあるPublicIpAddressフィールドに格納されているIPアドレス文字列のみを返すようにしています。
param( $InstanceId )
if (-Not($InstanceId)) {
Write-Host "Usage : "$MyInvocation.MyCommand.Name"InstanceId rdp_filePath" -ForegroundColor Red
exit
}
Write-Host "<"$MyInvocation.MyCommand.Name">" -ForegroundColor Yellow
Write-Host "Searhing InstanceId = " -NoNewline
Write-Host $InstanceId -ForegroundColor Green
$res = & "aws" ec2 describe-instances --output json
$Check_MS_Windows = $FALSE
$Check_publicIp = $FALSE
for ($i = 0; $i -lt $res.Length; $i++) {
##--------------------------------------------------------------##
## PlatformがWindowsかどうかを判定する
##--------------------------------------------------------------##
if ($res[$i].IndexOf("`"Platform`": `"windows`"") -ge 0) {
$Check_MS_Windows = $TRUE
}
if ($Check_MS_Windows -eq $TRUE) {
##--------------------------------------------------------------##
## PublicIpAddressの値を取得する
##--------------------------------------------------------------##
if ($res[$i].IndexOf("`"PublicIpAddress`":") -ge 0) {
$workStr = $res[$i].Replace(" ","").Replace("`"","").Replace(",","").split(":")
if ($workStr.Length -gt 0) {
$publicIpStr = $workStr[1]
$Check_publicIp = $TRUE
}
}
##--------------------------------------------------------------##
## InstanceIdが見つかったらpublicIpを返す
##--------------------------------------------------------------##
if ($Check_publicIp -eq $TRUE) {
if ($res[$i].IndexOf("`"InstanceId`":") -ge 0) {
if ($res[$i].IndexOf("`"$InstanceId`"") -ge 0) {
Write-Host "publicIpAddress : " -NoNewline
Write-Host $publicIpStr -ForegroundColor Cyan
Write-Host
return $publicIpStr
}
else {
$Check_publicIp = $FALSE
}
}
}
}
}
# 見つからなかった場合はnullを返す
return "None"
全レコードから検索する処理を書いてしまったため、少し長くなってしまいましたが、
aws ec2 describe-instances --query 'Reservations[*].Instances[*].[InstanceId, PublicIpAddress]' --output json
の出力結果からInstanceIdを探し、その次のフィールドに出力されている値を取り出しても良いかもしれません。(その方が余計なトラフィックが流れない)
リモートデスクトップ接続の接続先プロパティに取得したIPアドレスをセットする
リモートデスクトップ接続の接続先プロパティに取得したIPアドレスをセットする処理を紹介します。RDPファイルをテキストエディタで開いてみると解りますが、接続先のホスト名またはIPアドレスは、"full address:s:"というフィールドの値として保存されていますので、その値の文字列(FQDNまたはIPアドレス)を取得したIPアドレスに書き換え、RDPファイルに書き戻します。念のため、現在のRDPファイルには上書きせず、最終更新日時を付加したファイル名にリネームして残すようにしています。
param( $rdp_filePath, $publicIp )
## --------------------------------------------------------##
## RDPファイルの読み込み
## --------------------------------------------------------##
function load_RDP_File_and_ipChange([string]$filePath)
{
$f = (Get-Content $filePath) -as [string[]]
$lines = @()
foreach ($currentLine in $f){
# 接続先IPアドレス情報の検索
if ($currentLine.IndexOf("full address:s:") -eq 0) {
$workStr = $currentLine.Split(":")
if ($workStr.Length -eq 3) {
$new_fullAddr = $workStr[0] + ":" + $workStr[1] + ":" + $publicIp
Write-Host "Current Value ... " -NoNewline
Write-Host $currentLine -ForegroundColor Cyan
Write-Host "New Value ... " -NoNewline
Write-Host $new_fullAddr -ForegroundColor Cyan
Write-Host
# キー入力を調べる
if ((Check_ReadKey $filePath) -eq $FALSE) {
# "n"が入力された場合は終了する
return $FALSE
}
$lines += $new_fullAddr
}
else {
Write-Host "full address get Error!"
return $FALSE
}
}
else {
$lines += $currentLine
}
}
return($lines)
}
## --------------------------------------------------------##
## キー入力チェック
## --------------------------------------------------------##
function Check_ReadKey([string]$filePath)
{
while ($TRUE) {
Write-Host "["$filePath"]" -NoNewline -ForegroundColor Yellow
Write-Host " Overwrite? y/n [y]:" -NoNewline
# キー入力の読み込み
$keyInfo = [Console]::ReadKey($TRUE)
Write-Host
if (($keyInfo.Key -eq "N") -Or ($keyInfo.Key -eq "n")) {
Write-Host "Canceled."
Write-Host
return $FALSE
}
elseif (($keyInfo.Key -eq "Y") -Or ($keyInfo.Key -eq "y")) {
Write-Host
return $TRUE
}
elseif ($keyInfo.Key -eq "Enter") {
Write-Host
return $TRUE
}
}
}
## --------------------------------------------------------##
## メイン
## --------------------------------------------------------##
Write-Host "<"$MyInvocation.MyCommand.Name">" -ForegroundColor Yellow
if (-Not($publicIp)) {
Write-Host "Usage : "$MyInvocation.MyCommand.Name"publicIp rdp_filePath" -ForegroundColor Red
exit
}
if (-Not($rdp_filePath)) {
Write-Host "Usage : "$MyInvocation.MyCommand.Name"publicIp rdp_filePath" -ForegroundColor Red
exit
}
# rdpファイルが存在しているかどうか調べる
if ((Test-Path($rdp_filePath)) -eq $FALSE) {
Write-Host "["$rdp_filePath"] is not found." -ForegroundColor Red
exit
}
$lines = @()
# RDPファイルを読み込む
$lines = load_RDP_File_and_ipChange $rdp_filePath
if ($lines -eq $FALSE) {
return $FALSE
}
# 現在の日付時刻を取得する
$timestamp = $(Get-ItemProperty $rdp_filePath).LastWriteTime.ToString('_yyyyMMdd_HHmmss')
# 現在のファイルをリネームしておく
$oldFileName = $rdp_filePath.Replace(".rdp", $timestamp + ".rdp")
Move-Item $rdp_filePath $oldFileName
Write-Host "["$rdp_filePath"]" -NoNewline -ForegroundColor Yellow
Write-Host " Rename to "
Write-Host "["$oldFileName"]" -ForegroundColor Yellow
Write-Host
# RDPファイルに書き込む
Set-Content -Path $rdp_filePath -Value $lines -Encoding Unicode
# 書き込み終了メッセージ
Write-Host "["$rdp_filePath"]" -NoNewline -ForegroundColor Yellow
Write-Host " was saved."
Write-Host
return $TRUE
メインプログラム
次に、メインプログラムです。さきほどのget_publicIP.ps1(グローバルIPアドレスを取得するスクリプト)を実行してグローバルIPアドレスを取得後、overwrite_rdp.ps1(RDPファイルのプロパティを変更するスクリプト)でRDPファイルを更新します。更新後は、リモートデスクトップ接続を起動させています。
param( $id, $rdp_filePath )
## --------------------------------------------------------##
## メイン
## --------------------------------------------------------##
if (-Not($id)) {
$id = "ここにインスタンスIDをセットしてください"
}
if (-Not($rdp_filePath)) {
$rdp_filePath = "ここにRDPファイルのパスをセットしてください"
}
if ($rdp_filePath.Substring(0,1) -ne ".") {
$rdp_filePath = ".\" + $rdp_filePath
}
Write-Host "<"$MyInvocation.MyCommand.Name">" -ForegroundColor Yellow
# 指定した[InstanceId]の[PublicIpAddress]を取得
# $publicIp = &".\get_Win_PublicIpAddress_by_text.ps1" $id # text形式での検索
$publicIp = &".\get_Win_PublicIpAddress_by_json.ps1" $id # json形式での検索
if ($publicIp -eq "None") {
Write-Host "publicIp is Nothing."
exit
}
# 指定したrdpファイルの接続先IPアドレスを上書きする
$result = .\overwrite_rdp.ps1 $rdp_filePath $publicIp
if ($result -eq $TRUE) {
Write-Host "Start " -NoNewline
Write-Host "["$rdp_filePath"]" -ForegroundColor Yellow
# リモートデスクトップ接続を起動する
&$rdp_filePath
}
実行方法
実行方法は以下のとおりです。
PS > .\ec2_win_set_rdp.ps1 <InstancdId> <RDP filePath>
インスタンス番号およびRDPファイルのパスは、ec2_win_set_rdp.ps1(メイン処理)の
$id = "ここにインスタンスIDをセットしてください"
$rdp_filePath = "ここにRDPファイルのパスをセットしてください"
```
の箇所に直接記述することもできます。
# 実行例
```
PS D:\ec2_win_set_rdp> .\ec2_win_set_rdp.ps1 i-xxxxxxxxxxxxxxxxx .\sample.rdp
< ec2_win_set_rdp.ps1 >
< get_publicIP.ps1 >
Searhing InstanceId = i-xxxxxxxxxxxxxxxxx
publicIpAddress : xx.xxx.xxx.xx
< overwrite_rdp.ps1 >
Current Value ... full address:s:xx.xxx.xxx.xx
New Value ... full address:s:xx.xxx.xxx.xx
[ .\sample.rdp] Overwrite? y/n [y]:
[ .\sample.rdp] Rename to
[ .\sample_20180806_233719.rdp]
[ .\sample.rdp] was saved.
Start [ .\sample.rdp]
PS D:\ec2_win_set_rdp>
```
[^1]: Default output formatは json、text、table の3種類があり、設定内容は`C:\Users\USERNAME \.aws\config`に格納されています。デフォルトは json です。`aws configure`コマンドで確認および変更できます。