Windows PowerShell独自のソフトウェア インベントリ ツールを開発する

Don Jones

目次

情報を検出する
プロトタイプを作成する
コンピュータ名を読み取る
モジュール化
パイプライン関数

今月の Windows PowerShell コラムでは、非常に実用的な用途をご紹介します。今月は、一連のコンピュータについて、オペレーティング システムのビルド番号 (これはオペレーティング システムのバージョンを特定する最適な情報の 1 つです) とサービス パックのバージョン番号を一覧表示するツールを作成します。ですが、このソリューションについて、すぐに説明するつもりはありません。ソリューションについて説明する前に、このスクリプトの記述に至る過程を説明します。

このツールは間違いなく便利なものですが、それよりも、このツールの開発プロセスが重要であると考えています。このプロセスを理解して、皆さんが必要な作業で、この開発プロセスを再利用できるようになれば、Windows PowerShell を使用して、管理上のあらゆる問題を解決できる状態に、また一歩近付いたことになります (「ツールの開発方法を教えれば…」とは、よく言ったものですよね)。では、本題に入りましょう。

情報を検出する

(多くの場合は一番厄介な作業ですが) 最初に行う作業は、オペレーティング システムとサービス パックのバージョン番号を検出できる場所を特定することです。レジストリを調べようと思っている方がいらっしゃるかもしれませんね。確かにレジストリを参照すると、このような情報を入手できることもありますが、レジストリを処理するのは、少し厄介なので、私の中ではレジストリを参照するのは最終手段です。

「情報」と「取得する」という言葉から、私の頭には瞬時に解決策の候補が浮かびました。そして、その解決策は Windows Management Instrumentation (WMI) を使用することでした。「リモート」という言葉も WMI を連想させます。というのも、Windows PowerShell のバージョン 1 では、リモートで情報を一覧表示したり、管理したりするには、WMI を使用するしかなかったからです。

困ったことに、大半の Windows システムには何万もの WMI クラスがあるため、必要な情報を保持している WMI クラスを探すのは困難です。通常、私は、まずインターネット検索エンジンを使用し、「wmi サービス パック バージョン番号」のようなフレーズを入力して検索を行います。的確な検索結果を得るには、比較的長い検索フレーズが必要になります。

いくつかの異なる検索用語を試さなければならない場合もありますが、省略形は使用しないでください (「wmi sp バージョン」という検索フレーズを使用しても、あまり有益な検索結果を得ることはできません)。別の表現を使用することを検討してください。たとえば、皆さんが「パッチ」と呼んでいるものを、「ホットフィックス」と呼ぶ人がいたり、「quick fix engineering」や「qfe パッチ」と呼ぶ人がいたりします。最適な検索結果を得るには、このような用語をすべて試すことが必要になる場合もあります。

コンピュータ ハードウェアや主要な Windows OS に関連する WMI クラス名の大半は Win32_ で始まります。ですから、このようなものに関する情報を検索している場合には、検索フレーズに「Win32」という用語を追加すると役立ちます。現在の検索文字列に Win32 という用語を追加すれば、間違いなく最適な結果を得られるでしょう。そして、検索結果には、タイトルに Win32_OperatingSystem という文字列を含むページが何件かありました。これは WMI クラスの名前です。

ここで重要なのは、安易に検索結果のリンクをクリックしないことです (このような操作を行うと、混乱を招きます)。まず、このクラスのドキュメント ページを検索したいので、先ほどの検索結果で特定したクラス名を使用して、新たに検索を実行します。通常、クラス名で検索すると、検索結果の先頭から数件目までに msdn.microsoft.com の Web サイトのリンクが表示されます。このリンクをクリックすれば、WMI クラスのドキュメント ページにアクセスできます。

図 1 は、このようなページの一部を示したものです。ここでは、特に重要な表がある位置までスクロールしました。この表には、このクラスが対応している OS のバージョンが一覧されています。何かを達成するために苦労をした結果、私が使用しているバージョンの Windows では、そのもの自体が存在しないことが判明したという悲惨な目には何度遭ったことかわかりません。このような経験から、私は、まず、この表を確認することを覚えました。

fig01.gif

図 1 WMI クラスに関する情報を調べる (画像をクリックすると拡大表示されます)

このページを少し上にスクロールすると、ここで必要な BuildNumber および ServicePackMajorVersion という 2 つのプロパティに関する記述があります。ServicePackMinorVersion プロパティも役に立つかもしれませんが、私は 2.1 というようなサービス パックのバージョン番号は見たことがありませんので、ここでは割愛します。ですが、万全を期すなら、これも確認する価値のあるプロパティでしょう。

今月のコマンドレット : Export-CliXML と Import-CliXML

Windows PowerShell では、オブジェクトの静的なスナップショットを特殊な XML 形式で格納して、オブジェクトの情報をファイルに保持して、後でメモリに読み込んで調査を行うことができます。次のようにオブジェクトを Export-CliXML コマンドレットにパイプして、オブジェクトの情報をファイルに格納できます。

Get-Process | Export-CliXML c:\processes.xml

このようなオブジェクトは、後でシェルにインポートして、他のオブジェクトと同じように調査することができます。これは実際のオブジェクトではありませんが、このようなオブジェクトを使用すると、レポート オプションの幅が広がります。なんらかのメンテナンス作業を実行している午前 3 時に指定のサーバーですべてのプロセスをエクスポートするスクリプトをスケジュールしたとしましょう。翌朝、出勤したら、次のように、エクスポートされたプロセスを読み込んで内容を確認し、仮想メモリの使用量に基づいてプロセスを並べ替えることができます。

Import-CliXML c:\processes.xml | Sort VM -descending

プロトタイプを作成する

次の作業に入る前に、これらのプロパティで必要な情報が提供されることを確認したいと思います。Windows PowerShell を使用すると、このような処理を簡単に行うことができます。まず、次のように、私のローカル コンピュータで、この情報を確認してみることにしました。

Get-WmiObject Win32_OperatingSystem | Select BuildNumber,ServicePackMajorVersion,ServicePack­MinorVersion

マイナー バージョンは 0 で、これは予想どおりの結果です。ですから、マイナー バージョンについては忘れることにしましょう。それ以外の情報についても、期待どおりのものが得られました。Windows Server 2008 コンピュータのビルド番号は 6001 で、サービス パックのバージョンは 1 でした。

今度は、同様のテストを、私が管理者になっているリモート コンピュータに対して実行します。

Get-WmiObject Win32_OperatingSystem –computer Server2 | Select BuildNumber,ServicePackMajorVersion

このテストがエラーになる場合は、次の作業に進む前に、作業を中断して、その原因を特定する必要があります。発生する問題は、Windows PowerShell の管理下にない接続、ファイアウォール、アクセス許可に関する可能性が高いことが考えられます。すべての処理が正常に実行されることを確認したら、次は、ファイルに記載されている一連のコンピュータ名を取得する方法を調査したいと思います。

コンピュータ名を読み取る

コンピュータの一覧が記載されているテキスト ファイルがあって、1 行に 1 台のコンピュータ名が記載されている場合は、Get-Content コマンドレットを使用すると、一番簡単にコンピュータ名を読み取ることができます (コンピュータ名がテキスト ファイルに記載されていなかったり、1 行に 1 台のコンピュータ名が記載されていなくても心配しないでください。今後のコラムで、別の状況に対応するテクニックをご紹介しますから)。

各コンピュータの名前は、個別の文字列オブジェクトとして返されます。Get-WmiObjectcmdlet コマンドレットには、–computerName パラメータという便利な機能があり、コンピュータ名のコレクションを受け取ることができます。ですから、次のコマンドを実行して、一連のコンピュータ名を取得できます。

$names = Get-Content c:\computernames.txt Get-WmiObject Win32_OperatingSystem –comp $names | Select BuildNumber,ServicePackMajorVersion

ここでは、このコマンドの出力結果が数値の一覧であり、どの番号がどのコンピュータに対応しているのかわからないという問題があります。さいわい、Win32_OperatingSystem クラスには、偶然にも、コンピュータ名が格納されている CSName という名前のプロパティがあります。ですから、このプロパティを出力に含めると、希望どおりの一覧を作成することができます。

$names = Get-Content c:\computernames.txt Get-WmiObject Win32_OperatingSystem –comp $names | Select CSName,BuildNumber,ServicePackMajorVersion

モジュール化

ここまで紹介した内容は、経験の浅い方が使用するには難易度が高すぎたかもしれません。そこで、最後に、ここまで紹介した内容を関数としてモジュール化することにしましょう。その 1 つの方法としては、次のようにファイル名を受け取る関数を記述し、その関数ですべての処理を行うことができます。

Function Get-SPInventory ([string]$filename) { $names = Get-Content $filename Get-WmiObject Win32_OperatingSystem –comp $names | Select CSName,BuildNumber,ServicePackMajorVersion }

ご覧のとおり、ここでは単に作業コードを Get-SPInventory という名前の関数でラップしただけです。これは $filename という名前の入力パラメータを使用して定義したので、次のように呼び出すことができます。

Get-SPInventory c:\computernames.txt

この結果は、通常の Windows PowerShell コマンドを使用して、CSV ファイルにパイプしたり、HTML に変換したり、別の形式に合わせて変更したりすることができます。その一例を次に示します。

Get-SPInventory c:\computernames.txt | Export-CSV SPInventory.csv

しかし、まだ完璧ではありません。Win32_OperatingSystem クラスが保持していない、各コンピュータの BIOS シリアル番号などの情報も一覧に含める場合はどうしたら良いでしょうか。多くの Configuration Management Database (CMDB) では、BIOS シリアル番号をコンピュータの一意な ID として使用しているので、このような情報を一覧に含めることができたら便利です。

この関数の出力結果に、もう少し柔軟性を持たせて、結果をもう少し簡単に並べ替えたり、フィルタ処理したりできるようにできたら便利だと思っています。このようにすると、たとえば、最終的な出力結果には、古いバージョンのサービス パックが適用されている Windows Server 2003 コンピュータのみを含め、更新する必要があるコンピュータの一覧を作成することができます。

パイプライン関数

今度は、先ほどの関数を書き直して、Windows PowerShell のパイプ処理に適したものにしたいと思います。具体的には、パイプ処理で直接コンピュータ名を受け取れるようにします。このようにすると、この関数を使用するときに、コンピュータ名をどこから取得するのかを指定できるようになります。コンピュータ名はファイルに記載されている場合もあれば、Active Directory に格納されている場合もあり、どちらの場合も、この関数で処理できるようにする必要があります。パイプ処理に対応できるように記述し直した関数は次のようになります。

Function Get-SPInventory { PROCESS { $wmi = Get-WmiObject Win32_OperatingSystem –comp $_ | Select CSName,BuildNumber,ServicePackMajorVersion Write-Output $wmi } }

この特殊な関数では PROCESS スクリプト ブロックを使用しています。このブロックは、関数にパイプする各パイプライン オブジェクトに対して 1 回実行されます (このコラムの熱心な読者の方は、2008 年 7 月号のコラム (technet.microsoft.com/magazine/cc644947.aspx) で PROCESS スクリプト ブロックについてお話ししたことを覚えていらっしゃいますよね)。特殊な &_ 変数には、パイプ処理で渡されたものが自動的に代入されます。とりあえず、コンピュータ名をパイプする場合には問題なく動作します。この新しい関数は、次のように使用します。

Get-Content c:\computernames.txt | Get-SPInventory

ご覧のとおり、この関数では、コンピュータ名を異なるソースから取得するという柔軟性を実現することができました。ここでは単に Get-Content コマンドの部分を、コンピュータ名を取得するのに必要なコマンドに置き換えただけです。また、出力結果を作成する前に、さまざまな WMI クラス (または他の任意のデータ ソース) をクエリして、より堅牢な出力結果を作成できるようにもしました。

このトピックは、これで終わりではありません。来月のコラムでは、この関数を拡張して、出力に BIOS シリアル番号を含める方法を紹介します。

Don Jones は、Concentrated Technology の共同創設者で、IT 関連の書籍を多数執筆しています。www.ConcentratedTech.com で、Don は、毎週 WindowsPowerShell に関するヒントを紹介しています。また、このサイトから、Don に連絡を取ることもできます。