Hyper-V 虛擬化技術(Hyper-V 2.0) Part II

Hyper-V 虛擬化技術(Hyper-V 2.0) Part II

上一篇Hyper-V 虛擬化技術(Hyper-V 2.0) Part I講解的是整體運作的機制

 

這篇並不會像上一篇一樣長篇大論,因為只會稍微的講解WMI與Hyper-V的關係

在此引用這個網站的圖片,來做一個簡單的圖解

http://www.msservermag.com.tw/technicwords/021128.aspx

01

微軟的MSDN中,有提供Hyper-V WMI Provider的文件可以參考

http://msdn.microsoft.com/en-us/library/cc136992(VS.85).aspx

 

在啟用Hyper-V後,會新增root\virtualization這個命名空間,我們可以透過PowerShell去查詢該命名空間底下所有的Object

指令是Get-Wmiobject –Namespace “root\virtualization” –Computer Hostname –list

WMI2

下圖這個範例,示範了如何透過WMI去查詢Guest OS的狀態

Get-WmiObject -Class Msvm_ComputerSystem -Namespace "root\virtualization" -ComputerName Hostname

其中的EnabledState就是回傳的狀態值,2代表正常

wmi

 

這邊看似沒甚麼了不起,GUI介面就可以得知的東西

呃…確實是如此,因為GUI介面就已經幫你寫好查詢的方法跟回傳,這裡只是大概講解Hyper-V Manager

是如何去取得Guest OS的狀態之類

 

但是如果是GUI介面所沒有的呢:P

或者你要用Job的方式從Host去控制Guest OS,而不是透過Guest OS的Job去控制呢?

這裡的命令,其實都是透過WMI去控制的

WMI3

接著來示範一個很奇特的範例,來驗證第一張圖,WMI的架構

我們先透過一個VBScript去使用Windows Script Host去呼叫CIMOM

然後,對Guest OS做鍵盤輸入的動作,首先先將下列VBScript存成PressKey.vbs

如對此VBScript不放心,您可以直接至Microsoft MSDN中複製

http://msdn.microsoft.com/en-us/library/cc136956(v=vs.85).aspx

 


option explicit 

dim objWMIService
dim fileSystem
const wmiSuccessful = 0

Main()

'-----------------------------------------------------------------
' Main routine
'-----------------------------------------------------------------
Sub Main()
    
    dim computer, objArgs, vmName, computerSystem, keycode, keyboard
    
    set fileSystem = Wscript.CreateObject("Scripting.FileSystemObject")

    computer = "."
    set objWMIService = GetObject("winmgmts:\\" & computer & "\root\virtualization")

    set objArgs = WScript.Arguments
    if WScript.Arguments.Count = 2 then
       vmName= objArgs.Unnamed.Item(0)
       keycode = objArgs.Unnamed.Item(1)
    else
       WScript.Echo "usage: cscript PressKey.vbs vmName keycode"
       WScript.Quit
    end if
    
    set computerSystem = GetComputerSystem(vmName)
    set keyboard = GetComputerKeyboard(computerSystem)

    if PressKey(keyboard, keycode) then

        WriteLog "Done"
        WScript.Quit(0)
    else
        WriteLog "PressKey failed"
        WScript.Quit(1)
    end if

End Sub

'-----------------------------------------------------------------
' Retrieve Msvm_VirtualComputerSystem from base on its ElementName
' 
'-----------------------------------------------------------------
Function GetComputerSystem(vmElementName)
    dim query
    On Error Resume Next
    query = Format1("select * from Msvm_ComputerSystem where ElementName = '{0}'", vmElementName)
    set GetComputerSystem = objWMIService.ExecQuery(query).ItemIndex(0)
    if (Err.Number <> 0) then
        WriteLog Format1("Err.Number: {0}", Err.Number)
        WriteLog Format1("Err.Description:{0}",Err.Description)
        WScript.Quit(1)
    end if
End Function


'-----------------------------------------------------------------
' Retrieve Msvm_Keyboard from given computer system
' 
'-----------------------------------------------------------------
Function GetComputerKeyboard(computerSystem)
    dim query
    On Error Resume Next
    query = Format1("ASSOCIATORS OF {{0}} WHERE resultClass = Msvm_Keyboard", computerSystem.Path_.Path)
    set GetComputerKeyboard = objWMIService.ExecQuery(query).ItemIndex(0)
    if (Err.Number <> 0) then
        WriteLog Format1("Err.Number: {0}", Err.Number)
        WriteLog Format1("Err.Description:{0}",Err.Description)
        WScript.Quit(1)
    end if
End Function

'-----------------------------------------------------------------
' Press the key with the given key code on the given keyboard
'-----------------------------------------------------------------
Function PressKey(keyboard, keyCode)
    WriteLog Format2("PressKey({0}, {1})", keyboard.ElementName, keyCode)
    
    dim objInParam, objOutParams
    
    PressKey = false
    set objInParam = keyboard.Methods_("PressKey").InParameters.SpawnInstance_()
    objInParam.keyCode = keyCode

    set objOutParams = keyboard.ExecMethod_("PressKey", objInParam)

    if objOutParams.ReturnValue = wmiSuccessful then
        WriteLog Format2("The key with code '{0}' is typed on {1}.", keyCode, keyboard.ElementName)
        PressKey = true
    end if

End Function

'-----------------------------------------------------------------
' Create the console log files.
'-----------------------------------------------------------------
Sub WriteLog(line)
    dim fileStream
    set fileStream = fileSystem.OpenTextFile(".\PressKey.log", 8, true)
    WScript.Echo line
    fileStream.WriteLine line
    fileStream.Close

End Sub


'------------------------------------------------------------------------------
' The string formatting functions to avoid string concatenation.
'------------------------------------------------------------------------------
Function Format2(myString, arg0, arg1)
    Format2 = Format1(myString, arg0)
    Format2 = Replace(Format2, "{1}", arg1)
End Function

'------------------------------------------------------------------------------
' The string formatting functions to avoid string concatenation.
'------------------------------------------------------------------------------
Function Format1(myString, arg0)
    Format1 = Replace(myString, "{0}", arg0)
End Function

 

接著我們會需要這張表去對應Virtial Key相對應的Uint32的值

http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx

 

這張表的值是16進位,將其換算成十進位後,加上256,會可以輸入該值到Guest OS中

像範例中,我會Daniel-AD這部Guest OS輸入鍵盤324,d這個字母在表列中為0x44

也就是256+68=324,接著他就會在Guest OS中輸入d這個字母

WMI4

 

你也可以透過Powershell去轉換這個數值

PowerShell的語法function To-UInt32{[UInt32]("0x{0:x}" -f $args[0])+256}

這可以新增一個To UInt32的轉換方法

接著可以透過To-UInt32 0x44去取得相對應的值

WMI5