2010/01/12

VHD Boot かどうかを識別するスクリプト

仮想マシンのゲスト OS からの識別に続いて、VHD Boot か否かの識別を考えてみました。VHD Boot については、過去に雑誌に寄稿したものが、COMPUTERWORLD.JP のサイトでまとまっています。

COMPUTERWORLD.JP: Windows 7の仮想ハードディスクがスゴイ!―(1)~(5)http://www.computerworld.jp/topics/win7/151010.html


(2010/12/07 追記: BCDEDIT の方法はだめなときもあるみたいです。調査中...)

VHD Boot を構成するには、ブート構成データ(BCD) ストアに VHD Boot 用の起動エントリを登録します。BCDEDIT /enum {current} を実行すると、動作中の OS の登録エントリが参照できます。出力結果の device または osdevice が vhd=[ドライブ名:]\VHD ファイルのパス (.vhd) になっていれば、現在動作中の OS は VHD Boot で起動したことになります。


今の説明をそのままスクリプトにすると、次のようになります。このスクリプトでは、BCDEDIT コマンドを使用していますが、BCD WMI プロバイダーを使用することも可能です。私の場合は、BcdLibraryDevice_ApplicationDevice が返す BcdDeviceElement クラスの扱いがわからず、断念してしまいましたが...


BCD WMI プロバイダーについての参考情報:
http://technet.microsoft.com/ja-jp/magazine/2008.07.heyscriptingguy.aspx
http://msdn.microsoft.com/en-us/library/aa362652(VS.85).aspx
 
[getosdevice.vbs]
--------------------------------------------------------------------------------
strCmd = "BCDEDIT /enum {current}"
Set objShell = CreateObject("WScript.Shell")
Set objExec = objShell.Exec ("%comspec% /c " & strCmd)
Do While Not objExec.StdOut.AtEndOfStream
  strOut = objExec.StdOut.ReadLine
  If InStr(strOut, "パラメーターが間違っています。") > 0 Then
    WScript.Echo "管理者権限で実行してください。"
    WScript.Quit
  ElseIf InStr(strOut, "osdevice") > 0 Then
    If InStr(strOut, "vhd=") > 0 Then
      WScript.Echo "This computer boot from vhd file (" & Mid(strOut,25) & ")"
    Else
      WScript.Echo "This computer boot from fixed disk (" & Mid(strOut,25) & ")"
    End If
  End If
Loop
--------------------------------------------------------------------------------
 
VHD Boot の場合の実行例:
通常起動の場合の実行例:

 

BCD にアクセスする方法は、1 つ問題があります。Windows 7 の場合、UAC で管理者権限に昇格しなければ、BCD ストアにアクセスできません。そのため、スクリプトを実行するのにも管理者権限への昇格が必要になります。

管理者権限を必要としない別の方法を考えてみました。C: ドライブが存在する物理ディスクのドライバー情報を使います。VHD をマウントした場合、ディスク アクセスには Msft Virtual Disk SCSI Disk Device というドライバーが使用されます。Hey, Scripting Guy! 様のスクリプト (http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/may05/hey0523.mspx) を参考に作ったものが、次の WSH スクリプトです。
[bootfrom.vbs]
--------------------------------------------------------------------------------
'参考: http://www.microsoft.com/japan/technet/scriptcenter/resources/qanda/may05/hey0523.mspx
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colDiskDrives = objWMIService.ExecQuery("SELECT * FROM Win32_DiskDrive")
VHDBOOT = False
For Each objDrive In colDiskDrives
  If objDrive.Caption = "Msft Virtual Disk SCSI Disk Device" Then
    strDeviceID = Replace(objDrive.DeviceID, "\", "\\")
    Set colPartitions = objWMIService.ExecQuery _
      ("ASSOCIATORS OF {Win32_DiskDrive.DeviceID=""" & _
        strDeviceID & """} WHERE AssocClass = " & _
          "Win32_DiskDriveToDiskPartition")
    For Each objPartition In colPartitions
      Set colLogicalDisks = objWMIService.ExecQuery _
        ("ASSOCIATORS OF {Win32_DiskPartition.DeviceID=""" & _
          objPartition.DeviceID & """} WHERE AssocClass = " & _
            "Win32_LogicalDiskToPartition")
      For Each objLogicalDisk In colLogicalDisks
         If objLogicalDisk.DeviceID = "C:" Then
            VHDBOOT = True
         End If
       Next
    Next
  End If
Next
If VHDBOOT Then
  WScript.Echo "This computer boot from VHD file."
Else
  WScript.Echo "This computer boot from fixed disk."
End If
--------------------------------------------------------------------------------

管理者権限が必要ないスクリプト: