Hey, Scripting Guy!アドレナリンの大量分泌

Microsoft Scripting Guys

私たちは、TechNet Magazine の記事を執筆する作業は、あらゆる仕事の中で最も名誉とやりがいのある仕事だと確信しています (もちろん、実際に報酬をいただけたら、さらにやりがいは増しますが、それはまた別の話です)。この仕事にはどれほどの名誉があるのか、ですか。次のようにお答えしておきましょう。現在、世界中で、布団にくるまった子供たちが母親を見上げて、「お母さん、おとなになったら TechNet Magazine で月刊のスクリプト コラムを書きたい」と言っています。

注 : もちろん、世界中の人は、このコラムが既に子供によって書かれていると思っているかもしれませんが、それもまた別の話です。

Scripting Guys が TechNet Magazine の記事を執筆することに伴う称賛を喜んで受け入れることは有名です。私たちは、サインをねだられたりパパラッチに追い回されたりすることにも耐えられるようになりました。でも、実のところ、私たちは名声や誇りのためにこの仕事をしているのではありません。私たちは、システム管理スクリプトの記述に伴う、純粋なアドレナリンの大量分泌のためにこの仕事をしているのです。

確かに、"純粋なアドレナリンの大量分泌" という言葉と "システム管理スクリプト" という言葉を同じ文の中で目にすることは、あまりありません (もちろん、"純粋なアドレナリンの大量分泌" の後に "とは無縁の" が付いていれば話は別ですが)。

普通の人は、システム管理スクリプトは非常に便利であるが、おそらくあまり刺激的なものではないと考えています。それどころか、スクリプトは少し退屈だと感じているかもしれません。その理由は、これらの人たちが皆、Windows Vista® や Windows Server® 2008 のブート構成データ スクリプトを記述したことがないからです。

今の話を聞いて心拍数が 1 つか 2 つ上昇したでしょう。このコラムを読んでいる方のほとんどはおそらくご存知だと思いますが、Windows Vista と Windows Server 2008 では、従来の boot.ini ファイルが廃止され、代わりに新しいブート構成データ ストアが導入されました。この新しいデータ ストアが導入されたことにより、強化された機能を使用して、より柔軟にブート処理を管理できるようになりました。

これは非常にすばらしいことです。でも、本当にすばらしいのは、新しい Windows® Management Instrumentation (WMI) プロバイダの登場によって、スクリプトを使用してブート構成データ (BCD) ストアに簡単にアクセスし、このデータ ストアを完全に管理できるようになったことです。

背骨のあたりに奇妙な感覚が走ったと思いますが、心配しないでください。純粋なアドレナリンが大量分泌されると、そういう感じがするものです。BCD スクリプトを使用し始めれば、この感覚にも慣れてくるでしょう。

先に進む前に 1 つお伝えしておきますが、BCD プロバイダを使用して実現できる操作をすべて取り上げるのは、少なくともこの 1 回のコラムでは、まず不可能です (TechNet Magazine の編集者に、ブート構成データ スクリプトの記述方法のみを扱った特別号を発行してもらえるかどうかをメールでたずねましたが、まだ返事は届いていません)。

詳細については、BCD WMI プロバイダのドキュメント (go.microsoft.com/fwlink/?LinkId=116953) を参照してください。とりあえず、このコラムでは、マルチブート コンピュータ (複数のオペレーティング システムがインストールされたコンピュータ) 用に設計されたサンプル コードを紹介します。

これらのスクリプトは Windows Vista と Windows Server 2008 でのみ動作します。この理由は、前述のとおり、現在 BCD はこれら 2 つのオペレーティング システムでのみサポートされているためです。

まずは、現在コンピュータで使用されている OS を通知するスクリプトを紹介します。確かに、これは BCD プロバイダの最も刺激的な使用方法ではありません。BCD プロバイダを使用しなくても、WMI の Win32_OperatingSystem クラスを使用すれば、現在コンピュータで使用されている OS を確認できるためです。ただし、これはかなり単純なスクリプト (少なくとも BCD スクリプトにしては) であり、BCD の操作に必要な基本的な技法を示すのに適しています (控えめに言うと、そうですね、何と言えばいいでしょう、やや "珍しい" 技法ですね)。

それに、私たちは Hey, Scripting Guy! コラムをあまり刺激の強い内容にすることはできません。過度に興奮した、あまりに熱心な Hey, Scripting Guy! コラムのファンが原因で起こったすべての損害の責任は私たちが負うことになると、TechNet Magazine のスタッフに言われているためです。正規表現に関するコラムを公開した後に世界中で勃発した騒動を考えると、もう二度と、あれほどまでに刺激的なことをするわけにはいきません。

注 : ビートルズがファンに取り囲まれているビデオや、ジョン、ポール、ジョージ、およびリンゴをひとめ見ただけで、気絶したり泣いたりしている女の子たちの写真を覚えていますか。新しいコラムを公開するたびに、私たちはほぼこれと同じ状況を経験します。

ええ、まあ、今の話は少し大げさかもしれません。でも、多くの人が (女性だけでなく男性も) Hey, Scripting Guy! コラムを読んだ後にむせび泣くことは確かです。

それはともかく、図 1 のスクリプトをご覧ください。このスクリプトでは、BCD プロバイダを使用して、現在コンピュータで使用されている OS を確認しています。このスクリプトを実行する前に知っておかなければならないのは、管理者として実行する必要があることです。管理者として実行しなかった場合、スクリプトは失敗します。

図 1: 現在使用されているオペレーティング システムの取得

Const BcdLibraryString_Description = &h12000004
Const Current = "{fa926493-6f1c-4193-a414-58f0b2456d1e}"

strComputer = "."

Set objStoreClass = GetObject("winmgmts:{(Backup,Restore)}\\" & _
 strComputer & "\root\wmi:BcdStore")

objStoreClass.OpenStore "", objStore
objStore.OpenObject Current, objDefault

objDefault.GetElement BcdLibraryString_Description, objElement
Wscript.Echo "Current operating system: " & objElement.String

いえ、単に管理者特権が与えられたアカウントでログオンすればよいと言っているわけではありません。[スタート] ボタンをクリックし、[コマンド プロンプト] を右クリックし、[管理者として実行] をクリックしてコマンド プロンプト ウィンドウを開く必要があります。これで、このスクリプトをコマンド プロンプトから実行できます。

このスクリプトのしくみはどうなっているか、ですって。皆さんから、その質問が寄せられるのではないかと心配していたのです。でも、問題ありません。できる限りわかりやすく説明するよう努めます (そうすれば刺激を最小限に抑えることができますね、少なくともしばらくの間は)。

まずは、BcdLibraryString_Description と Current という 2 つの定数を定義します。BcdLibraryString_Description は、ここで取得するオブジェクトを参照する定数です。この場合、現在使用されているオペレーティング システムの説明 (名前) がこのオブジェクトに格納されます。

ちなみに、これは、BCD プロバイダの使用に関する愛すべき特徴の 1 つです。通常は、単純にプロパティの値を取得するのではなく、このような定数値の 1 つ (および GetElement メソッド) を使用して別のオブジェクトを取得し、そのオブジェクトのプロパティの値をエコー バックします。確かに少しばかげた処理ですが、よく言われるように、楽しみの半分は、その目的地に至るまでの道程ですからね。

注 : こう言われると、目的地はどこなんだろうと思ってしまいますね。

定数 Current は、単に現在使用されているオペレーティング システムを表す GUID です。

 {fa926493-6f1c-4193-a414-58f0b-2456d1e} 

上記の値は "既知の" GUID、言い方を変えれば "よく知られている" GUID と考えられています (これで少なくとも、マイクロソフトの社員が実はユーモアのセンスも持ち合わせていることがおわかりいただけたでしょう)。

この "よく知られている" GUID を、私たちはあえてスクリプトの中に含めました。このコラムを読んでいる方の中に、次の 2 つの値のどちらが正しいかを思い出せない方がいらっしゃるといけないからです。

{fa926493-6f1c-4193-a414-58f0b2456d1e} 
{fa926493-6f1c-4193-a414-58f0b2456d1f}

注 : 気になる方のために言っておくと、GUID は "グイッド" または "グーイッド" と発音します。また、上記の GUID は 3 組目の数字が 4 で始まるのでバージョン 1 の GUID であることなど、説明したいことはまだたくさんありますが、刺激は最小限に抑えると約束しましたからね。私たちは、約束は守ります。

ご想像のとおり、BCD プロバイダを使用するときは、ほぼどのような場合でも、定数、16 進値、および GUID を使用する必要があります。これらをすべて今月のコラムで取り上げることはできませんが、詳細については、前述の MSDN® の BCD に関するページ (go.microsoft.com/fwlink/?LinkId=116953) で確認できます。ただし、このページを参照するのは、刺激に耐えられる方だけにしてください。

2 つの定数を定義したら、次は、ローカル コンピュータの WMI サービスに接続します。このスクリプトを使用して、リモート コンピュータのブート構成データを取得することはできるでしょうか。もちろん、できます。

正直なところ、取得できなかったとしたら、この BCD プロバイダを使用したスクリプトの価値はほとんどなくなります。リモート コンピュータからブート構成データを取得するには (この場合も、リモート コンピュータでは Windows Vista または Windows Server 2008 が実行されている必要があります)、以下のように、そのコンピュータの名前を変数 strComputer に代入するだけです。

strComputer = "atl-fs-001"

WMI 接続文字列に含まれているいくつかの重要な項目についても説明しておきます。まず、お気付きかもしれませんが、バックアップ特権と復元特権の両方が接続文字列に含まれています。これを示しているのが {(Backup,Restore)} という構文です。この構文は重要なのでしょうか。そうですね、スクリプトを動作させたいのであれば、非常に重要です。この 2 つの特権を明示的に含めずにスクリプトを実行すると、エラーが発生します。

次に注意する必要があるのは、システム管理スクリプトで最もよく使用される root\cimv2 名前空間に接続しないことです。代わりに、root\WMI 名前空間に接続し、BCDStore クラスに直接バインドします。これを行うのが次のコードです。

"\root\wmi:BcdStore" 

この部分はそれほど刺激的ではありません。お楽しみはこれからです。

1 つか 2 つ例外はあるかもしれませんが、ほとんどの BCD スクリプトは、共通する 3 つの手順で始まります。それは、定数を定義し、WMI サービスに接続し、BCD ストアを開くという手順です。1 つ目と 2 つ目の手順は既に完了しました。次のコード行は 3 つ目の手順を示しています。

objStoreClass.OpenStore "", objStore

前述のとおり、ここでは BCD ストアを開いています。BCD ストアは、すべてのブート構成情報が格納されるオペレーティング システム エンティティです。このストアを開くには、単純に OpenStore メソッドを呼び出して、次の 2 つのパラメータを渡します。

  • 空の文字列 ("")。この文字列は、既定のストアを開くことをスクリプトに指示します。
  • objStore。これは、スクリプトに提供する "出力" パラメータです。メソッドに変数名を渡すと、メソッドは感謝のしるしに、その変数名をオブジェクト参照として使用するオブジェクト (この場合は、BCD ストアを表すオブジェクト) を返します。

ストアが開いたら、次のように OpenObject メソッドを使用して、(出力パラメータ objDefault に格納された) もう 1 つのオブジェクトを取得できます。

objStore.OpenObject Current, objDefault

この新しいオブジェクトは何でしょうか。そうです、現在使用されているオペレーティング システムです。これは、OpenObject に、現在使用されているオペレーティング システムを表す既知の GUID である定数 Current を渡していることからわかります。

これで、現在コンピュータで使用されているオペレーティング システムがわかりましたね。まあ、まだ完全にはわかっていませんが。この情報を得るには、次のように GetElement を使用して、このオペレーティング システムの説明を表すオブジェクトを取得する必要があります。

objDefault.GetElement _
  BcdLibraryString_Description, objElement

さて、皆さんは、過度に興奮してなんらかの騒動を起こさないことを約束できますか。そうですか、わかりました。それではお教えします。次のように String プロパティの値をエコー バックすれば、ようやく現在コンピュータで使用されているオペレーティング システムを確認できます。

Wscript.Echo "Current operating system: " _
  & objElement.String

落ち着いてください。騒動を起こさないと約束してくださったじゃないですか。難しいとは思いますが、できる限り努力してください。深呼吸をしましょう。BCD スクリプトを記述するときは、これが一番です。

既に説明したように、コンピュータで使用されているオペレーティング システムを確認するだけでも、非常に手間がかかります。この作業はもっと簡単に行うことができます。ですが、良い面を見ると、これで皆さんは BCD スクリプトのしくみを理解できました。つまり、今までスクリプト作成者にできなかったことをご自分の手で実現できます (落ち着いてください、落ち着いてください)。たとえば、マルチブート コンピュータでは、常に 1 つのオペレーティング システムが "既定" として設定されているので、コンピュータの再起動時には、だれかがそばにいて明示的に指定しない限り、既定のオペレーティング システムが自動的に読み込まれます。Windows Vista (および BCD プロバイダ) が登場するまで、スクリプト作成者は、コンピュータの既定のオペレーティング システムを確認できませんでした。でも今では非常に簡単に確認できます。図 2 のようなスクリプトを実行するだけです。

図 2: 既定のオペレーティング システムの確認

Const BcdLibraryString_Description = &h12000004
Const BootMgrId = "{9dea862c-5cdd-4e70-acc1-f32b344d4795}"
Const DefaultType = &h23000003

strComputer = "." 

Set objStoreClass = GetObject("winmgmts:{(Backup,Restore)}\\" & _
    strComputer & "\root\wmi:BcdStore")
objStoreClass.OpenStore "", objStore

objStore.OpenObject BootMgrId, objBootMgr 

objBootMgr.GetElement DefaultType, objDefaultOSIdentifier
objStore.OpenObject objDefaultOSIdentifier.Id, objDefault

objDefault.GetElement BcdLibraryString_Description, objElement 
WScript.Echo "Default operating system: " & objElement.String

おっしゃるとおり、これはちょっとした騒動を引き起こすかもしれません。でも、ちょっとだけにしておいてくださいよ、いいですね。このスクリプトについては詳しく説明しません。これより前の 10 ~ 12 個の段落を読み飛ばしていなければ、自力でロジックを理解できるはずです。ただし、お気付きかもしれませんが、既定のオペレーティング システムを突き止めるには、OpenObject メソッドを使用してブート マネージャ オブジェクトのインスタンスを開くという中間手順を実行する必要があります。ブート マネージャを開いたら、定数 DefaultType を使用して、既定のオペレーティング システムを表すオブジェクトを取得できます。

確かに、現在使用されているオペレーティング システムを確認することも、既定のオペレーティング システムを確認することもできるとは、かなり刺激的ですね。でも、本当にすばらしいことはまだあります、わかりますか。それは、コンピュータにインストールされているすべてのオペレーティング システムの一覧を取得することです。これは刺激的でしょう。シートベルトを締めて、図 3 をご覧ください。

このスクリプトでは何を行っているのでしょうか。まず、WindowsImages と LegacyImages という 2 つの新しい定数を定義しています。WindowsImages を使用すると、BCD がサポートされているすべての OS (つまり Windows Vista と Windows Server 2008) のインスタンスを取得でき、LegacyImages を使用すると、コンピュータにインストールされているすべての "古い" オペレーティング システムのインスタンスを取得できます。BCD ストアに接続したら、次のように EnumerateObjects メソッドを使用して、コンピュータにインストールされている BCD に対応したオペレーティング システムのインスタンスをすべて取得します。

objStore.EnumerateObjects _
  WindowsImages, colObjects 

図 3: コンピュータにインストールされているすべてのオペレーティング システムの検出

Const BcdLibraryString_Description = &h12000004
Const WindowsImages = &h10200003
Const LegacyImages = &h10300006

strComputer = "."

Set objStoreClass = GetObject("winmgmts:{(Backup,Restore)}\\" & _
 strComputer & "\root\wmi:BcdStore")

objStoreClass.OpenStore "", objStore 

objStore.EnumerateObjects WindowsImages, colObjects 

For Each objObject in colObjects
 objObject.GetElement BcdLibraryString_Description, objElement 
 Wscript.Echo objElement.String
Next
Wscript.Echo

objStore.EnumerateObjects LegacyImages, colObjects 

For Each objObject in colObjects
 objObject.GetElement BcdLibraryString_Description, objElement 
 Wscript.Echo objElement.String
Next

EnumerateObjects による処理の後は、コレクション内のすべてのオペレーティング システムを 1 つずつ処理する For Each ループを設定します。このループ内では、次の 2 行のコードを使用して、オペレーティング システムの説明を取得し、その説明を表示します。

objObject.GetElement _
  BcdLibraryString_Description, objElement 
Wscript.Echo objElement.String

その後、次のように、コンピュータにインストールされているすべての古いオペレーティング システムに対して同じ処理を繰り返します。

objStore.EnumerateObjects _
  LegacyImages, colObjects 

For Each objObject in colObjects
 objObject.GetElement _
  BcdLibraryString_Description, objElement 
 Wscript.Echo objElement.String
Next

注 : BCD スクリプトを実行するときの興奮は理解できますが、責任を持って実行するようにしてください。おそらく、人間の体が耐えられるアドレナリン大量分泌の回数には限界があります。妊娠中の女性、妊娠するかもしれない女性、妊娠しないかもしれない女性、妊娠したことのある女性、女性ですらない女性 (要するに男性) は、最初に医師の診察を受けてから、BCD スクリプトを実行することをお勧めします。

ええ、まあ、最初に医師の診察を受ける必要はありません。でも、実際に BCD スクリプトの実行についてたずねた場合に、医師が何と言うかは興味深いですね。

では、本当にすごいことに挑戦しましょう。それは、既定のオペレーティング システムを変更することです。たとえば、あるデュアルブート コンピュータで Windows Vista と Windows Server 2008 の両方を実行しており、Windows Vista を既定のオペレーティング システムに設定する必要があるとします。この操作を行うにはどうすればよいでしょうか。図 4 をご覧ください。このスクリプトを使用すると、目的の操作を行うことができます。

図 4: 既定のオペレーティング システムの変更

Const BootMgrId = "{9dea862c-5cdd-4e70-accl-f32b344d4795}"
Const BcdLibraryString_Description = &h12000004
Const DefaultType = &h23000003
Const WindowsImages = &h10200003

strComputer = "."

Set objStoreClass = GetObject("winmgmts:{(Backup,Restore)}\\" & _
 strComputer & "\root\wmi:BcdStore")

objStoreClass.OpenStore "", objStore 
objStore.EnumerateObjects WindowsImages, colObjects 

For Each objObject in colObjects
 objObject.GetElement BcdLibraryString_Description, objElement 
 If Instr(objElement.String, "Vista") Then
  objStore.OpenObject BootMgrId, objBootMgr 
  objBootMgr.SetObjectElement DefaultType, objObject.ID 
 End If
Next

このスクリプトでは、先ほどと同様に BCD ストアを開いた後、EnumerateObjects を使用して、コンピュータにインストールされている、BCD に対応したすべてのオペレーティング システムのコレクションを取得しています。その後、コレクション内のすべての項目を 1 つずつ処理する For Each ループを設定します。各オペレーティング システムの説明を取得するには、次の (もうお馴染みの) コード行を使用します。

objObject.GetElement _
  BcdLibraryString_Description, objElement

特定のオペレーティング システムの説明を取得したら、次のように InStr 関数を使用して、その値に Vista という言葉が含まれているかどうかを確認します。

If Instr(objElement.String, "Vista") Then

おっしゃるとおり、この方法は少し野暮な感じがします。より洗練された方法は、コンピュータにインストールされているすべてのオペレーティング システムを列挙し、それらを 1 つずつ処理するのではなく、Windows Vista の GUID を使用して、Windows Vista を直接開くことです。

残念ながら、この洗練された方法を使用するには、Windows Vista の GUID を知っている必要があります。一方、上記の野暮な方法を使用する場合は、何も知っている必要はありません (Scripting Guys にとって、これは常に喜ばしいことです)。名前に Vista という言葉が含まれているオペレーティング システムが見つかるまで調べ続ければよいだけです。

注 : Windows Vista のインスタンスがコンピュータに複数インストールされている場合は、どうすればよいでしょうか。その場合は、Vista Ultimate や Vista Enterprise などの文字列を探す必要があります。

Windows Vista が見つかったら、次の 2 行のコードを使用して、Windows ブート マネージャを開き、既定のオペレーティング システムを Windows Vista に設定します。

objStore.OpenObject BootMgrId, objBootMgr 
objBootMgr.SetObjectElement _
  DefaultType, objObject.ID 

今月はこれで終わりにします。いくら Scripting Guys と言えども、24 時間 365 日、休みなく刺激を受け続けたら、頭がおかしくなりますからね。でも、ご心配なく。来月また、刺激的な Hey, Scripting Guy! コラムを用意して戻ってきます。運が良ければ、皆さんもそれまでにはいつもの状態に戻っているでしょう。

Dr. Scripto のスクリプト パズル

パズルを解く能力だけでなく、スクリプト作成スキルもテストする月に 1 度の課題です。

2008 年 7 月 : VBScript 正方形

そうですね、おそらく正方形ではなく長方形ですが、それは良しとしましょう。このパズルを解くには、右側にある各正方形を左側にある空の正方形にはめ込んで、VBScript 関数の名前を作成します。各正方形は 1 回のみ使用できます。以下に例を示します。

この例では、OU という正方形 (長方形) を 1 つ目の単語に含まれている空の正方形に移動し、MS と OX を 2 つ目の単語に含まれている空の正方形に移動します。これで、VBScript 関数の UBound と MsgBox ができあがります (下図参照)。

それでは、いざ挑戦です。

解答 :

Dr. Scripto のスクリプト パズル

解答 : VBScript 正方形 (2008 年 7 月)

Scripting Guys は、マイクロソフトの仕事をしています、というよりもマイクロソフトにより雇われています。野球をプレイしたり監督したり観戦したり (または他のさまざまな活動を) しているのでない限り、彼らは TechNet スクリプト センターを運営しています。詳細については、www.scriptingguys.com を参照してください。

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