AWSエンジニアのためのはじめてのPowerShell

2013.12.21

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

こんにちは植木和樹です。ここ最近AWSのお仕事でWindowsを使った案件が多くなってきました。これまでオンプレミスで運用していたWindowsシステムのAWSへのリプレースが加速している・・・ということでしょうか?

EC2でWindowsを動かすにあたり、AWSが提供する各種APIを用いたスクリプト類を使いたい場合があります。選択肢としては「AWS CLI for Windowsをインストールする」「AWS SDK for .NETでプログラムを作成する」などが考えられますが、今回はもっとWindowsっぽく かつ お手軽に使いたいということで「AWS Tools for Windows PowerShell」を使用してみたいと思います。

筆者はPowerShellを扱うのが今回初めてだったため、分からない用語や使い方を調べたり、ハマッて悩んだ点が多々ありました。今回はPowerShellを使ってみたいと考えておられるAWSエンジニアの方の参考になればと思い、個人的な備忘録をまとめて公開してみたいと思います。

AWS Tools for PowerShellのインストール

インストール自体はMSI形式のインストーラーをダウンロードしてきて実行するだけなので割愛します。以下のサイトを参考にしながら進めてください。

Setting up the AWS Tools for Windows PowerShell
http://docs.aws.amazon.com/powershell/latest/userguide/pstools-getting-set-up.html
AWS Tools for Windows PowerShellのダウンロード
http://aws.amazon.com/jp/powershell/

PowerShellとAWS Toolsのバージョンについて

PowerShellにはバージョン1〜3まで大きく3種類が存在します。Windowsのバージョンによってデフォルトでインストールされているバージョンが異なります。

Windows PowerShell - Wikipedia

今回PowerShellを学ぶにあたりWindows7で作業していた関係上PowerShellのバージョンを2.0で進めていたので、今回掲載するコードは2.0ベースになっています。しかし、改善されたフィルターの初期化コードやWebリクエスト用コマンドレット(Invoke-WebRequest)を利用できることから、バージョンは3.0以上にあげた方が良いでしょう。これらについては後述します。なおWindows Server 2008用AMI(Tokyo: ami-ab4a2daa)でのPowerShellはバージョン3.0が使えるようになっています。

2013/12/22 追記
Windows7 や Windows Server 2008へのPowerShell 3.0インストーラーは下記サイトからダウンロードできます。ServicePackの適用有無と32bit/64bitで計4種類のパッケージが提供されていますので、お使いのOSに適したファイルをダウンロードしてください。(Windows7 SP1 64bit の場合は「Windows6.1-KB2506143-x64.msu」になります)。またインストールには「Microsfot .Net Framework 4.0」以上が必要になりますので、事前にWindows Updateからインストールしておいてください。

Download Windows Management Framework 3.0 from Official Microsoft Download Center

PowerShellのバージョンとは別にAWS Tools for PowerShellにもバージョンがあります。2013年11月時点で起動したWindows Server 2008(ami-e3dd41e2)ではAWS Toolsのバージョンが「1.1」でしたが、2013年12月21日現在公開されているAMIでは2.0.2になっています。AWS Toolsのバージョンが新しいと、KinesisやCloudTrailなど新たに追加されたAWSのサービスに対応していたり、既存のサービスへも操作できるコマンドが追加されていたりします。新しいサービスや機能を使いたいので2.0以上のバージョンをインストールしておくのが良いでしょう。

AWS Tools for Windows PowerShell Release Notes : Amazon Web Services

PowerShellのバージョン確認方法

以降の作業はWindows7で行っています。冒頭にお断りさせていただいた通りPowerShellはバージョン2.0で進めています。

PS > $PSVersionTable

Name                           Value
----                           -----
CLRVersion                     2.0.50727.5472
BuildVersion                   6.1.7601.17514
PSVersion                      2.0
WSManStackVersion              2.0
PSCompatibleVersions           {1.0, 2.0}
SerializationVersion           1.1.0.1
PSRemotingProtocolVersion      2.1

PowerShell ISEを使う際のAWSモジュールインポート方法

PowerShellのコード記述はインストール時に同梱されているWindows PowerShell ISE(Integrated Scripting Environment)という環境で行います。ISEを起動した直後は、まだAWS Toolsのコマンドレットは使えません。AWS Toolsが提供するコマンドレットをPowerShellから使用するためにはモジュールをインポートする必要があります。

PS > import-module "C:\Program Files (x86)\AWS Tools\PowerShell\AWSPowerShell\AWSPowerShell.psd1"

PS > Get-Module

ModuleType Name                      ExportedCommands                                                           
---------- ----                      ----------------                                                           
Binary     AWSPowerShell             {Enable-IAMMFADevice, Get-EC2VpnConnection, Copy-EC2Image, Get-S3BucketV...

AWS Tools for PowerShellのバージョン確認方法

AWSモジュールをインポートしたらバージョンを確認してみましょう。以下では2.0.2を使用していることが分かります。(注:2013/12/20 に2.0.4がリリースされています)

PS > Get-AWSPowerShellVersion

AWS Tools for Windows PowerShell
Version 2.0.2.2
Copyright 2012-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.

Amazon Web Services SDK for .NET
Version 2.0.2.3
Copyright 2009-2013 Amazon.com, Inc. or its affiliates. All Rights Reserved.

AWS Toolsを使って各種コマンドレットを実行する前に、Initialize-AWSDefaultsコマンドレットを使って、アクセスキーやデフォルトリージョンを設定する必要があります。こちらについては「Specifying AWS Credentials - AWS Tools for Windows PowerShell」を参考に設定してください。

AMIをバックアップするPowerShell

まずはPowerShellでなにかしらコードを書いてみよう、ということでEC2インスタンスのAMIを取得するスクリプトを作成しました。デフォルトリージョンにあるすべてのEC2インスタンスのAMIを取得し、AMIにいくつのタグを設定しています。その後取得してから7日経過したAMIを削除しています。

PowerShellのコードはShellとPerlとVBAが一緒くたに混在したような印象です。

$purgeAllowTag = New-Object Amazon.EC2.Model.Tag
$purgeAllowTag.Key = "PurgeAllow"
$purgeAllowTag.Value = "true"

$purgeAfterTag = New-Object Amazon.EC2.Model.Tag
$purgeAfterTag.Key = "PurgeAfter"
$purgeAfterTag.Value = (Get-Date).AddDays(+7).ToString(“yyyy-MM-dd”)

Get-EC2Instance | ForEach-Object {
  $_.Instances | ForEach-Object {
    New-EC2Image -Instance $_.InstanceId -Name "AutoBackup_$($_.InstanceId)_$(Get-Date -Format "yyyy-MM-dd")"  -Description "ec2ab_$($_.InstanceId)_$(Get-Date -Format "yyyy-MM-dd")"
    $response = $AWSHistory.LastServiceResponse
    New-EC2Tag -Resources $response.ImageId -Tags $purgeAllowTag,$purgeAfterTag
  }
}

$typeFilter = New-Object Amazon.EC2.Model.Filter
$typeFilter.Name = "resource-type"
$typeFilter.Values.Add("image")

$purgeAllowKeyFilter = New-Object Amazon.EC2.Model.Filter
$purgeAllowKeyFilter.Name = “key"
$purgeAllowKeyFilter.Values.Add("PurgeAllow")

$purgeAllowValueFilter = New-Object Amazon.EC2.Model.Filter
$purgeAllowValueFilter.Name = “value"
$purgeAllowValueFilter.Values.Add("true")

$purgeAfterKeyFilter = New-Object Amazon.EC2.Model.Filter
$purgeAfterKeyFilter.Name = “key"
$purgeAfterKeyFilter.Values.Add("PurgeAfter")

$images = Get-EC2Tag -Filters $typeFilter,$purgeAllowKeyFilter,$purgeAllowValueFilter
foreach($image in $images) {
  $imageId = $image | Select-Object -ExpandProperty ResourceId
  Echo $imageId
  $resourceIdFilter = New-Object Amazon.EC2.Model.Filter
  $resourceIdFilter.Name = "resource-id"
  $resourceIdFilter.Values.Add($image.ResourceId)

  $purgeAfter = Get-EC2Tag -Filters $typeFilter,$purgeAfterKeyFilter,$resourceIdFilter | Select-Object -ExpandProperty Value
  $purgeAfterEpoch = Get-Date -Date $purgeAfter -UFormat "%s"
  $currentEpoch = (Get-Date -UFormat "%s")
  If ($purgeAfterEpoch -lt $currentEpoch) {
    Unregister-EC2Image -ImageId $imageId
    Echo "AMI was purged [$imageId]"
  }
}

PowerShellでの躓きポイント

コマンドレットの探し方

AWS Toolsでは多くのコマンドレットが提供されています。GET-XXXX や NEW-XXXX など命名ルールがあるようなのでTABキーによるコマンド補完を使えばなんとなくは探せるのですが、行いたい処理がどのコマンドレット名で提供されているのか分からないこともしばしばです。そんな時Get-Commandでコマンドレット一覧を表示することができます。

Cmdlet Discovery and Aliases - AWS Tools for Windows PowerShell

Get-Command -Module AWSPowerShell

それっぽいコマンドレットが見つかったらGet-Helpにコマンドレット名を指定しヘルプを見て使い方を確認しましょう。-fullオプションをつけると詳細なヘルプを表示してくれます。

Get-Help Get-EC2Instance -full

Webでリファレンスも提供されています。普段はこちらのページをブラウザに表示しながらコードを作成すると良いでしょう。

AWS Tools for Windows PowerShell Reference

パイプラインとデフォルトパラメーター

PowerShellを触り始めて最初に戸惑うのが、Unixシェルと違いパイプ(パイプライン)で渡されるのがオブジェクトということです。パイプラインの出力側コマンドレットでは受け取ったオブジェクトのプロパティを参照することができます。

またパイプラインから受け取ったオブジェクトを、(暗黙の)パラメータとして利用するコマンドレットがあります。例としてGet-EC2Imageのヘルプを見てみましょう。(Amazon Elastic Compute Cloud: Get-EC2Image Cmdlet)。「-ImageIds」パラメータの「Accept pipeline input?」という項目がTrue (ByValue, )となっています。つまり以下のようにAMIのイメージIDを配列にしてパイプラインでGet-EC2Imageコマンドレットに渡すと、AMI情報を取得してくれます。

"ami-e3dd41e2", "ami-ab4a2daa" | Get-EC2Image

クラスとプロパティとメソッド

クラスとプロパティ、メソッドはオブジェクト指向言語ではお馴染みな言葉なので説明は不要でしょう。あるクラスにどのようなプロパティやメソッドがあるかを調べるにはGet-Memberコマンドレットにオブジェクトを渡します。

New-Object Amazon.EC2.Model.Tag | Get-Member

$AWSHistory

AWS Toolsが提供するコマンドレットを実行し、AWSのAPIを実行した際のHTTPレスポンスは$AWSHistoryという特殊な変数に自動的に格納されます。先に掲載したAMIを取得するPowerShellコードの例だとNew-EC2Imageで新しく作成されたAMIの、イメージIDを取得するために使用しています。

$response = $AWSHistory.LastServiceResponse
New-EC2Tag -Resources $response.ImageId -Tags $purgeAllowTag,$purgeAfterTag

$AWSHistory についての詳細は下記ドキュメントを参考にしてください。

Pipelining and $AWSHistory - AWS Tools for Windows PowerShell

インスタンスメタデータの取得

Linuxのシェルでインスタンスメタデータを取得する際にはcurl http://169.254.169.254/ のように取得します。PowerShellではHTTPを扱うコマンドレットとしてInvoke-WebRequestまたはInvoke-RestMethodが用意されています。ただしPowerShellのバージョン3以上でないと存在しませんので注意してください。

自身のインスタンスIDは次のコマンドで取得できます。

Invoke-RestMethod "http://169.254.169.254/latest/meta-data/instance-id"

フィルター(Amazon.EC2.Model.Filter)

PowerShellのバージョン2.0だとフィルターは次のように使います。これはAMI(Image)に設定されたタグを取得しています。初期化コードが少々冗長ですね。

$typeFilter = New-Object Amazon.EC2.Model.Filter
$typeFilter.Name = "resource-type"
$typeFilter.Values.Add("image")

$images = Get-EC2Tag -Filters $typeFilter

PowerShellのバージョン3だと次のコードで初期化が可能になります。ずいぶんシンプルになり読みやすくなった感があります。

(AWS Tools for PowerShell バージョン 1.1の場合)
$typeFilter = New-Object Amazon.EC2.Model.Filter -Property @{Name = "resource-type"; Value = @("image")}
$images = Get-EC2Tag -Filter $typeFilter

(AWS Tools for PowerShell バージョン 2.0の場合)
$typeFilter = New-Object Amazon.EC2.Model.Filter -Property @{Name = "resource-type"; Values = @("image")}
$images = Get-EC2Tag -Filters $typeFilter

文字列展開

PowerShellでは型を意識しなくて良いといわれていますが、Tagから取ってきたValue値はそのまま文字列として使えません。文字列として扱いたい場合はSelect-Object -ExpandPropertyを使います。

$purgeAfter = Get-EC2Tag | Select-Object -ExpandProperty Value

まとめ

今回は初めてAWS Tools for PowerShellを触った際に躓きやすいだろう項目についてまとめてみました。筆者は以前からシェルスクリプトやPerlを扱っていたので文法的な戸惑いは少なかったです。今回まとめたバージョン間の違いや困った時に調べる方法を抑えつつ、あとは数をこなしていけば習得は難しくない言語だと思いました。Windowsのバッチファイルに比べれば遥かに覚えやすく扱いやすい言語ではないでしょうか。

なお今回ご紹介しませんでしたが、PowerShellでは「連想配列」や「正規表現」、変数のスコープといった概念も存在します。これらは一般的なPowerShellの解説本を読んでいただくのが良いでしょう。ただ日本語の書籍でPowerShellバージョン3に対応したものがなかなかありません。そこで最後に今回大変お世話になった参考本をご紹介したいと思います。

Amazonでチェックする