Windows PowerShell見栄えの良い出力

Don Jones

多くの人が見栄えの良い出力を作成するスクリプトを望んでおり、よく、テーブルのような出力を作成するのに最も良い方法についてたずねられます。これには、実際にいくつかの方法があります。最初の手順では、書式設定された形で表示するデータを次の名前の付いた変数に変換するスクリプトを書きます。

$data1、$data2、および $data3。これで、データの書式設定を始める準備が整いました。

テキストの特徴

Web 上

今月の Windows PowerShell のコラムに紹介されている手法の簡単なデモンストレーションをご覧になりたい方は、technetmagazine.com/video にアクセスして、Don Jones によるこれらのコマンドレットの実行を参照してください。

この作業を行う際に最も一般的に取られる方法は、VBScript、Perl、KiXtart、またはその他のテキスト指向の言語などで作業する場合と同じになる傾向があります。画面に列のヘッダーのセットを書くことから始めます。

Write-Host "ColumnA'tColumnB'tColumnC"

Windows PowerShellTM では、"`t" はタブ文字を挿入する特別なエスケープ シーケンスであることに注意してください。データが $data1、$data2、および $data3 であることを考慮に入れると、テーブルの各行を書くには、いくつかの選択肢があります。1 つは、変数を二重引用符で囲まれたコンテンツに置換するシェルの機能を利用して、変数を記述する方法です。

Write-Host "$data1't$data2't$data3"

もう 1 つの、より魅力的な方法は –f 演算子を使用する方法です。この手法では、データから書式設定を分離して、読みやすく、維持が簡単なコード行を作成します。

Write-Host "{0}'t{1}'t{3}" –f $data1,$data2,$data3

しかしながら、これらの方法には重大な問題があります。まず、コンソール ウィンドウで固定されたタブ ストップを使用することにより、おかしな書式設定になってしまう可能性があります。たとえば、あるテーブルの最初の列の行に 20 文字分のデータが含まれていると、その行の書式設定全体がおかしくなってしまいます。また、Write-Host を使用してテキストを出力するため、コンソール表示の制限の影響を受けてしまいます。

ファイルや他の形式で出力する簡単な方法はなく、あまりお勧めしません。最も重要なことは、このテキストベースの方法では、私が専門としている本質的なオブジェクトベースのシェルが完全に無視され、Windows PowerShell のすばらしい技法や機能を活用できない点です。

Windows PowerShell の特徴

Windows PowerShell はオブジェクト指向のシェルです。つまり、理想を言うならば、扱う対象をすべてオブジェクトにするべきです。そうすれば、必要な場合はシェルによってテキスト表示に変換されます。しかし、任意のデータに対して、どのようにしてオブジェクトを作成したらよいのでしょうか。

先ほどの例を使って、空白のカスタム オブジェクトを作成して、それを変数の中に格納します。

 $obj = New-Object PSObject

これで、新しい空のオブジェクトを使って作業を進めることができます。次に、データをプロパティの形にしてこのオブジェクトに追加します。単純に、オブジェクトを Add-Member コマンドレットにパイプするだけです。NoteProperty と呼ばれるものを追加し、プロパティに名前を付け (列のヘッダーをプロパティ名として使用することをお勧めします)、データをプロパティの値として挿入します。

 $obj | Add-Member NotePropertyColumnA $data1
$obj | Add-Member NotePropertyColumnB $data2
$obj | Add-Member NotePropertyColumnC $data3

次に、オブジェクトをコンソールではなく、パイプラインに出力します。

Write-Output $obj

出力するテーブルの行ごとに、これらの手順を繰り返します。以下は、文字列を受け取り、元の文字列と共に大文字と小文字のバージョンを出力する短い関数です。

functionStringVersions {
param([string]$inputString)
  $obj = New-Object PSObject
  $obj | Add-Member NoteProperty Original($inputString)
  $obj | Add-Member NoteProperty Uppercase($inputString.ToUpper())
  $obj | Add-Member NoteProperty Lowercase($inputString.ToLower())
  Write-Output $obj
}  
$strings = @("one","two","three")
foreach ($item in $strings) {
StringVersions $item
}

文字列変数の配列から始めて、これらを 1 つずつ関数に送ります。関数の出力がパイプラインに書き込まれます。

これより短いコードを書く方法もありますが、強調したい点を明確に表すためにこの手法を選びました。図 1 は、完全に書式設定されたテーブルの出力を示しています。シェルがテーブル内のオブジェクトを書式設定する方法を既に知っているからです。

図 1 テーブルに表示された Windows PowerShell の出力

図 1** テーブルに表示された Windows PowerShell の出力 **(画像を拡大するには、ここをクリックします)

オブジェクト内のプロパティが 4 つ以下の場合、Windows PowerShell は自動的にテーブルを選択します。したがって、特に何もしなくても、見栄えの良いテーブルが完成しました。

しかし、この機能は、これだけではありません。

今月のコマンドレット : Get-Command

利用可能な Windows PowerShell コマンドレットの一覧を見るために、Get-Command または使いやすいエイリアス (gcm) を 1 度か 2 度は使用した経験があるかと思います。しかし、実際に gcm にどれほどの柔軟性があるかは、まだご存じないかもしれません。たとえば、Windows PowerShell がサービスに関してできることをすべて表示する場合は、gcm -noun service を実行します。また、Windows PowerShell のエクスポート オプションをすべて表示する場合は、gcm -verb export を実行します。PowerShell Community Extensions など、特定のスナップインによって追加されたコマンドレットを表示する場合は、gcm -pssnapin pscx を実行します (特定のスナップインのコマンドレットを表示するには、"pscx" の部分を該当するスナップイン名に置き換えます)。

ご覧のとおり、Get-Command は Windows PowerShell の検出における中心的存在です。これを使用することにより、マニュアルを手にしなくても、利用できる機能を調べることができます。また、機能を検出する際に Help * などのコマンドを使用するよりも gcm を使用する方が正しい結果を得られます。Help 関数は、用意されているヘルプ トピックを一覧表示するだけです。必要なコマンドレットが存在していても、それがヘルプと共に出荷されていない場合はヘルプの一覧に表示されません。

この手法のメリットはテーブルだけにとどまりません。オブジェクトを扱う場合、Windows PowerShell が実行できる機能の範囲は多岐に及びます。データを CSV ファイルに出力する場合は、Export-CSV を使用します。HTML 形式のテーブルに出力する場合は、オブジェクトを ConvertTo-HTML にパイプします。箇条書きの書式で出力する場合は、オブジェクトを Format-List にパイプします。オブジェクトを使用することにより、シェルが既に知っている方法をすべて利用することができます。次に、先ほどの例を書き換えたものを示します。

functionStringVersions {
  PROCESS {
   $obj = New-Object PSObject
   $obj | Add-Member NoteProperty Original($_)
   $obj | Add-Member NoteProperty Uppercase($_.ToUpper())
   $obj | Add-Member NoteProperty Lowercase($_.ToLower())
   Write-Output $obj
}
}

今回は、オブジェクトを扱う場合にお勧めする方法として、パイプラインの入力を受け取り、パイプラインに出力するように関数を変更しました。

この関数は、PROCESS スクリプト ブロック内にコードを含んでいます。つまり、関数はパイプラインの入力を受け取り、パイプされたオブジェクトごとに PROCESS スクリプト ブロックを 1 回実行します。

PROCESS スクリプト ブロック内では、特殊な $_ 変数によって、処理中の現在のパイプライン オブジェクトが参照されます。この実用的な結果として、単純に文字列の配列をパイプすることができるようになりました。

@("one","two","three") | StringVersions

関数の出力がパイプラインに書き込まれるため、テーブルが作成されます。パイプラインの最後に、シェルは書式設定のサブシステムを呼び出すことを知っており、パイプライン内のオブジェクトのプロパティの数が 5 よりも少ないため、テーブルを使用する決定が下されます (プロパティの数が 5 以上の場合、既定では、シェルは箇条書きを使用します)。

しかし、既定の動作を使用する必要はありません。他の形式に出力する場合は、これらのオブジェクトを別のコマンドレットにパイプすればよいのです。

@("one","two","three") | StringVersions | Format-List
@("one","two","three") | StringVersions | ConvertTo-HTML | Out-File "strings.html"
@("one","two","three") | StringVersions | Export-CSV "strings.csv"
@("one","two","three") | StringVersions | Select Uppercase,Lowercase -unique

図 2 は、2 番目の例で出力された HTML を Web ブラウザで表示したものです。出力データを単純なテキストではなく、オブジェクトとして表すだけで、さまざまな書式設定のレイアウト、HTML 変換、エクスポート オプション、並べ替え/フィルタ処理/グループ化の機能、その他シェルに組み込まれた数多くの豊富な機能を利用することができるようになります。

図 2 Windows PowerShell による HTML 形式でのデータ出力

図 2** Windows PowerShell による HTML 形式でのデータ出力 **(画像を拡大するには、ここをクリックします)

これは非常に強力なツールです。実際、スクリプトを記述する場合は、オブジェクトをその出力として作成すべきであると勧めています。これにより、コードを 1 行すら追加することなく、可能な限り多様な方法で出力を作成することができます。

Don Jones は Windows 管理の自動化の専門家で、『Windows PowerShell: TFM』、『VBScript, WMI, and ADSI Unleashed』などの書籍を執筆しています。Don に対するお問い合わせについては、彼の Web サイト フォーラム (ScriptingAnswers.com) にアクセスしてください。

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