Doctor Scripto のスクリプト ショップ

Windows XP Service Pack のインベントリ作成 - 第 1 部

公開日: 2005年7月14日
Microsoft Scripting Guys

作業中の Doctor Scripto

読者の皆さんからのご要望にお応えして、Scripting Guys は仮想の Scripting Guy、Dr. Scripto の才能を紹介する新しいコラムを立ち上げることにしました。皆さんは彼の歌やつまらない冗談を聞いたことがあると思いますが、ようやく今回から、白衣をまとった小柄な彼の技術的な一面に触れることができます。レドモンドにある Microsoft の敷地の頂上には、私たちの住む豪華なペントハウスがあります。その物置の中には、Dr. Scripto のスクリプト パーツや道具が備品として収められた、巨大な仮想の倉庫があります。彼と一緒にこの中を歩いてみることにしましょう。

Doctor Scripto のスクリプト ショップでは、読者の皆さんから寄せられる、実際のシステム管理スクリプトに関する問題を取り上げて、それらを解決するためのスクリプトを開発します。スクリプト倉庫にあるサンプルのほとんどは、簡単な作業を 1 つ実行するだけですが、このコラムではそれとは対照的に、それらのサンプルを組み合わせて、より複雑なスクリプトを作成します。これらは、何でもできる万能のスクリプトというわけではありません。しかし、これらのスクリプトを通じて、再利用可能なコード モジュールからスクリプトを作成する方法、エラーやリターン コードを処理する方法、さまざまなソースから入出力を行う方法、複数のコンピュータに対して実行する方法など、実際のスクリプトの中で実行してみたいテクニックを紹介します。

このコラムで紹介するトピックの多くでは、中級から上級のスクリプト技術が必要です。しかし、それらの技術をわかりやすく説明するように心掛けたいと思います。いつものように、スクリプトを作成する皆さんを置き去りにはしません。このコラムやここで紹介するスクリプトが皆さんのお役に立つことを期待します。ご意見、ご要望のほか、皆さんが問題解決のために編み出した方法や、今後取り上げてほしい話題などがありましたら、ぜひお知らせください (英語のみ)。

トピック

Windows XP Service Pack のインベントリ作成 - 第 1 部
Active Directory 以外のネットワークのインベントリ作成
テキスト ファイルからコンピュータの一覧を取得する
オペレーティング システムのバージョンとサービス パックを取得する
コンピュータをサービス パック別に並べる
データをテキスト ファイルに出力する
重大な問題
詳細情報

Windows XP Service Pack のインベントリ作成 - 第 1 部

2005 年 4 月 12 日が過ぎました。この日は休日ではなく、特に重要な意味を持つ日です (もちろん、世界のどこかでは休日かもしれませんが、私たちに限っては、この日が休みになることはありませんでした)。ほとんどのカレンダーではいつもの火曜日のようですが、Windows XP クライアントを管理しているシステム管理者にとっては、最後の審判とも言うべき日です。

なぜなら、4 月 12 日以降は、自動更新および Windows Update Services からの Windows XP Service Pack 2 の配布を無効にすることができないためです (詳細については、「Windows Update および自動アップデートによる Windows XP Service Pack 2 の配布を一時的に無効にする」を参照してください)。それまでは、レジストリの値を設定することによって、自動更新からの Windows XP クライアントへの Service Pack 2 の自動ダウンロードを無効にすることができました。この方法については、「Windows XP Service Pack 2 の配布を無効にする」で紹介しました。

しかし、2005 年 4 月 12 日以降は、このレジストリ設定は無視されます。ルイ 15 世の愛人であり、王室の管理者のような存在であったポンパドゥール夫人の不吉な言葉を借りれば、"Après nous, le Service Pack 2 (わが亡き後に Service Pack 2 よ来たれ)" といったところでしょうか。

一方で、スクリプト作成者にとっては、4 月 12 日は彼らの出番です。大量のアップグレードを管理するうえで、スクリプトがどれほど便利であるかを示す絶好の機会です。そして間違いなく、Dr. Scripto もこの機会を逃しはしません。

Scripting Guys の第一人者であり助言者である彼は、使い古したコードや作り直したコードのコレクションをくまなく調べ、役に立ちそうなものを見つけ出してそれらをまとめ、いやおうなしに配布される SP2 を管理するための究極のスクリプトにしあげました。

ここで誤解のないように言っておきますが、Service Pack 2 には、Windows ファイアウォールなど、セキュリティを強化するための便利な機能が組み込まれています。しかし、システム管理者にとっては、これらの機能を管理する方法を見つけ出すまで、それらの機能がじゃまになる可能性があります。そして、Service Pack 2 の既定の設定では、WMI や ADSI を使用したリモート管理が拒否されます。WMI や ADSI はシステム管理スクリプトの多くで必要な機能です。これらの機能のいくつかについては、以前のコラムや Web キャストで既に取り上げられています。このドキュメントの終わりにその一覧が掲載されています。

今回のコラムは Jeremy からアイデアを得ました。彼は南カリフォルニアに住む郡の相談役で、今回取り上げたトピックについて、数か月前に電子メールを送ってくれました。彼は、所属する組織のネットワーク上で Windows XP を実行しているクライアントのいくつかに Service Pack 2 をインストールしました。そして、アップグレードを必要とする残りのコンピュータを検索するスクリプトを作成したいと考えていました。そこで、私たちの議論が始まり、いくつかのアイデアが浮かびました。

IT 部門では Service Pack 2 の取り扱いについてさまざまな計画を立てていると思いますが、それがどのようなものであっても、インベントリを作成しておくことは、作業の手始めとして適切なものです。どのコンピュータで、どのオペレーティング システム バージョンと、どのサービス パックが実行されているのかを調べて、問題の範囲を把握しておけば、今回の更新プログラムがシステムに与える影響について、より性格に判断することができ、問題を整理して処理することができます。たとえば、4 月 12 日にネットワークが混乱しないように、SP2 を段階的にインストールすることが考えられます。また、既定の設定をそのまま受け入れるのではなく、IT 部門のニーズに応じて新しいファイアウォールの設定を変更することもできます。

この作業を支援するために、Dr. Scripto は、さまざまな種類のネットワーク上に存在するすべての Windows XP クライアントについて、その Service Pack の状態を把握するためのスクリプトをまとめました。

私たちは、スクリプトの仕様を決めた後 (コーディングの前に必ず仕様書を作成しますよね)、Windows XP SP2 に対応する準備方法を紹介するために、少なくとも 3 つのコラムが必要になると判断しました。今回の第 1 部では、Active Directory を使用していないワークグループまたはネットワークで Windows XP コンピュータのインベントリを作成する方法を紹介します。次回のコラムでは、Active Directory Service Interfaces (ADSI) と ActiveX データ オブジェクト (ADO) の両方を使用して、同じ作業を Active Directory で実行するスクリプトを紹介する予定です。そして、最後のコラムでは、作成したインベントリを使用して、ネットワークを引き続きリモートで管理できるような方法で SP2 を展開する方法についてお話しします。

その後は、定期的に更新されるコラムになり、そこで他のスクリプト作業について取り上げる予定です。

Active Directory 以外のネットワークのインベントリ作成

最初に、Active Directory を使用していないネットワーク上でインベントリを取得するという最も簡単なシナリオから見ていきましょう。この場合は、WMI を使用してオペレーティング システムとサービス パックのバージョンを調べます。この方法は Active Directory による方法と比べると高速ではありません。Active Directory ではこれらの情報がディレクトリに格納されているため、個々のコンピュータに接続しなくても情報を取得できます。しかし、WMI はほとんどの Windows スクリプト作成者にとって使い慣れた技術であるという利点があり、小規模のネットワークではこの方法で十分です。

Active Directory を使用しないため、検索するコンピュータの一覧をスクリプトに渡す必要があります。ここでは単純なテキスト ファイルを使用しますが、スプレッドシートやデータベースを使用することもできます。そして、結果についても別のテキスト ファイルに出力することにします。

テキスト ファイルからコンピュータの一覧を取得する

fso

入力用テキスト ファイルの名前を hosts.txt とし、1 行に 1 つずつコンピュータ名を記述します。これらのコンピュータはネットワーク上でアクセスできる必要があり、それらに対する管理者権限が必要になります (リモート コンピュータに対してスクリプトを実行するときは、通常この条件が必要です)。ファイルの内容は次のようになります。

client1
client2
client3
client4

頼りになる FileSystemObject を使用して、ファイルからコンピュータ名を取り出します (FileSystemObject は Windows スクリプト ホストに付属しているスクリプト ランタイムの一部です)。コードは次のようになります (多くの皆さんは、このようなコードを見慣れているので、眠たくなってしまうかもしれません)。

Const FOR_READING = 1
strFilename = "hosts.txt"
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextStream = objFSO.OpenTextFile(strFilename, FOR_READING)
Do Until objTextStream.AtEndOfStream
  strComputer = objTextStream.ReadLine
  Wscript.Echo "Use WMI to get OS and SP versions from " & strComputer
Loop

FileSystemObject の OpenTextFile メソッドは、実際にはテキスト ストリームを表すオブジェクトを返します。このオブジェクトは、AtEndOfStream プロパティや ReadLine メソッドなどの便利なプロパティやメソッドを持っており、ここではこれらを使用して一度に 1 行ずつ取り出します。

オペレーティング システムのバージョンとサービス パックを取得する

コンピュータのオペレーティング システムとサービス パックを調べるために、WMI クラス Win32_OperatingSystem の 3 つのプロパティである、Version、ServicePackMajorVersion、および ServicePackMinorVersion を使用します。

まず、対象のコンピュータ上の WMI に接続し、Win32_OperatingSystem クラスのインスタンスを問い合わせます (このクエリでは、常にインスタンスが 1 つだけ返されます。これは、現在実行されているオペレーティング システムです)。次に、これら 3 つのプロパティを表示し、ServicePackMajorVersion と ServicePackMinorVersion の間にピリオドをはさんで連結します。

'Get strComputer from each line of text file.
Set objWMIService = GetObject("winmgmts://" & strComputer)
Set colOSes = objWMIService.ExecQuery _
 ("SELECT * FROM Win32_OperatingSystem")
For Each objOS in colOSes
  Wscript.Echo
  Wscript.Echo strComputer
  Wscript.Echo "OS Version: " & objOS.Version
  Wscript.Echo "Service Pack: " & objOS.ServicePackMajorVersion & _
   "." & objOS.ServicePackMinorVersion
Next

これを実行すると、次のような出力が得られます。

client1
OS Version: 5.1.2600
Service Pack: 2.0

バージョン番号ではなくオペレーティング システムの名前を表示する場合は、Caption プロパティを使用できます。このプロパティの方が Version よりも多少読みやすいかもしれません。いずれの場合も、このスクリプトでは Windows XP だけを対象としています。

作成した 2 つのコンポーネントを 1 つにまとめることで、たとえば次の 4 台のコンピュータについて OS のバージョンとサービス パックを取得できます。出力は次のようになります。

C:\scripts>xpsplist-wmi.vbs 

client1
OS Version: 5.1.2600
Service Pack: 1.0

client2
OS Version: 5.1.2600
Service Pack: 2.0

client3
OS Version: 5.1.2600
Service Pack: 2.0

client4
OS Version: 5.1.2600
Service Pack:

これは簡単な WMI であり、多くの皆さんは間違いなく大あくびをして 2 杯目のコーヒーを欲しがっていることでしょう。しかし、これがスクリプト技術のすばらしいところです。一度覚えてしまえば後は決まりきった作業で済み、簡単に使うことができます。このコラムでは、このような単純なスクリプトを多少複雑で実用的な方法でまとめようとしていますが、それらのほとんどは既におなじみのものです。Dr. Scripto の永遠の格言である「怠惰であれ。わかりきったことを繰り返すな。」という言葉を忘れないようにしてください (IT 管理者は「怠惰」の部分を「生産的」と読んでください)。

コンピュータをサービス パック別に並べる

win32_os

ここで私たちが本当に必要としているのは、コンピュータをその OS バージョンやサービス パックと一緒に列挙しただけの単純な一覧ではありません。そうではなく、一覧に多少手を加えて、Service Pack 2 がインストールされているコンピュータ、Service Pack 1 がインストールされているコンピュータ、およびサービス パックがインストールされていないコンピュータ別に分かれた一覧を必要としています。そして、それぞれの台数がわかれば、今後の仕事量を知ることができるので便利です。

このような情報を取得するコードを次に示します。

'Get strComputer from each line of text file.
Set objWMIService = GetObject("winmgmts://" & strComputer)
Set colOSes = objWMIService.ExecQuery _
 ("SELECT * FROM Win32_OperatingSystem")
For Each objOS in colOSes
  If objOS.Version = "5.1.2600" Then
    If objOS.ServicePackMajorVersion = "2" Then
      strSP2 = strSP2 & strComputer & vbCrLf
      intSP2 = intSP2 + 1
    ElseIf "1" = objOS.ServicePackMajorVersion Then
      strSP1 = strSP1 & strComputer & vbCrLf
      intSP1 = intSP1 + 1
    Else
      strSP0 = strSP0 & strComputer & vbCrLf
      intSP0 = intSP0 + 1
    End If
  Else
    intNotXP = intNotXP + 1
  End If
Next

これで、Windows XP の各サービス パックを実行しているコンピュータの名前を、それぞれの台数と一緒に別々の変数に格納しました。また、Windows XP 以外のコンピュータについても別のカウンタに格納しました。

ちなみに、サービス パックがまったくインストールされていないことを明示的に調べる場合は、ServicePackMajorVersion = 0 をチェックします (Null ではありません。間違えないようにしてください)。ここでは、この条件を Else 句で処理していますが、今のところ問題なく動作しています。将来、別のサービス パックがリリースされた場合は、この Else 句に含めて、Windows XP 以外としてカウントすることになります。しかし、このコラムではコードを単純にしておくことも目的にしているので、将来の出来事への対応については見送ることにします。

データをテキスト ファイルに出力する

このデータを別のテキスト ファイルに出力するために、入力ファイルを読み取るコードの変形バージョンを使用します。ここでは、名前の付いたファイルが存在するかどうかをチェックします。存在する場合は、そのファイルを開いてデータを追加します。存在しない場合は、ファイルを作成してそこに書き込みます。次に、かなり旧式のテキスト書式化処理をいくつか追加します。Dr. Scripto のような古い開発者にとって、このようなコードは MS-DOS を思い出させます。テキスト ストリームは書き込みが終了したら忘れずに閉じる必要があります。これでテキスト ファイルが保存され、ファイルが閉じられます。

Const FOR_APPENDING = 8
strOutputFile = "xpsp.txt"
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strOutputFile) Then
  Set objTextStream = objFSO.OpenTextFile(strOutputFile, FOR_APPENDING)
Else
  Set objTextStream = objFSO.CreateTextFile(strOutputFile)
End If

objTextStream.WriteLine "Inventory of Windows XP Service Packs"
objTextStream.WriteLine "Taken " & Now
objTextStream.WriteLine vbCrLf & "Computers Running Windows XP"
objTextStream.WriteLine "============================"
objTextStream.WriteLine  "Total number: " & (intSP2 + intSP1 + intSP0)

objTextStream.WriteLine  vbCrLf & "Service Pack 2"
objTextStream.WriteLine  "--------------"
objTextStream.WriteLine  strSP2
objTextStream.WriteLine  "Total number: " & intSP2

objTextStream.WriteLine  vbCrLf & "Service Pack 1"
objTextStream.WriteLine  "--------------"
objTextStream.WriteLine  strSP1
objTextStream.WriteLine  "Total number: " & intSP1

objTextStream.WriteLine  vbCrLf & "No Service Pack"
objTextStream.WriteLine  "---------------"
objTextStream.WriteLine  strSP0
objTextStream.WriteLine  "Total number: " & intSP0

objTextStream.WriteLine  vbCrLf & "Computers Not Running Windows XP"
objTextStream.WriteLine  "================================"
objTextStream.WriteLine  "Total number: " & intNotXP

objTextStream.WriteLine  vbCrLf & "Could Not Connect To Computer"
objTextStream.WriteLine  "============================="
objTextStream.WriteLine  "Total number: " & intErr
objTextStream.WriteLine

objTextStream.Close

重大な問題

さて、必要なコンポーネントが得られたので、Dr. Scripto はアーク溶接機と酸素アセチレン トーチに火を付けて、各パーツを組み立てて高性能のインベントリ作成マシンを組み立てる作業に取りかかります。はい、ちゃんとわかっています。とりあえず、私のコンピュータで動作するスクリプトをご紹介します。無料の記事に何を期待しているのでしょうか。

ここまで説明してきたコンポーネントを別々のプロシージャにまとめて、メンテナンスや再利用がしやすいモジュールの形にしようと思います。このことは今回のコラムのポイントとなりそうです。というのも、どれほど複雑なスクリプトでも構造化することはよいことだからです。

Scripting Guys は、Dr. Scripto の「わかりきったことを繰り返すな。」という言葉について熟考することがよくあります。おそらく、彼の意図は、便利なコードは数多くのスクリプトに再利用するべきだということでしょう。そうだとすると、スクリプトに貼り付けることができるように、再利用可能な機能を汎用のサブルーチンや関数にまとめることは、合理的な戦略です。そのようなコード スニペットを標準のフォームに貼り付ければ、最も効率的でコンパクトな形にしあげることができ、組織内のすべてのスクリプト作成者がそれらを活用することができます。

コードの一部分をプロシージャにまとめると、コードをスクリプトの複数の場所で使用する場合にも便利です。そのようなコードをプロシージャにまとめれば、記述が 1 度で済み、1 つの場所で維持管理できます。

私たちの中にも、長くて複雑なスクリプトも、このように分けた方が読みやすいと考える人がいます。しかし、関数やサブルーチンの利点について議論する中で、私たち Scripting Guys にもいろいろな考え方があることがわかりました。Greg は、関数やサブルーチンは過大評価されていると考えているようです (おそらく、このことについては今後のコラムで彼に語ってもらうことになるでしょう)。そこで皆さんにお願いです。プロシージャについてどのように考えているか、好きか嫌いか、どのように使っているかなど、皆さんのご意見を電子メールでお送りください (英語のみ)。

さて、スクリプトに戻りましょう。ここでは、コードを次の部品に分割しました。

  • メイン ルーチン。定数とグローバル変数を初期化し、コンピュータ名の配列を入力関数 (ReadTextFile) から取得して、他のプロシージャを呼び出します。また、メイン ルーチンでは、WMI に接続しようとしたときにスクリプト エラーが発生したコンピュータの台数も数えます。一部の変数名の先頭には "g_" が付いていますが、これらはグローバル変数であることを示しています。グローバル変数の適用範囲はスクリプト全体なので、複数のプロシージャで使用できます。

  • 入力関数 ReadTextFile。ファイル名をパラメータとして受け取り、コンピュータ名の配列を返します。この関数は、新しい名前を読み取るたびに配列の次元を動的に再設定します。ReDim Preserve がこの処理を実行します。

  • 関数 GetSP。インベントリの作成と台数のカウントを実行します。メイン ルーチンで配列をループ処理している間に、この関数に各コンピュータの名前を渡します。この関数は、コンピュータで実行されているサービス パックの一覧をコンピュータ名の末尾に追加し、そのサービス パックを実行しているコンピュータの台数を数えるグローバル変数の値を 1 つ増やします。実行に成功した場合は 0 を返し、エラーが発生した場合は 1 を返します。

  • 出力サブルーチン WriteTextFile。ファイル名をパラメータとして受け取り、累積したインベントリ データをそのテキスト ファイルに書き込みます。

GetSP 関数では、リモート コンピュータ上の WMI に接続しようとした後にエラーが発生しないかテストしています。コンピュータの台数が少ないと、この処理は問題なく実行され、対象のコンピュータが見つけられなかったかどうかが WMI によって通知されます。しかし、コンピュータが多数ある場合は、WMI に接続しようとする前に、各コンピュータに対して ping を実行し、ネットワークに接続していることを確かめた方がよいかもしれません。このためにはさらに数行のコードが必要ですが、ping は WMI がタイムアウトになるまで待つ時間よりも速く実行されます。

最後に、Dr. Scripto の最高傑作を次に示します。

'List the operating system and service pack of all computers in a text file.
On Error Resume Next

'Initialize constants and variables.
Const FOR_READING = 1
Const FOR_APPENDING = 8
strInputFile = "hosts.txt"
strOutputFile = "xpsp.txt"
g_strSP2 = ""
g_strSP1 = ""
g_strSP0 = ""
g_intSP2 = 0
g_intSP1 = 0
g_intSP0 = 0
g_intNotXP = 0
g_intErr = 0

'Get list of computers from text file.
arrComputers = ReadTextFile(strInputFile)
For Each strComputer In arrComputers
  intGetSP = GetSP(strComputer)
  If 1 = intGetSP Then
    g_intErr = g_intErr + 1
  End If
Next

WriteTextFile(strOutputFile)

WScript.Echo "Data written to " & strOutputFile

'******************************************************************************

'Read text file line by line and return array of lines.
Function ReadTextFile(strFileName)

On Error Resume Next

Dim arrLines()

Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strFilename) Then
  Set objTextStream = objFSO.OpenTextFile(strFilename, FOR_READING)
Else
  WScript.Echo "Input text file " & strFilename & " not found."
  WScript.Quit
End If
Do Until objTextStream.AtEndOfStream
  intLineNo = objTextStream.Line
  ReDim Preserve arrLines(intLineNo - 1)
  arrLines(intLineNo - 1) = objTextStream.ReadLine
Loop
objTextStream.Close
ReadTextFile = arrLines

End Function

'******************************************************************************

'Get list and count of computers by OS and SP.
Function GetSP(strComp)

On Error Resume Next

'Connect to WMI on remote computer.
Set objWMIService = GetObject("winmgmts:\\" & strComp)
If Err <> 0 Then
  WScript.Echo "  Unable to connect to WMI."
  WScript.Echo "    Error Number:" & Err.Number
  WScript.Echo "    Source:" & Err.Source
  WScript.Echo "    Description:" & Err.Description
  GetSP = 1
  Exit Function
End If
Set colOSes = objWMIService.ExecQuery _
 ("SELECT * FROM Win32_OperatingSystem")
For Each objOS in colOSes
  If objOS.Version = "5.1.2600" Then
    If objOS.ServicePackMajorVersion = "2" Then
      g_strSP2 = g_strSP2 & strComp & vbCrLf
      g_intSP2 = g_intSP2 + 1
    ElseIf objOS.ServicePackMajorVersion = "1" Then
      g_strSP1 = g_strSP1 & strComp & vbCrLf
      g_intSP1 = g_intSP1 + 1
    Else
      g_strSP0 = g_strSP0 & strComp & vbCrLf
      g_intSP0 = g_intSP0 + 1
    End If
    GetSP = 0
  Else
    g_intNotXP = g_intNotXP + 1
  End If
Next
GetSP = 0

End Function

'******************************************************************************

'Write or append data to text file.
Sub WriteTextFile(strFileName)

On Error Resume Next

'Open text file for output.
Set objFSO = CreateObject("Scripting.FileSystemObject")
If objFSO.FileExists(strFileName) Then
  Set objTextStream = objFSO.OpenTextFile(strFileName, FOR_APPENDING)
Else
  Set objTextStream = objFSO.CreateTextFile(strFileName)
End If

'Write data to file.
objTextStream.WriteLine "Inventory of Windows XP Service Packs"
objTextStream.WriteLine "Taken " & Now
objTextStream.WriteLine vbCrLf & "Computers Running Windows XP"
objTextStream.WriteLine "============================"
objTextStream.WriteLine  "Total number: " & (g_intSP2 + g_intSP1 + g_intSP0)

objTextStream.WriteLine  vbCrLf & "Service Pack 2"
objTextStream.WriteLine  "--------------"
objTextStream.WriteLine  g_strSP2
objTextStream.WriteLine  "Total number: " & g_intSP2

objTextStream.WriteLine  vbCrLf & "Service Pack 1"
objTextStream.WriteLine  "--------------"
objTextStream.WriteLine  g_strSP1
objTextStream.WriteLine  "Total number: " & g_intSP1

objTextStream.WriteLine  vbCrLf & "No Service Pack"
objTextStream.WriteLine  "---------------"
objTextStream.WriteLine  g_strSP0
objTextStream.WriteLine  "Total number: " & g_intSP0

objTextStream.WriteLine  vbCrLf & "Computers Not Running Windows XP"
objTextStream.WriteLine  "================================"
objTextStream.WriteLine  "Total number: " & g_intNotXP

objTextStream.WriteLine  vbCrLf & "Could Not Connect To Computer"
objTextStream.WriteLine  "============================="
objTextStream.WriteLine  "Total number: " & g_intErr
objTextStream.WriteLine

objTextStream.Close

End Sub

たとえば、出力ファイル xpsp.txt の内容は次のようになります。

Inventory of Windows XP Service Packs
Taken 3/15/2005 1:40:10 PM

Computers Running Windows XP
============================
Total number: 3

Service Pack 2
--------------
client1
client2
Total number: 2

Service Pack 1
--------------
client3
Total number: 1

No Service Pack
---------------
client4
Total number: 1

Computers Not Running Windows XP
================================
Total number: 0

Could Not Connect To Computer
=============================
Total number: 0

今回は Windows XP を実行していないコンピュータの名前は取得しませんでしたが、もっと完成度の高いインベントリが必要な場合は、そのためのコードを簡単に追加できます。さらに、サービス パックだけでなくすべての更新プログラムをチェックしたい場合は、WMI クラス Win32_QuickFixEngineering を使用して、更新プログラムの一覧を取得することもできます。多数の更新プログラムがインストールされている可能性があるため、この場合は既に紹介した最初のコード例のように、インベントリをコンピュータごとに表示した方がよいでしょう。

また、Service Pack 2 がインストールされていないすべてのコンピュータについて、SP2 のインストールを開始するコードを追加することもできます。そのためには、文字列 g_strSP1 と g_strSP0 を 1 つの文字列に連結し、Split(strSP1AndSP0, vbCrLf) を使用して、再び配列に変換します。g_strSP1 および g_strSP0 には、SP2 がインストールされていない Windows XP コンピュータの名前が格納されます。次に、For Each ループを使用してその配列をループ処理し、それらの各コンピュータで Service Pack 2 セットアップを実行できます。この方法では、リモート管理を有効にする既定のファイアウォール設定でサービス パックを展開できるだけでなく、独自のファイアウォールを持つネットワーク上にサービス パックを展開したり、ファイアウォールを無効にしたりできます。その他にもいろいろなことができますが、ちょっと先走り過ぎてしまいましたね。

次回のコラムでは、Active Directory ドメインに参加しているコンピュータからこれと同じサービス パック情報を取得する方法について説明します。

詳細情報