Skip to main content
評価してください: 

 

Windows PowerShell でのパイプ処理とパイプライン

Windows PowerShell オーナー マニュアル

これは、Windows PowerShell の使用を開始するためのガイドです。このガイドを一読して Windows PowerShell について理解すると、すぐにこのツールをプロフェッショナルのように駆使できるようになります。

トピック

パイプ処理とパイプライン

Windows PowerShell をインストールしたらすぐに "パイプ処理" や "パイプライン" について聞いたり読んだりするようになるでしょう。これは避けられないことです。そこから、「パイプラインとは何なのか」、そして「そもそもパイプ処理とパイプラインについて知る必要はあるのか」という 2 つの疑問が生まれます。

まずは、「そもそもパイプ処理とパイプラインについて知る必要はあるのか」という 2 つ目の疑問にお答えしましょう。知る必要はあります。パイプラインを使わなくても Windows PowerShell スクリプトを記述できるのは間違いありませんが、問題は、パイプラインを使わずに PowerShell スクリプトを記述したいかどうかです。バナナ スプリット (バナナを縦切りにしたものにアイスクリームを載せ、チョコレート シロップや生クリームなどをかけたデザート) からアイスクリームを抜いたものを注文することは可能で問題ありませんが、それではバナナ スプリットとは呼べないと思いませんか。PowerShell のパイプラインも同様です。パイプラインを使わなくてもスクリプトを記述できますが、それでも "PowerShell" スクリプトと呼べるのでしょうか。

: ええ、ちょっと誇張してしまいました。パイプラインが必要ではないスクリプトもあります。ですが一般的には、より長くて複雑な PowerShell スクリプトにはパイプラインが必要です。


ページのトップへ

パイプラインの組み立て

それでは、パイプ処理とパイプラインとは何なのでしょうか。そもそも、ある意味で "パイプライン" は間違った名称だと言えます。アラスカ パイプラインのような石油パイプラインがあるとしましょう。パイプラインの一方の端から油を注ぎます。もう片方の端からは何が出てくると思いますか。そうです、石油です。これがパイプラインの本来の機能です。パイプラインとは本来、何かをある場所から別の場所に形を変えずに移動する手段に過ぎません。ですが、Windows PowerShell におけるパイプラインの機能はこれと異なります。

: これに関しては議論があります。たとえば、あるオブジェクトを、コマンドの一部分から別の部分に "パイプ処理" する場合、そのオブジェクトは、コマンドの一部分から別の部分に形を変えずに渡されます。このトピックに関しては興味深い議論があり、これには、クールエイド、廃棄物管理施設 (聞かないでください)、また、売買のパイプラインやその他の産業特有の専門用語の話が関係していますが、これによって皆さんを混乱させるわけにはいきません。おそらく、もう十分に混乱されていると思いますし、このガイドの目標は皆さんの混乱を解くことですので、次に進みます。

Windows PowerShell のパイプラインは、むしろ組み立てラインに近いとお考えください。組み立てラインでは、特定のものを出発点として作業を始めます。たとえば、車から始めるとしましょう。ただし、"完成した" 車から始めるのではなく、最終的に車と "なる"、骨組みのようなものから始めます。車は、組み立てラインを流れていくにしたがって、さまざまな工程を通ります。各工程では、作業員がドアの溶接、窓の設置、シートの取り付けなど、なんらかの変更を加えます。すべての工程が終了しても、開始したときと同様に車であることに変わりはありません。歯磨き粉のチューブや石油になるということはありません。ですが、完成までの過程で加えられたあらゆる変更によって、組み立てラインの最初の段階での "車" とはまったく異なる車になります。

ページのトップへ

まずはコマンドレットから

Windows PowerShell でパイプラインを使用するときも、同じようなことが行われます。たとえば、Get-Shapes というコマンドレットがあるとしましょう。このコマンドレットを実行すると、コンピューター上にあるすべての幾何学的図形が返されます。この架空のコマンドレットを呼び出すには、次のようなコマンドを使用します。

Get-Shapes

このコマンドを実行すると、次のような図形が返されます。

図形のイメージ

ページのトップへ

フィルター処理の工程

かなりすばらしい結果になりましたが、1 点だけ問題があります。実は、オレンジ色の図形だけを表示したいのです。ですが、残念ながら、架空の Get-Shapes コマンドレットでは、指定した基準を満たさないアイテムを除外できません。ついていないと思いませんか。

ええ、ついていませんね。

ちょっと待ってください。間違えました。「いや、そんなことはありません。」と言おうとしたのです。確かに、Get-Shapes では不要なアイテムを除外できません。ですが、これは問題ではありません。PowerShell の Where-Object コマンドレットを使用すれば、不要なアイテムを除外できるからです。したがって、私たちはただ、Get-Shapes を使用してすべての図形を取得したら、それらの図形を Where-Object に渡し、オレンジ色でない図形を除外する処理は Where-Object に任せればよいのです。つまり、次のようなコマンドを使います。

Get-Shapes | Where-Object {$_.Color -eq "Orange"}

ひとまず、Where-Object コマンドレットの構文については気にする必要はありません。Where-Object の使い方の概要については、 この記事を参照してください。ひとまず重要なのは、2 つのコマンド (Get-Shapes と Where-Object) を区切っているパイプ区切り記号 (|) です。通常、Windows PowerShell でパイプラインを使用するというのは、コマンドレットを使用してオブジェクトのコレクションを取得することを意味します。ですが、取得したオブジェクトに対して何かを行うわけではありません (少なくとも、今すぐ何かを行うわけではありません)。代わりに、取得したオブジェクトのコレクションを、なんらかのさらなる処理 (フィルター処理、グループ化、並べ替えなど) を行う 2 つ目のコマンドレットに渡します。これこそが、パイプラインの機能です。

架空のコマンドレットを使用した今回の例では、パイプラインを使用することで、次のように、オレンジ色ではない図形をすべて除外できます。

オレンジ色ではない図形をすべて除外したイメージ


ページのトップへ

並べ替えの工程

これもすばらしいのですが、もっとすばらしいのは、組み立てラインを構成する工程を 2 つよりも多くできるということです。たとえば、オレンジ色の図形をサイズに基づいて並べ替える必要があるとします。Where-Object を使用しても並べ替えを行うことはできませんが、次のように Sort-Object を使用すると並べ替えを行うことができます。

Get-Shapes | Where-Object {$_.Color -eq "Orange"} | Sort-Object Size

これで本当にうまくいくのでしょうか。もちろんうまくいき、次のような結果が返されます。

オレンジ色の図形をサイズに基づいて並べ替えしたイメージ


ページのトップへ

実用的なパイプライン

PowerShell パイプラインのもう少し実用的な使い方の例をご紹介します。これからご紹介するコマンドでは、Get-ChildItem コマンドレットを使用して、C:\Scripts フォルダー内にあるすべてのアイテムの一覧を取得します。その後、それらのアイテムを Where-Object コマンドレットに渡し、Where-Object では、サイズが 200 KB 未満のすべてのアイテム (ファイルまたはフォルダー) を除外します。Where-Object は、フィルター処理を完了すると、残ったアイテムを Sort-Object コマンドレットに渡します。Sort-Object コマンドレットは、それらのアイテムをファイル サイズに基づいて並べ替えます。

コマンドそのものは次のようになります。

Get-ChildItem C:\Scripts | Where-Object {$_.Length -gt 200KB} | Sort-Object Length

このコマンドを実行すると、次のような結果が返されます。

ディレクトリ: Microsoft.PowerShell.Core\FileSystem::C:\Scripts

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---         2/19/2007   7:42 PM     266240 scores.mdb
-a---         5/19/2007   9:23 AM     328620 wordlist.txt
-a---         12/1/2002   3:35 AM     333432 6of12.txt
-a---         5/18/2007   8:12 AM     708608 test.mdb

かなりうまくできましたが、少し懐疑的な方もいらっしゃるようです。「ああ、確かにいいけど、たいしたことはないな。結局、WMI クエリを記述すれば、クエリでフィルター処理ができるじゃないか。そして、ADSI スクリプトを記述すれば、コレクションをたとえばユーザー アカウントに限定するフィルターを追加できる。どれも既にやっているよ。」というのが、このような方々の意見です。

考えようによっては、それも正解です。結局、WMI でも ADSI スクリプトでも、確かにフィルター処理を実行することはできます。ただし、WMI でフィルターを記述する際に使用するアプローチは、一般的に、ADSI でフィルターを記述する際に使用するアプローチとは大きく異なります。同様に、ADSI のフィルターを記述する際に使用するアプローチは、FileSystemObject を使用してフィルターを記述する際に使用するアプローチとは異なります。Windows PowerShell のメリット、そしてパイプラインを使用するメリットは、操作するデータやオブジェクトの種類を考慮しなくて済むことです。必要なものをすべて Where-Object に渡したら、後はすべて Where-Object に任せてしまえばよいのです。

別のよく使用される操作の例として、並べ替えについて考えてみましょう。データベース クエリ (Active Directory に対する ADO クエリを含む) を行う場合、クエリの一部として並べ替えオプションを指定できるので、パイプラインは必要ありません。ですが、WMI クラスに対して WQL クエリを行う場合はどうでしょう。WQL では並べ替えオプションを指定できないので、これは問題です。VBScript でこれに対処しようとすると、データの並べ替えという一見簡単そうな処理を行うためだけに、独自の並べ替え関数を記述したり、切断されたレコードセットのような回避策を使用したりするなど、大変な作業を行う必要があります。

PowerShell の場合もそうなのでしょうか。もうその答えはおわかりですね。もちろん、そんなことをする必要はありません。PowerShell を使用する場合は、データを Sort-Object コマンドレットにパイプして、そのままくつろぎながら待つだけです。たとえば、コンピューターで実行されているサービスに関する情報を取得し、その後、サービスの状態 (実行中、停止中など) に基づいて、返されたコレクションを並べ替えるとします。次のようにすれば、お手のものです。

Get-Service | Sort-Object Status | Format-Table
: おまけとして、並べ替えたデータを Format-Table コマンドレットにパイプしていることにお気付きだと思います。つまり、最終的に画面に表示されるのは、一覧ではなく表になるということです。


ページのトップへ

我を忘れずに

簡単だと思いませんか。実際、問題にぶつかるのは、我を忘れてすべてをパイプ処理しようとする場合にほぼ限られます。パイプラインを使用する意味がない場合は、何かをパイプ処理することはできないことに注意してください。Sort-Object では、ほぼ何でも並べ替えることができるので、サービス情報を Sort-Object にパイプすることには意味があります。また、Format-Table では、ほぼどのような情報でも受け取って表として表示できるので、並べ替えた情報を Format-Table にパイプすることにも意味があります。

ですが、次のコマンドについて考えてみてください。

Sort-Object | Get-Process

このコマンドでは、何が行われるのでしょうか。何も行われません。何かが行われるのを期待することもできません。Sort-Object は情報を並べ替えるためのものなのに、ここには並べ替えるものが何もないのですから (ところで、これは、Sort-Object は一般的にパイプラインの右側に置く必要があるというヒントでもあります。情報を並べ替えるには、その前にまず、その情報を取得する必要があります)。

: この規則に例外はあるのでしょうか。もちろんあります。たとえば、データのコレクションが格納された $a 変数があるとします。次のようなコマンドを使用すると、パイプラインをまったく使用しないでデータを並べ替えることができます。
Sort-Object -inputobject $a

このようなアプローチをいずれ必要とする日が来るかもしれませんが、初心者の方はこれを気にする必要はありません。代わりに、パイプ処理とパイプラインを使用する習慣を身につけておきましょう。まずは規則を学ぶのが大切です。その後、例外を学ぶ時間はいくらでもあります。

ですが、たとえ Sort-Object によって並べ替えられるものがあったとしても、このコマンドにはあまり意味がありません。Get-Process コマンドレットは、コンピューターで実行されているプロセスに関する情報を取得するように設計されているのです。パイプラインを通じて渡された並べ替え済みの情報を、Get-Process がどう操作すればよいというのでしょうか。ほとんどの場合、まずは何か (コレクション、オブジェクトなど) を取得して、それから、そのデータをパイプラインを通じて渡します。その後、パイプラインの右側にあるコマンドレットが、渡されたアイテムに対して、なんらかのさらなる処理や書式設定を行います。

つまり、パイプラインを通じてデータを渡すときは、パイプラインの反対側に必ずコマンドレットがなければなりません。PowerShell をよく使うようになると、しだいに次のようなコマンドを記述したくなります。

$a = Get-Process | $a

確かに、このコマンドには問題がなさそうに見えます。Get-Process の出力を $a 変数に代入し、$a を表示しようとしているようです。ですが、このコマンドは機能せず、次のようなエラー メッセージが表示されます。

式は、パイプラインの最初の要素としてのみ許可されます。
発生場所 行:1 文字:21
+ $a = Get-Process | $a <<<<

確かに区別が難しいかもしれませんが、パイプラインは、"データをパイプラインの一部から次の部分に渡しながら"、複数のコマンドをつなげて単一のコマンドにするために使用されます。さらに、そのデータは、あるセクションから別のセクションに渡されるたびに、なんらかの方法 (フィルター処理、並べ替え、グループ化、書式設定など) で形を変えられます。上記の無効なコマンドでは、何のデータも渡していません。実際のところ、ここにあるのは完全に独立した 2 つのコマンドです。まず、Get-Process を使用して、コンピューター上で実行されているプロセスについての情報を返そうとしており、その後、そのデータの形をまったく変えずに情報を表示しようとしています。実際には独立したコマンドが 2 つあるので、次のように 2 行のコードが必要です。

$a = Get-Process
$a

このすべてを 1 行のコードで行う必要がある場合は、次のように、パイプ区切り記号ではなくセミコロンを使用してコマンドを区切ります。

$a = Get-Process; $a

ただし、これはパイプ処理ではなく、複数のコマンドを 1 行に記述しているだけです。


ページのトップへ

おまけのヒント

では、プロセス情報を取得し、その情報をプロセス ID に基づいて並べ替えてから、その情報を表示するのではなくデータを $a という名前の変数に格納する必要があるとします。これは可能でしょうか。次のようにすると、これを行うことができます。

$a = (Get-Process | Sort-Object ID)

ここでは、$a に値を代入しています。代入しているのは、Get-Process コマンドレットを呼び出した後、取得した情報を Sort-Object にパイプしたときに返された値です。このコマンドが機能するのは、Get-Process/Sort-Object コマンドがかっこで囲まれているからです。PowerShell がコマンドを解析するときは常に、かっこで囲まれている指示を何よりも先に実行します。この場合はつまり、PowerShell はまずプロセス情報を取得して並べ替え、それからそのデータを $a に代入するということです。$a の値を表示して、ご自身で確かめてみてください。

ですが、初心者の方は、このおまけの例についてはあまり気にしないでください。"従来の" 方法でパイプラインを使うのに慣れてから、この部分を読み返して、かっこを使いこなしましょう。


ページのトップへ

パイプラインについての詳細情報

うまくいっていれば、パイプ処理とパイプラインを使い始めるのに十分な知識を得ることができたと思います。基本的な考え方が理解できたら、パイプラインに関するもう少し技術的な情報を知りたいと思われるかもしれません。その場合は、Windows PowerShell コマンド プロンプトで次のように入力してみてください。

Get-Help About_pipeline

さらに良い方法としては、新しい Windows PowerShell グラフィカル ヘルプ ファイルをダウンロードして、便利な .CHM ヘルプ ファイルで同じヘルプ トピックを読むことをお勧めします。どちらにしても、パイプラインを無視しては真の Windows PowerShell スクリプト作成者にはなれません。バナナ スプリットを注文するときにマラスキーノ チェリーを抜いてもらうのはかまいません (むしろ、そうするべきです)。ですが、アイスクリームを抜いたバナナ スプリットを注文した場合、なぜバナナ スプリットごときに皆がそれほど大騒ぎするのかを終始疑問に思うことになるでしょう。同じ過ちを Windows PowerShell で犯さないようにしましょう。


ページのトップへ