Windows PowerShellドロップ ボックス

Don Jones

目次

コマンドレット
フィルタ処理関数
物理的考察
実践的応用
遊ぶ時間を作る

私が最近講師を務めた Windows PowerShell のあるクラスで、数人の受講者がシェルのパイプラインを理解するのに苦労していました。パイプラインの概念は直感的に理解できるとは言えないため、視覚的に理解しようとする受講者がパイプラインを正確に把握するのは困難です。私が

パイプラインで直接機能するフィルタ処理関数の概念を説明したとき、受講者の表情から間違いなく数人の受講者を失うだろうと思いました。

受講生をサポートするために、翌日、私は箱、名前シール、そしてピンポン球を持って行きました。これで、Windows PowerShell® が楽しいはずがないと言う受講者はいなくなりました。私は次のコマンド ラインを使用してデモンストレーションを実施することにしました。

Get-Process | Where { $_.VM –gt 1000 } | Sort VM –descending | Export-CSV C:\Procs.csv

コマンドレット

同窓会などのイベントで身に着ける「こんにちは。私の名前は...です。」のような名札シールを使用して、コマンドレット名を各受講者に割り当てました。ピンポン球は Windows® プロセス オブジェクト (具体的には、System.Diagnostics.Process 型のオブジェクト) を表すことを説明しました。その後、受講者にプロセス オブジェクトを生成する可能性が最も高いコマンドレット名を私に伝えるように言いました。

受講生は互いの名札を見回して、Get-Process という明白な選択に落ち着きました。これは、Windows PowerShell のコマンドレット名を私が本当に好きな理由の 1 つを示しています。つまり、ほとんどの場合、一目瞭然であるということです。

Get-Process の名札を付けた受講生は、すべてのピンポン球をつかみ、段ボール箱に入れました。箱はシェルのパイプラインを表し、受講生が行った操作がまさにコマンドレットの処理です。コマンドレットは 1 つ以上のオブジェクトを生成し、それをパイプラインに渡します。

パイプラインの次のコマンドレットが処理を引き継ぎます。この例では、Where-Object コマンドレットの名札を付けた受講者がすべてのピンポン球を拾い上げ、1 つずつ調べてピンポン球の VM プロパティが 1,000 より大きいかどうかを確認しました。シェルでは、"VM" は仮想メモリを表します。この演習では、私は各ピンポン球にマーカーで仮想メモリのさまざまなサイズを記入しました。

VM が 1,000 以上のすべてのピンポン球 (つまりプロセス) を箱 (パイプライン) に戻し、1,000 未満のピンポン球を再び現れないようにゴミ箱に捨てました (実際には、私はこれらのピンポン球を今後のクラスで使用できるようにゴミ箱の中から拾いだしました)。

次に、Sort-Object の名札を付けた受講生がピンポン球の箱を調べて、VM プロパティに基づいてピンポン球を順番に並べました。正直に言うと、この部分の演習は、考慮が足りませんでした。ピンポン球があちこちに転がらないようにするのに注意が必要でした。次のクラスでは四角いピンポン球を探すか、卵のケースを手元に置いておく必要があるようです。

最後に、Export-CSV の名札を付けた受講者がピンポン球を拾い上げて、その情報を CSV ファイルに書き込みました。実際には、これは CSV ファイルで代用したフリップ チャートにプロセスのプロパティを書き込むことになります。

フィルタ処理関数

簡単なパイプラインから少し離れて、もう少し複雑なフィルタ処理関数を考察することにしました。私は図 1 に示すフィルタ処理関数とコマンド ラインを提示しました。

図 1 フィルタ処理関数とコマンド ラインのサンプル

Function Do-Something { BEGIN { } PROCESS { $obj = New-Object PSObject $obj | Add-Member NoteProperty "TimeStamp" (Get-Date) $obj | Add-Member NoteProperty "ProcessName" ($_.Name) Write-Output $obj } END {} } Get-Process | Do-Something | Format-Table *

まず、フィルタ処理関数が行う処理について簡単に説明します。この関数には BEGIN、PROCESS、および END という名前の 3 つのスクリプト ブロックがあります。

パイプラインで関数を使用すると、まず BEGIN スクリプト ブロックが実行されます。このスクリプトは、データベース接続を開くなどのセットアップ タスクを実行することがあります。

次に、PROCESS スクリプト ブロックが関数に渡されたオブジェクトごとに 1 回実行されます。PROCESS スクリプト ブロック内では、$_ 変数に現在のパイプライン オブジェクトが自動的に格納されます。したがって、10 個のオブジェクトが渡された場合、PROCESS スクリプト ブロックは 10 回実行されます。

最後に、渡されたすべてのオブジェクトの実行後、END スクリプト ブロックが実行され、データベースを閉じるなどの必要な後処理が実行されます。

これらのスクリプト ブロック内では、Write-Output を使用して書き込まれたすべてのものがパイプラインで次のコマンドレットに渡されます。Write-Output を使用して書き込まれなかったものはすべて破棄されます。

コマンドで Get-Process が開始されると、受講生はすべてのピンポン球を集めて (少し休憩した後、ピンポン球はなぜか部屋中に転がっていました。不思議です)、それをパイプラインの箱に入れました。作業が完了すると、"Do-Something" フィルタ処理関数の名札を付けた受講者が引き継ぎました。

彼は、まず BEGIN スクリプト ブロックを実行しました。ブロックは空だったので、あまり手間はかかりませんでした。次に、彼はすべてのパイプライン オブジェクト (ピンポン球) をつかみ、1 つずつ確認し始めました。1 ダースほどのピンポン球を膝の上に置いてバランスをとろうとしていた彼はとても愉快でした。あなたもその場にいたらよかったのに。

とにかく、彼はプロセス オブジェクトを 1 つずつ拾い上げて PROCESS スクリプト ブロックを実行しました。そのスクリプト ブロックによって新しいカスタム オブジェクトが作成されました。私はこのために特別な黄色いピンポン球を使用しました。これは地元のスポーツ用品店で簡単に見つけられるものではありません。彼はこれらの新しいピンポン球に、現在の日時と現在確認しているプロセス オブジェクトの名前を記入しました。

この新しいカスタム オブジェクトはパイプラインに書き込まれました。つまり、彼は黄色のピンポン球を箱の中に入れました。元のプロセス オブジェクトのピンポン球は破棄されました。彼は箱に入っている合計 1 ダースほどのプロセス オブジェクトのピンポン球それぞれに対してこの操作を行いました。操作が完了すると、白の各ピンポン球が黄色のカスタム オブジェクトのピンポン球に置き換えられました。最後に、彼は END スクリプト ブロックを実行しました。このブロックは空だったので時間はかかりませんでした。

締めくくりに、Format-Table の受講生が処理を引き継ぎました。彼女は箱の中のすべてのピンポン球 (この時点ではすべて黄色の "カスタム" オブジェクト) を拾い上げ、各ボールに書き込まれた両方のプロパティを使用して表を作成し始めました。フリップ チャートに書き込んだところ、TimeStamp と ProcessName の 2 つの列を持つ行が 12 行ほどある表ができました。

物理的考察

この演習のパイプラインとフィルタ処理関数は、クラスの受講生全員の心を捉えました。ピンポン球は、オブジェクトを表すという大きな役割を果たしました。オブジェクトは、シェルについてただ話をするときは抽象的になりがちです。

コマンドレットがこれらのオブジェクトを操作する方法、結果がパイプラインに渡される方法、および次のコマンドレットが結果を取得し、さらにオブジェクトを操作する方法を全員が理解できました。PROCESS スクリプト ブロックが入力オブジェクトを 1 つずつ処理する手法と同様に、フィルタ処理関数のイベント シーケンスはさらに明白でした。

これは、新しいカスタム オブジェクトを作成し、パイプラインに渡す方法も示しました。さらに、単純なテキストではなくカスタム オブジェクトを作成する利点も示しました。利点とは、新しいカスタム オブジェクトは Format-Table などの他のコマンドレットでも使用できるため、後でデータを柔軟に使用したり表示したりできるということです。

実践的応用

受講生からの明白な質問は、デモンストレーションで示したパイプラインとこれらのフィルタ処理関数を実際のアプリケーションでどのように使用できるか、ということでした。私にとってその答えは簡単でした。最近開催された会議のためにいくつかの例を作成していたからです (これらの例は scriptinganswers.com/essentials/index.php/2008/03/25/techmentor-2008-san-francisco-auditing-examples からダウンロードできます)。

ある例は、複数のコンピュータから Windows Management Instrumentation (WMI) の Win32_UserAccount クラスのプロパティ一覧を取得することを目的としています。コンピュータ名の一覧が C:\Computers.txt にある場合は、次の単純なコマンドでこの処理を行うことができます。

Gwmi win32_useraccount –comp (gc c:\computers.txt)

問題は、Win32_UserAccount クラスに各インスタンスを呼び出したコンピュータを通知するプロパティが含まれていないということです。したがって、多くのコンピュータのアカウントが混在する役に立たない一覧が生成されます。私はこの問題を解決するために、呼び出し元のコンピュータ名を含む新しいカスタム オブジェクトを作成し、必要なクラス プロパティを選択します。このカスタム オブジェクトのコードを図 2 に示します。

図 2 カスタム オブジェクトを使用したコンピュータ名の収集とプロパティの選択

function Get-UserInventory { PROCESS { # $_ is a computer name $users = gwmi win32_useraccount -ComputerName $_ foreach ($user in $users) { $obj = New-Object $obj | Add-Member NoteProperty Computer $_ $obj | Add-Member NotePropertyPasswordExpires ($user.PasswordExpires) $obj | Add-Member NoteProperty Disabled ($user.Disabled) $obj | Add-Member NotePropertyFullName ($user.FullName) $obj | Add-Member NoteProperty Lockout ($user.Lockout) $obj | Add-Member NoteProperty Name ($user.Name) $obj | Add-Member NotePropertyPasswordRequired ($user.PasswordRequired) $obj | Add-Member NotePropertyPasswordChangeable ($user.PasswordChangeable) } } } Get-Content c:\computers.txt | Get-UserInventory | where { $_.PasswordRequired -eq $False } | selectComputer,Name | Export-Csv c:\BasUsersBad.csv

最後のコマンド ラインは、すべてのコンピュータ名をフィルタ処理関数に渡してカスタム オブジェクトを作成します。次に、PasswordRequired プロパティが False であるユーザー以外のすべてのユーザーを除外しました (問題のあるアカウントの監査レポートを作成するためです)。そして単純に Computer プロパティと Name プロパティを保持し、無期限のパスワードを持っているため注意が必要なコンピュータ名とアカウント名の一覧が最終的なレポートに含まれるようにします。フィルタ処理関数によって、このマルチコンピュータ レポートの作成が可能になります。フィルタ処理関数は、呼び出し元のコンピュータ名を出力に追加し、表示する必要のないプロパティを削除するからです。

同じようにこのタスクを実行できる方法は他にもありますが、この方法がおそらく最も簡単でしょう。この方法は、重要な概念や手法を示すのにも役立ちます。

遊ぶ時間を作る

パイプラインに慣れている場合でも、ここで学ぶべき教訓があります。物理的なオブジェクトの観点で考察すると、自分が何をしようとしているかを把握するのに役立ちます。

したがって、Windows PowerShell の概念に苦労する場合は、コンピュータから一歩離れて、日常的なものを使用してタスクを再現してみてください。そのためにピンポン球 (または、見つかった場合は四角いピンポン球) を入れた小さなバッグを手元に置いておくことをお勧めします。

今月のコマンドレット : Out-File

> 記号を使用してコマンドレットの出力をファイルにリダイレクトしたことが何回ありますか。つまり、Get-Process > Processes.txt などのリダイレクトです。実際には Out-File コマンドレットを使用していることをご存じですか。上記と同じ機能を実行するコマンドは、Get-Process | Out-File Processes.txt です。

もちろん、入力する文字の数は増えます。では、なぜわざわざ完全な Out-File コマンドレットを入力するのでしょうか。その理由の 1 つは、Out-File の方が読みやすいということです。たとえば 6 か月後に来た人があなたのスクリプトを見て、> が何を表しているのだろうと思うことがあります (やはり、> は古い方法なのです)。

一方、Out-File を使用すると、ファイルが作成されて書き込まれることが一目瞭然です。さらに、-force パラメータや -noClobbe パラメータと共に -append パラメータ (>> と同じ) を使用することで、既存のファイルを上書きするかどうかを指定できます。最後に、Out-File を入力すると -whatif パラメータを使用することもできます。この便利なパラメータは、Out-File の処理内容を実際には処理を行わずに表示します。このすばらしい方法を使えば、ほとんど危険を冒すことなく複雑なコマンド ラインをテストできます。

Don Jones は『Windows PowerShell: TFM』の共著者で、Windows PowerShell のクラス (www.ScriptingTraining.com) の講師も務めています。

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