Windows PowerShellのパワーの源は.NETオブジェクト:特集:Windows PowerShellレビュー(後編)(1/3 ページ)
マイクロソフトの新シェルでは、コマンドの実行結果はテキストではなくオブジェクトだ。このことはかつてない操作性をもたらす。
前編ではWindowsの新しいシェルであるWindows PowerShell(以下、PowerShell)の対話式シェルとしての基本機能について紹介した。
後編となる今回では、PowerShellにおけるオペレーションのベースとなっている「オブジェクトの操作」について解説していく。これはPowerShellがこれまでのテキスト・ベースのシェルと比較して画期的に異なるポイントだ。
コマンドの実行結果はオブジェクト
これまでのUNIXシェルやWindowsのコマンド・プロンプトで実行されるコマンドの多くは、その実行結果をテキスト・データとして返す。これに対してPowerShellでは、コマンド(Cmdlet)の実行結果はすべて「オブジェクト」である。これはメソッドやプロパティを持った、.NET Frameworkのオブジェクト・モデルをベースとするオブジェクトだ。
もちろん、最終的に画面に出力されたりファイルへリダイレクトされたりするときにはコマンドの実行結果はテキストとなるのだが、それまでにオブジェクトとしてさまざまな操作が可能だ。PowerShellを実際に使いながらそれを見てみよう。
■dirコマンドが返すファイル情報オブジェクト
ここではまず、「dirコマンド」(前回で解説したように、これはCmdletの1つである「Get-ChildItemコマンド」のエイリアス)の実行結果をシェル変数$resultに代入する。シェル変数は「$変数名」の形式で表記され、宣言なしで使える(以降の実行例では、キーボードからの入力を黄色い文字で示している)。
PS C:\proj> dir Form1.cs
Directory: Microsoft.PowerShell.Core\FileSystem::C:\proj
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2006/07/12 23:05 2422 Form1.cs
PS C:\proj> $result = dir Form1.cs
dirコマンドの実行結果はオブジェクトであるため、シェル変数「$result」にはそのオブジェクトが代入される。
では、実行結果であるオブジェクトの型を知るために、$resultに対してGetTypeメソッドを呼び出してみよう。.NET開発者ならご存じのように、GetTypeメソッドはすべてのクラスの基本クラスであるObjectクラスで定義されているため、どのオブジェクトもこのメソッドを持っている。
PS C:\proj> $result.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True FileInfo System.IO.FileSys...
GetTypeメソッドはその型に関する情報を返す。このメソッドはすべてのクラスの基本クラスであるObjectクラスで定義されているため、どのオブジェクトに対しても呼び出し可能だ。
このようにdirコマンドはファイル「Form1.cs」の情報をFileInfo型のオブジェクトで返している。これは、.NET Frameworkクラス・ライブラリにあるFileInfoクラス(System.IO名前空間)のオブジェクトだ*。
* 実際には完全に同一ではない。PowerShell上でのFileInfoオブジェクトは、.NET Frameworkクラス・ライブラリのFileInfoオブジェクトにいくつかのプロパティやメソッドを追加して拡張している。標準のCmdletがその実行結果として利用する基本的なオブジェクトの多くはそのようになっている。これらの拡張のためのプロパティやメソッドの定義は、PowerShellのインストールされたディレクトリにある「types.ps1xml」で記述されている。また、「Add-Memberコマンド」によりコマンドラインからユーザーが動的にメンバを追加することもできる。
FileInfoクラスには例えば、そのファイルをコピーするためのCopyToメソッドが用意されている。実際に、このメソッドを以下のようにして呼び出すことができる。
PS C:\proj> $result.CopyTo("c:\tmp\tmp.cs")
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2006/07/12 23:05 2422 tmp.cs
PS C:\proj> dir /tmp/tmp.cs
Directory: Microsoft.PowerShell.Core\FileSystem::C:\tmp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2006/07/12 23:05 2422 tmp.cs
$resultが示すファイル「Form1.cs」をCopyToメソッドにより「c:\tmp\tmp.cs」にコピーしている。メソッド呼び出しの結果、tmp.csについての情報が表示されるのは、このメソッドの戻り値が、コピーされた新しいファイルを示すFileInfoオブジェクトのためである。
また、FileInfoクラスにはファイルのサイズを取得するためのLengthプロパティも用意されている。もちろんこれも問題なく実行できる。
PS C:\proj> $result.Length
2422
FileInfoクラスのLengthプロパティはそのファイルのサイズを返す。
ちなみに、Lengthプロパティの型は64ビット符号付き整数であるInt64型である。
PS C:\proj> $result.Length.GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Int64 System.ValueType
ファイル・サイズを取得するLengthプロパティの値も単なる数値ではなく、実際にはInt64型のオブジェクトである。
FileInfo型についての情報はMSDNなどに記述されているが、あるオブジェクトがどのようなメンバ(=メソッドやプロパティ)を持っているかは「Get-Memberコマンド」により参照可能だ*。
PS C:\proj> Get-Member -InputObject $result
TypeName: System.IO.FileInfo
Name MemberType Definition
---- ---------- ----------
AppendText Method System.IO.StreamWriter AppendText()
CopyTo Method System.IO.FileInfo CopyTo(String de...
Create Method System.IO.FileStream Create()
CreateObjRef Method System.Runtime.Remoting.ObjRef Crea...
CreateText Method System.IO.StreamWriter CreateText()
Decrypt Method System.Void Decrypt()
……以下省略……
Get-Memberコマンドでは-InputObjectオプションにより、対象となるオブジェクトを指定する。
* ここでは入力オブジェクトを-InputObjectオプションにより指定しているが、Get-Memberコマンドはパイプ(|)と組み合わせて使用するのが一般的だ。これについては後述する。
なお、ここまでは分かりやすいようにコマンドの実行結果を最初にシェル変数に代入したが、実際にはコマンドをカッコでくくることにより、その実行結果のオブジェクトを直接扱うことができる。つまり以下のような実行が可能だ。
PS C:\proj> (dir Form1.cs).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True FileInfo System.IO.FileSys...
コマンドをカッコでくくることにより、その実行結果となるオブジェクトを直接扱うことができる。
以下の例では、この記述方法を使っていく。
■オブジェクトの配列を返すdirコマンド
ここまでの例では、dirコマンドのパラメータに「Form1.cs」を指定して1つのファイルについてのオブジェクトを扱ったが、dirコマンドは通常、複数のファイルやディレクトリを返す。このような場合にはコマンドの結果はオブジェクトの配列となる。
PS C:\proj> (dir).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
実行結果の型が「Object[]」となっていることから、それがObject型のオブジェクトの配列であることが分かる。
配列では、その要素数(dirコマンドの場合にはファイルやディレクトリの総数)をLengthプロパティから得ることができる。
PS C:\proj> (dir).Length
8
PS C:\proj> dir
Directory: Microsoft.PowerShell.Core\FileSystem::C:\proj
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2006/07/12 23:05 2422 Form1.cs
-a--- 2006/07/10 17:15 1333 Form1.Designer.cs
-a--- 2006/07/10 17:15 344 Form2.cs
-a--- 2006/07/12 23:06 521 Program.cs
-a--- 2006/07/10 17:15 3093 WindowsApplication1.csproj
d---- 2006/07/12 23:00 bin
d---- 2006/07/12 23:00 obj
d---- 2006/07/12 23:00 Properties
dirコマンドは結果を配列で返すが、その要素数はArrayクラス(System名前空間)のLengthプロパティにより取得できる。ここではファイルとディレクトリが合計8個あるので、Lengthプロパティの値は8となる。
また、配列の各要素へは大カッコ([])によりアクセスできる。
PS C:\proj> (dir)[0]
Directory: Microsoft.PowerShell.Core\FileSystem::C:\proj
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2006/07/12 23:05 2422 Form1.cs
PS C:\proj> (dir)[0].Name
Form1.cs
配列の個々の要素へは大カッコでインデックス番号を指定してアクセスする。「(dir)[0]」はdirコマンドの実行結果の先頭のオブジェクトを示している。
配列の全要素を順に操作したければ、foreachステートメントが使える*。foreachステートメントの記述方法はC#のそれとほぼ同様だ。以下の例では、拡張子が.csの各ファイルに対して、そのファイル名のみを小文字で表示している。
PS C:\proj> foreach ($file in dir *.cs) { $file.Name.ToLower() }
form1.cs
form1.designer.cs
form2.cs
program.cs
「dir *.cs」の実行結果として返される配列の各要素が順にシェル変数$fileに代入され、中カッコ({})内のスクリプト(スクリプト・ブロックと呼ばれる)が実行される。ここではファイル名を得るためのNameプロパティを呼び出し、さらにそのToLowerメソッドを呼び出して小文字に変換している。NameプロパティはString型であり、ToLowerメソッドはStringクラスのメソッドである。
* PowerShellにはこれ以外にif、for、whileなどのステートメントが用意されている。これらはコマンドラインからも利用できるが、シェル・スクリプトの記述時に使用されるのが一般的だ。
■プロセスの操作
ここまではファイルを扱ってきたが、別の例として実行中のプロセスを扱う場合についても簡単に紹介しておこう。
実行中のプロセスの一覧はUNIXでは「psコマンド」で得られるが、PowerShellではそれが「Get-Processコマンド」のエイリアスとして用意されている。
PS C:\proj> ps
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
137 7 3484 6152 51 1.44 464 04WebServer
106 6 1224 3608 35 0.03 2512 alg
39 3 1880 4560 40 0.36 2996 ATOK17MN
149 5 5192 9512 63 0.38 2620 CameraAssistant
333 12 7572 13752 100 1.80 3188 CCAPP
261 7 2808 2072 53 0.30 1940 CCEVTMGR
185 5 2592 3660 38 0.25 1892 CCSETMGR
51 3 2144 5728 44 0.08 772 conime
625 7 2584 8348 76 22.08 1084 csrss
130 6 1864 5500 48 4.06 3300 ctfmon
72 4 2524 5252 43 0.27 1684 daemon
79 4 2944 3692 50 0.72 768 dice
項目ヘッダの項目名はそれぞれ以下のProcessクラスのプロパティを示している。
・NPM:NonpagedSystemMemorySize
・PM:PagedMemorySize
・WS:WorkingSet
・VM:VirtualMemorySize
・CPU:TotalProcessorTime
このように、psコマンドでは現在実行されているプロセスの一覧が、メモリ使用量やCPU使用時間などとともに表示される。
psコマンドも先ほどのdirコマンドと同様にオブジェクトの配列を返す。
PS C:\proj> (ps).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True True Object[] System.Array
psコマンドの実行結果もdirコマンドと同様にオブジェクトの配列となっている。
配列の要素となっているオブジェクトはこの場合、Processクラス(System.Diagnostics名前空間)のオブジェクトである。
PS C:\proj> ps explorer
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
643 19 25900 40272 149 139.95 2744 explorer
PS C:\proj> (ps explorer).GetType()
IsPublic IsSerial Name BaseType
-------- -------- ---- --------
True False Process System.ComponentM...
ここではエクスプローラがすでに実行されているものとする。psコマンドが表示する各プロセスは、Process型のオブジェクトである。
以下の例ではメモ帳(notepad.exe)を起動し、そのウィンドウのタイトルを表示してから、Killメソッドを呼び出すことによって強制終了させている。
PS C:\proj> notepad
PS C:\proj> (ps notepad).MainWindowTitle
無題 - メモ帳
PS C:\proj> (ps notepad).Kill()
メモ帳(notepad.exe)を起動し、そのウィンドウのタイトルを表示してから、Killメソッドを呼び出して強制終了させている。
なおここではKillメソッドを呼び出しているが、Cmdletとして「Kill-Processコマンド」(エイリアス名は「kill」)が用意されており、プロセスを強制終了させるには通常こちらを使う。
Copyright© Digital Advantage Corp. All Rights Reserved.