第2回 PowerShellの基礎PowerShell的システム管理入門(2/3 ページ)

» 2010年04月15日 00時00分 公開

PowerShellスクリプトの基本

 コンソールから入力していたコマンド列をそのままテキスト・ファイルの1行ごとに書いていくのがPowerShellスクリプトの基本である。スクリプトは原則として、1行目から最終行まで、1行ずつ順に実行されていく。そのため、これまではコマンドを1つ入力しては[Enter]キーを押下、と繰り返していた処理を一括で実行できるようになるわけである。例を挙げよう。

Get-Date > dirinfo.txt
Get-ChildItem C:\ >> dirinfo.txt

 以上を例えばSaveDirInfo.ps1と名前を付けて保存し、実行する。すると現在時刻とC:\に存在するファイルとフォルダのリストが、リダイレクト記号「 > (新規作成)」および「 >>(追記)」により、dirinfo.txtというテキスト・ファイルに保存される。

 このようにPowerShellはバッチファイルと同様に、コマンドを改行区切りで並べるだけでスクリプトが記述できる。それだけではなく、WSHで用いるVBScriptやJScriptのように、各種ステートメントを用いた構造化プログラミングも可能である。その方法については後述する。

変数と演算子について

 変数とはオブジェクトやその配列を格納しておくための箱のようなものである。変数に値を格納することで、後でその変数の値を参照することができるようになる。

 PowerShellの変数名は「$」を先頭に付けるのが決まりである。例えば2という整数を$iという変数に格納し、後で参照するには次のようにする。

$i = 2
Write-Host $i

 このスクリプトを例えばinteger.ps1という名前で保存し、実行すると結果は次のようになる。

スクリプトinteger.ps1の実行例
値を代入した変数を後で参照して表示している。

 このスクリプトでは1行目で2という整数値を$iという変数に代入(格納)している。そして2行目でWrite-Hostコマンドレットを使って変数の中身を出力している。

 ちなみにこのとき$iに格納されているのは、System.Int32構造体(注1)のインスタンスである。また、$iを「Int32型の変数」ということもある。型とはオブジェクト(インスタンス)の種類を意味し、変数が何のクラス/オブジェクトの変数であるかを示す。1.001など小数を含む数値を代入するとSystem.Double型の変数になる。

注1:System.Int32構造体は、PowerShellではintという別名も付けられている。構造体はクラスと同様のものである。ここでは構造体とクラスの違いについては触れないが、PowerShellで基本的なスクリプトを書く範囲では同様に扱える。また、変数やコマンドレットの戻り値などの型を調べるには、Get-Memberコマンドレットを用いる。

Get-Memberコマンドレットの使用例
変数やコマンドレットの出力をパイプでGet-Memberコマンドレットに渡すと、オブジェクトのクラス名やメソッド、プロパティなどが表示される。先頭の「TypeName:」に表示されているのがクラス名(型名)である。


 なおPowerShellの変数は、VBScriptのように使用するに当たって明示的に宣言する必要はない。変数を記述して値を代入するだけで、変数宣言も同時に行ったことになる(注2)。またPowerShellの変数名はVBScriptと同様、大文字/小文字の違いを区別しない。つまり$iと$Iは同じ変数である。変数名に限らず、コマンドレットやパラメータ名などでも同様である。

注2:スクリプトの先頭に、

Set-PSDebug -strict


と記述し、さらに最終行に

Set-PSDebug -Off


と記述しておけば、そのスクリプト中で「宣言が行われていない変数」を「参照」しようとすると、エラーが発生するようになる。VBScriptのOption Explicit宣言(宣言をしていない変数を使用しようとするとエラーになる機能)に似ているが、VBScriptと違って、PowerShellでは変数の「宣言」は値を代入することで自動的に行われる。

 文字列を扱う際は " " (ダブルクオーテーション)記号で囲む。例えば

$str = "Hello PowerShell World! "
Write-Host $str

のようにする。ただしコマンドレットのパラメータに指定する場合に限って、文字列は " " を省略することもできる。例えば

Get-Process | Select-Object -property "ProcessName"

としなくても、

Get-Process | Select-Object -property ProcessName

と書くことができる。

 値や変数は演算子を用いて演算が可能である。例えば算術演算子を使えば数値の四則演算や文字列の連結などが可能になる。

$i = 10 + 5
Write-Host $i
$j = $i * 3
Write-Host $j

$str = "Windows"
$str = $str + " PowerShell"
Write-Host $str

 このスクリプトを実行すると、次のように表示される。

operator.ps1の実行例
演算子を用いて得られた値を出力している。

 $iには算術演算子の1つ、「+」演算子を用いて10に5を加えた値が格納される。

 また「*」演算子を用いると掛け算を行うことができる。「+」演算子を文字列に対して使うと、文字列同士を連結して1つの文字列にすることができる。

 以下に、算術演算子のリストを示しておく。

算術演算子 説明
+ ・数値同士の足し算を行い、結果を返す
・文字列同士を連結した文字列を返す
・配列同士を連結した配列を帰す
- ・数値同士の引き算を行い、結果を返す
* ・数値同士の掛け算を行い、結果を返す
・左辺に与えた文字列を、右辺に与えた数値の回数だけ繰り返した文字列を返す
・左辺に与えた配列を、右辺に与えた数値の回数だけ繰り返した文字列を返す
/ ・数値同士の割り算を行い、結果を返す
% ・数値同士の割り算を行い、余りの値を返す
PowerShellの算術演算子のリスト

配列について

 これまでは変数に1つのオブジェクトを格納する例を取り上げたが、複数のオブジェクトを格納した配列を自分で作成することもできる。

$array = @(1,2,3,4,5)
Write-Host $array[2]

 このスクリプトを実行すると以下のように表示される。

array.ps1の実行例
5要素の配列を宣言し、3番目の要素の値(3)を表示している。

 配列は @( ) の中に , で要素を並べることで宣言および代入ができる。1行目では、Int32型の1から5までの5つの数字からなる配列を$arrayに代入している。このとき要素の数(総数)は5である($array.Lengthで調べることもできる)。2行目では、この配列の3番目の要素を参照している。[ ] 内に書くインデックス(配列を参照するための添字)は、配列の先頭を0と数えることに注意していただきたい。なお、@ と ( ) を省略して、「$array = 1,2,3,4,5」のようにも記述できる(つまりオブジェクトを「 , 」で区切って並べるだけで配列になるということ。このために「Select-Object Id,ProcessName」などと記述できる。 これは「Select-Object @("Id","ProcessName")」と等価)。

 もちろんコマンドレットの戻り値を変数に格納することもできる。

$process = Get-Process
$process[0]

 結果、1番目のProcessオブジェクトが表示される。コマンドレットの戻り値は配列のことが多いが、結果が1つだった場合は配列でないオブジェクトが返されることもある。そのため、コマンドレットの戻り値を必ず配列として扱うためには、

$process = @(Get-Process)
$process[0]

とした方がよい。こうすると、たとえ結果が1つであっても、要素数1の配列として変数に代入される。

ステートメントについて

 PowerShellにはほかのスクリプト言語と同様に、いくつかのステートメントが存在する。これらのステートメントを用いると構造化されたコードを書くことができる。そのうち最もよく使用する2つを解説する。

ifステートメント

 PowerShellにおいて、ある条件が満たされるときのみ何かを実行させるようにするには、ifステートメントを使って条件分岐を行う。例えば、現在時刻が午前中であるときだけ「現在時刻は午前です」という文字列を表示することを考えよう。

$now = Get-Date
if($now.Hour -lt 12)
{
    Write-Host "現在時刻は午前です"
}

 変数$nowにはGet-Dateコマンドレットにより、現在時刻がDateTime型で格納される。DateTimeオブジェクトのHourプロパティには「時分秒」の「時」が24時間制で格納されているので、それを基に午前か午後を判別する。12時より前なら午前なので、ifの中に条件を書く。-ltは比較演算子の1つで、「左辺が右辺より小さい」とき真(True)である(成立する)、という意味である。もしこの条件が成り立つ場合、続く { } 内の文が実行される。すなわち、0〜11時のときはメッセージが表示されるわけである。条件が成り立たない場合、すなわち12時〜23時のときは何も実行しない。

 次にこのスクリプトを改善し、午前には「現在時刻は午前です」と表示し、午後には「現在時刻は午後です」と表示するように変更してみよう。

$now = Get-Date
if ($now.Hour -lt 12)
{
    Write-Host "現在時刻は午前です"
}
elseif ($now.Hour -ge 12)
{
    Write-Host "現在時刻は午後です"
}

 ifの条件が成り立たない場合、elseifの条件が成り立つかどうかチェックされる。もし成り立つと続く { } 内の文が実行される。-geは「左辺が右辺以上である」という意味である。elseifは複数記述することができる。

 また、ifも、どのelseifも成り立たない場合に実行する文はelseの後に記述できる。先ほどのスクリプトではelseifを用いたが、「午前である」という条件が成り立たない場合は常に「午後である」ので、elseを使って次のように書き換えられる。

$now = Get-Date
if ($now.Hour -lt 12)
{
    Write-Host "現在時刻は午前です"
}
else
{
    Write-Host "現在時刻は午後です"
}

 以下にPowerShellでよく使われる比較演算子のリストをまとめておく。

比較演算子 説明 等価な算数の記号 演算子名の由来
-eq 左辺と右辺が等しい EQualの略
-ne 左辺と右辺が異なる Not Equalの略
-lt 左辺が右辺より小さい Less Thanの略
-le 左辺が右辺以下 Less than or Equalの略
-gt 左辺が右辺より大きい Greater Thanの略
-ge 左辺が右辺以上 Greater than or Equalの略
PowerShellの比較演算子のリスト(一部)

foreachステートメント

 配列に対して要素を列挙し、繰り返し処理を行うにはforeachステートメントを用いる。機能としてはForEach-Objectコマンドレットとほぼ同じだが、ステートメント内に複数の文を書くときにコードが見やすくなる。

 ForEach-Objectコマンドレットのところで取り上げた例と同じ結果になるコードを書くには、

$items = @(Get-ChildItem)
foreach($item in $items)
{
    Write-Host $item.FullName
}

となる。このように「foreach(変数 in 配列)」とすることで、配列に含まれる配列要素が1つずつ変数に格納され、配列要素すべてに対して繰り返し { } 内のコードが実行される。

 foreachステートメントの中にifステートメントを入れることも可能である。ForEach-Objectコマンドレットのところで取り上げた2つ目の例と同じ結果になるコードを書くと、次のようになる。

$items = @(Get-ChildItem)
foreach($item in $items)
{
    # テキスト・ファイルならば
    if ($item.Extension.ToLower() -eq ".txt")
    {
        Write-Host $item.FullName # フルパスを表示
    }
}

 なお「 # 」はコメント記号であり、#の右側にはスクリプトに対する注釈を記述できる。コメントは実行の対象にはならない。

 ほかにもさまざまなステートメントが存在するが、よく使われるのはこの2つであるので覚えておいてもらいたい。

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。