Windows PowerShellパイプラインについての再考

Don Jones

Windows PowerShell は、UNIX や Linux ベースのオペレーティング システムで数十年使用されているコマンド ライン インターフェイスの概念に基づいていますが、それとは異なる新しくおもしろいものであるということについては、十分に説明しました。けれども、Windows PowerShell という一般的な用語には、その前身も含まれてしまうので、次のようなデメリットがあります。

Windows PowerShell™ の柔軟性や独自性、Windows® 環境での優れた安定性が見落とされがちである

パイプラインは、Windows PowerShell の機能で最も話題に上るものの 1 つですが、残念ながら最も誤解されやすい機能の 1 つでもあります。これは、1970 年初頭に定義された同名の用語に基づいていることが原因です。当時、パイプラインという用語は、まったく別の機能を持った、パフォーマンスの低い機能の名称として使用されていました。

パイプの起源

初めて作成された UNIX シェルの 1 つは Thompson shell です。これは、非常に原始的なものであり、変数のないごく基本的なスクリプト言語の要素を搭載していました。このシェルの本来の目的はプログラムを実行することなので、意図的に質素なデザインが採用されていました。しかし、このシェルは、当時出回っていた他のシェルに改善をもたらした "パイプ" という重要な概念を導入しました。< 記号と > 記号を使用することで、シェルは、入力と出力をコマンド間でリダイレクトできるようになりました。この概念により、ユーザーがコマンドの出力をファイルにリダイレクトできるようになりました。

この構文は、後に、あるコマンドの出力を他のコマンドの入力としてパイプできるように拡張され、長いシーケンスのコマンドを連結して、より複雑なタスクを実行できるようになりました。シェルのバージョン 4 のころには、パイプするために縦線文字 "|" が導入され、パイプ文字として使用されるようになりました。MS-DOS® の初期バージョンでも、このパイプ文字を使用して基本的なパイプ機能が実装されていました。たとえば、ユーザーは、入力コマンドの出力を後続コマンドの入力としてパイプし、長いテキスト ファイルの 1 ページ単位の表示を作成できました。

UNIX Version 6 がリリースされた 1975 年ごろには、Thompson shell の機能は一般的には不十分だと見なされていましたが、パイプの概念は、シェル開発者とシェル ユーザーに浸透し、現在使用されている多くのテクノロジに受け継がれています。

テキストをパイプする

ほぼすべてのシェルには、本質的にテキスト ベースであるという制限があります。UNIX ベースのオペレーティング システムでは、これは制限というよりも、OS 自体のしくみを反映した結果です。UNIX のほぼすべてのリソースは、なんらかのファイルとして表されます。つまり、あるコマンドのテキストを別のコマンドにパイプできることは、大きなメリットと柔軟性をもたらします。

しかし、管理情報については、テキスト ベースであるということは間違いなく足かせになります。たとえば、私が読者の皆さんに Windows コンピュータで実行しているサービスの一覧を提供したら、その一覧の内容を問題なく理解してもらえるでしょう。おそらく、私は、1 列目にサービス名を記入し、2 列目にスタートアップの種類を記入するでしょう。脳は自動的かつ瞬時にテキストを解析 (解釈) するので、この一覧は有益な情報になります。残念ながら、コンピュータは、人間の脳ほど優れていません。コンピュータが、この一覧から有益な情報を得るには、1 列目が 1 ~ 20 文字で構成されていて、2 列目が 22 ~ 40 文字で構成されているなどのような情報をコンピュータに提示する必要があります。

何年もの間、このようなテキスト ファイルの解析を行うには、管理者が複数のコマンドを連結するしかありませんでした。実際、VBScript や Perl などのスクリプト言語では、あるプログラムやコマンドのテキスト出力を受け取って、この出力を後続のタスクで使用できる有益なデータとして解析する必要があるため、スクリプト言語は文字列を操作する言語としては優れています。たとえば、Dir コマンドのテキスト出力を受け取り、その出力からファイル名や日付を解析し、古くて使用していないファイルをアーカイブ用の場所に移動する VBScript ジョブを記述したことがあります。入力データには (一貫性がなく) 常に例外が付き物で、考えられるすべての順列に対応するスクリプトのロジックを作り直す必要があるので、文字列の解析は非常に難解な作業です。

Windows 環境における管理作業のスクリプト化や自動化の手段としてスクリプトを解析するのは、それほど有用ではありません。これは、Windows に格納されている大半のデータの形式が簡単にアクセスできるテキスト形式ではないからです。Windows では、Active Directory®、Windows レジストリ、証明書ストアなど、データ処理を中心とするストアを使用するので、スクリプトの作成者は、ツールを使用して何らかの形式のテキスト出力を生成し、その後、スクリプトを使用して生成したテキストを解析してテキストを操作する必要があります。

使いやすいオブジェクト

Windows ソフトウェアの開発者は、常に物事を改善してきました。初めに、マイクロソフトは、Windows 内部の複雑な処理を使いやすい形式で表すために COM を開発しました。現在、Microsoft® .NET Framework が、このタスクを受け継ぎ、標準化された形式でソフトウェア内部の処理を表しています。

一般的に、COM と .NET はどちらもアイテムをオブジェクトとして公開しています (ソフトウェア開発者は、この単純化について意義を唱えるかもしれませんが、この記事の説明では簡単な表現で差し支えないと判断しました)。これらのオブジェクトは、さまざまな型のメンバを持っています。この記事の説明においては、オブジェクトのプロパティとメソッドが最重要事項です。基本的に、プロパティは、オブジェクトについて説明するか、オブジェクまたはその動作を変更するものです。たとえば、サービス オブジェクトには、サービスの名前を保持するプロパティや、サービスのスタートアップの種類を保持するプロパティがあります。メソッドは、オブジェクトが何らかの処理を行うようにするものです。サービス オブジェクトには、サービスについて行えるさまざまな処理を表す Stop、Start、Pause、Resume などの名前のメソッドを持っていることがあります。

プログラミングやスクリプトの観点から説明すると、オブジェクトのメンバは、ドット形式の表記で表されます。オブジェクトを変数に割当てて、物理的にオブジェクトを操作できるようにすることができます。たとえば、サービスを変数 $service に割当てた場合、$service.Stop という構文を使用してサービスを停止できます。また、$service.Name という構文を使用してサービスの表示名を取得することもできます。

パイプにおけるオブジェクト

Windows は大規模で複雑なオペレーティング システムであり、管理データをテキスト形式で格納しないため、旧式のシェル技法は、管理データの操作には不向きです。たとえば、サービスとそのスタートアップの種類についての整形された一覧を生成する SvcList.exe という名前のコマンドライン ツールがあるとします。数十年前に誕生した MS-DOS シェルの流れを強く受け継いでいる Windows コマンド ライン シェルで、次のようなステートメントを実行したとします。

SvcList.exe | MyScript.vbs 

このステートメントは、サービスの一覧を取得して、一覧を VBScript ファイルにパイプします。整形された一覧を解析する VBScript ファイルを記述して、スタートアップの種類が "無効" (Disabled) に設定されているサービスを出力するなど、必要な処理を行う必要があります。この作業には時間がかかります。結局のところ、問題は、SvcList.exe の出力形式が一意で、他のコマンドが簡単に使用できる一般的な形式を使用していないことにあります。

しかし、オブジェクトでは共通の形式を提供できます。それが、Windows PowerShell パイプラインがテキストだけでなく、すべてのオブジェクトで機能する理由です。Get-WMIObject のようなコマンドレットを実行すると、オブジェクトのグループ (プログラマ用語ではコレクション) を作成することになります。各オブジェクトには、プロパティやメソッドが備わっており、開発者はこれを使用してオブジェクトを操作できます。オブジェクトを Where-Object コマンドレットにパイプすると、必要なオブジェクトだけが表示されるようにオブジェクトをフィルタ選択できます。Where-Object はテキストではなくオブジェクトを受け取っているので、テキストを解析する必要はありません。以下に例を示します。

Get-WMIObject Win32_Service | Where-Object {$_.StartMode -eq “Disabled” }

短い構文を使用する場合は、次のようにエイリアスを使用できます。

gwmi Win32_Service | where {$_.StartMode -eq “Disabled” }

ここで興味深いのは、Windows PowerShell がオブジェクトをパイプラインに必ず渡していることです。シェルは、オブジェクトがパイプラインの末尾に到達するまで、組み込みの書式の規則を使用してオブジェクトのテキスト表記を生成しません。たとえば、次の例について考えてみましょう。

Gwmi Win32_Service | where {$_.StartName –eq “LocalSystem” } | select Name,StartMode

この 3 つのコマンドレットは、ローカル コンピュータで実行されているすべてのサービスを取得し、ログオンに LocalSystem アカウントを使用していないサービスをフィルタアウトし、残りのサービスを Select-Object コマンドレットに渡します。Select-Object コマンドレットでは、指定した Name プロパティと StartMode プロパティのみを出力します。このコマンドレットの実行の結果は、LocalSystem としてログオンしているサービスの単純なレポートです (このレポートはセキュリティ監査に使用できます)。

すべてのコマンドレットでは、共通のデータ形式 (オブジェクト) が使用されているので、複雑な文字列の解析を行うことなくデータを共有できます。Windows PowerShell にはオブジェクトのテキスト表記を作成する機能が備わっているので、このパイプの最後では、必ず人間が解読できるテキスト出力が提供されます。図 1 に、出力の例を示します。

図 1 オブジェクトを渡す一連のパイプされたコマンドレットによって生成されたテキスト出力

図 1** オブジェクトを渡す一連のパイプされたコマンドレットによって生成されたテキスト出力 **

パイプの魅力

Windows PowerShell のパイプが優れているのは、Windows PowerShell で扱うものが、すべてプロパティとメソッドを完備したオブジェクトであるからです。技術的には、テキスト ファイルもファイルの各行が一意で独立した文字列オブジェクトとして動作する文字列オブジェクトのコレクションです。たとえば、メモ帳を使用して、C:\Computers.txt という名前のテキスト ファイルを作成します。このファイルにテキストを入力し、Windows PowerShell で次のコマンドを実行します。

Get-Content C:\Computers.txt | Select-Object Length | Format-List

ここでも、次のようにエイリアスを使用して短い構文を使用することができます。

gc C:\Computers.txt | select Length | fl

このコードは、テキスト ファイルの各行の長さを文字単位で提示します。Get-Content がファイルから文字列オブジェクトを取得し、Select-Object が各オブジェクトの Length プロパティを取得し、Format-List が解読可能なテキスト出力を作成します。これは実用的な管理ツールではないかもしれませんが、Windows PowerShell では、テキスト行のように単純なものもオブジェクトであることは十分に実証できたと思います。

オブジェクトをコマンドレット間 (または、コマンドレットとスクリプトとの間) でパイプできることは、非常に強力な "一行スクリプト" を作成できることになります。このような一行スクリプトは、長いパイプラインに割り当てられ、必要なものを提供するように一連のオブジェクトの精度を上げる単純なコマンドレットの文字列です。Windows PowerShell のコマンドレットは、適切なパイプラインに連結することで、スクリプトやプログラムを作成することなく、優れた結果を出すことができます。

次世代の製品をサポートする

今後リリースされるマイクロソフトのサーバー製品が Windows PowerShell に基づいて構築されるという事実は、この機能の拡張を意味します。たとえば、Exchange Server 2007 コンピュータを新たに実装する場合、Windows PowerShell を使用して、すべてのメールボックスを取得し、新しいメール サーバーを配置するオフィスで使用しないメールボックスをフィルタアウトし、該当メールボックスを新しいサーバーに移動することができます。この作業は、スクリプトを作成することなく、1 行のテキストを記述するだけで行えます。Exchange Server 2007 チームは、強力な一行スクリプトの詳細な一覧を公開しました。このページでは、パイプラインの威力とパイプラインを使用して行える管理作業を紹介しています。

Windows PowerShell を使いこなすには、この新しいツールが UNIX の世界で長い歴史を持つ原理と哲学に基づいて構築されてはいるが、Windows の管理に非常に適しているということを理解することが欠かせません。共通の用語があるという理由で、Windows PowerShell が UNIX シェルの単なる Windows 用の模造品であるとは思わないでください。Windows PowerShell には Windows プラットフォームを活用するための斬新な概念が取り入れられており、Windows での物事のやり方と密接に一体化しています。

Don Jones は Windows PowerShell MVP で、『Windows PowerShell 101**』(ScriptingTraining.com) の著者でもあります。連絡先は、www.ScriptingAnswers.com (英語のみ) です。

© 2008 Microsoft Corporation and CMP Media, LLC. All rights reserved; 許可なしに一部または全体を複製することは禁止されています.