2010/01/08

仮想マシンのホスト環境をゲストからどこまで識別できるのか?

Hyper-V の仮想環境において、ホスト OS 側でどのような仮想マシンが動作しているか把握することは比較的簡単です。Hyper-V マネージャーを見れば一目瞭然ですし、Hyper-V が提供する WMI プロバイダーを利用して情報を取得することもできます。WMI プロバイダーについては、Using the Virtualization WMI Provider (http://msdn.microsoft.com/en-us/library/cc723875(VS.85).aspx) を参照のこと。

ゲスト OS 側から、自分が物理環境で動作しているのか、それとも仮想環境で動作しているのか、仮想環境の場合は、どのホストのどんな仮想化テクノロジ上で動いているのかを把握するのは、難しいようです。MS さんのブログ「管理者は見た!~AD と ILM 一家の秘密~ [Windows 7] XP Mode か実機か Virtual PC か Hyper-V か見分ける方法とは?」 (http://blogs.technet.com/jpilmblg/archive/2009/12/22/windows-7-xp-mode-virtual-pc-hyper-v.aspx)では、いくつか興味深い方法で挑戦していますが、結局のところ、完全に識別することはできないと結論しています。

私も、私なりに別の方法を模索してみました。Hyper-V に関しては、なんだかいけそうな気がします。

私がヒントにしたのは、TechNet ライブラリのこちら (http://technet.microsoft.com/ja-jp/library/aa997613(EXCHG.80).aspx) のドキュメントです。このドキュメントでは、Exchange Server アナライザー ツールが仮想環境 を検出する方法 (古いドキュメントなので Virtual Server 2005 か Virutla PC 2004 かの区別ですが) が記されています。

まず、WMI の Win32_OperatingSystem クラスから、Manufacturer と Model の値を取得し、これらが Microsoft Corporation、Virtual Machine であったら、仮想マシンであると識別します。この方法は、MS さんのブログでも紹介されています。WSH を使うなら、次のようなスクリプトで仮想マシンか物理マシンかを識別できます。

[vmorpm.vbs]
--------------------------------------------------------------------------------
strComputer = "."
Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
Set colItems = objWMIService.ExecQuery("Select * From Win32_ComputerSystem")
For Each objItem in colItems
  If objItem.Manufacturer = "Microsoft Corporation" and objItem.Model = "Virtual Machine" then
    WScript.Echo "Virtual Machine"
  Else
    WScript.Echo "Physical Machine"
  End If
Next
--------------------------------------------------------------------------------

続いて、問題の仮想化テクノロジの識別ですが、これには、レジストリ キー HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters を使用します。Exchange アナライザー ツールの場合は、Virtual Server 2005 の仮想マシンではこのキーを生成され、Virtual PC 2004 の仮想マシンには存在しないと記されています。Virtual Server 2005 R2 SP1、Windows Virtual PC、Hyper-V 1.0、Hyper-V 2.0 の仮想マシンの場合はどうかというと、すべてに存在します。ただし、ゲスト OS にゲスト コンポーネントがインストールされている必要がありそうです。オフラインの VHD をマウントすると、キーが存在しないので、仮想マシンのゲスト OS が起動するごとに作成されるキーのようです。
すべての仮想環境において、HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters  キーの下に次の文字列値 (REG_SZ) が格納されています。これらの情報から、ホスト OS の名前と自分自身の仮想マシン名を知ることができます。

HostName
PhysicalHostName
PhysicalHostNameFullyQualified
VirtualMachineName

例えば、次の WSH スクリプトをゲスト OS で実行すれば、ホスト OS の FQDN を取得できます。

[getparenthost.vbs]
--------------------------------------------------------------------------------
Const HKEY_LOCAL_MACHINE = &H80000002
strComputer = "."
Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
strKeyPath = "SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters"
strValueName = "PhysicalHostnameFullyQualified"
objRegistry.GetStringValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
If IsNull(strValue) Then
  WScript.Echo "Virtualization Host:" & vbTab & "Unknown"
Else
  WScript.Echo "Virtualization Host:" & vbTab & strValue
End If
--------------------------------------------------------------------------------
Hyper-V 2.0 (Windows Server 2008 R2 および Hyper-V Server 2008 R2) の仮想マシンの場合は、さらに、次の DWORD 値が格納されています(残念ながら、Hyper-V 1.0 の仮想マシンには存在しません)。
 
HostingSystemEditionId: Win32_OperatingSystem の OperatingSystemSKU と一致
HostingSystemOsMajor: OS のメジャー バージョン
HostingSystemOsMinor: OS のマイナー バージョン
HostingSystemProcessorArchitecture:  プロセッサ アーキテクチャ?
HostingSystemSpMajor:  サービスパック メジャー番号
HostingSystemSpMinor:  サービス パック マイナー番号

HostingSystemOsMajor は 6、HostingSystemOsMinor は 1 なので、Windows Server 2008 R2 および Hyper-V Server 2008 R2 のバージョン 6.1 と一致しています。HostingSystemEditionId は、Win32_OperatingSystem の OperatingSystemSKU と一致しており、エディションの識別に使えます。

OperatingSystemSKU (http://msdn.microsoft.com/en-us/library/ms724358(VS.85).aspx)
7     Standard
8     Datacenter
10   Enterprise
12   Datacenter Server Core
13   Standard Server Core
14   Enterprise Server Core
42   Hyper-V Server

例えば、ゲスト OS で次の WSH スクリプトを実行すれば、Hyper-V 2.0 環境に限り、ホスト OS の情報を取得できます。

[getparenthostos.vbs]
--------------------------------------------------------------------------------
Const HKEY_LOCAL_MACHINE = &H80000002
strComputer = "."
Set objRegistry = GetObject("winmgmts:\\" & strComputer & "\root\default:StdRegProv")
strKeyPath = "SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters"
strValueName = "HostingSystemEditionId"
objRegistry.GetDwordValue HKEY_LOCAL_MACHINE,strKeyPath,strValueName,strValue
If IsNull(strValue) Then
  WScript.Echo "Host Operating System:" & vbTab & "Unknown"
Else
  Select Case strValue
  Case 7
    WScript.Echo "Host Operating System:" & vbTab & "Windows Server 2008 R2 Standard"
  Case 8
    WScript.Echo "Host Operating System:" & vbTab & "Windows Server 2008 R2 Datacenter"
  Case 10
    WScript.Echo "Host Operating System:" & vbTab & "Windows Server 2008 R2 Enterprise"
  Case 12
    WScript.Echo "Host Operating System:" & vbTab & "Windows Server 2008 R2 Datacenter Server Core"
  Case 13
    WScript.Echo "Host Operating System:" & vbTab & "Windows Server 2008 R2 Standard Server Core"
  Case 14
    WScript.Echo "Host Operating System:" & vbTab & "Windows Server 2008 R2 Enterprise Server Core"
  Case 42
    WScript.Echo "Host Operating System:" & vbTab & "Microsoft Hyper-V Server 2008 R2"
  End Select
End If
--------------------------------------------------------------------------------

結局のところ、Hyper-V 2.0 の仮想マシンであれば、ゲスト OS からホスト環境を正確に識別することができます。それ以外は、仮想環境か物理環境かの識別までになります。ただし、ホスト OS の名称を取得できるので、ホスト OS の WMI にリモートで接続して、ホスト OS から情報を引き出すことはできそうです。例えば、ホスト OS に KB950050 (Hyper-V 1.0 の正式リリース) が適用されていれば、Hyper-V 1.0 だとわかるでしょう。

次のスクリーンショットは、ゲスト OS から Hyper-V 2.0 のホスト環境を識別している例です。このスクリプトを Hyper-V 2.0 以外の環境で実行した場合、下から 2 つの情報は Unkonwn を出力します (無念です)。