Hyper-V配置(四)
阿新 • • 發佈:2018-11-02
上一篇貼了建立的指令碼,這篇說一下怎麼在C#下呼叫:
此部分程式碼包含兩種方法: Invoke 和 BeginInvoke ,兩者的區別就是後者導致工作執行緒等待,前者不會。因為關機要等到他關機結束以後虛擬機器的狀態顯示才是off,所以要用BeginInvoke等待他關機結束;而開機的話不需要,因為從接受到start虛擬機器命令開始虛擬機器的狀態就是running。
private static string startVMTemplet = @"function StartVM { param ( [string]$requestVMName = $(throw ""param -requestVMName is required."") ) Start-VM -Name $requestVMName }"; private static string stopVMTemplet = @"function StopVM { param ( [string]$requestVMName = $(throw ""param -requestVMName is required."") ) Stop-VM -Name $requestVMName -force }"; /* * vmname: VM name * return: Running for success case and Off for fail */ public VMState StartVM(string vmname) { if (vmname == null || vmname.Equals("")) { LogHelper.Write("error--StartHv: Name can not be empty!"); return 0; } try { string runScript = startVMTemplet; using (PowerShell psInstance = PowerShell.Create()) { Collection<PSObject> psOutput = null; // add hyperV management script, and invoke execution psInstance.AddScript(runScript); psOutput = psInstance.Invoke(); // run specified command psInstance.AddCommand("StartVM"); psInstance.AddParameter("requestVMName", vmname); psOutput = psInstance.Invoke(); // check the other output streams (for example, the error stream) if (psInstance.Streams.Error.Count > 0) { // default return is false foreach (ErrorRecord errorItem in psInstance.Streams.Error) { if (errorItem != null) { LogHelper.WriteWithDateTime("error--StartHv:{0}", errorItem.ToString()); } } } else { foreach (PSObject outputItem in psOutput) { // if null object was dumped to the pipeline during the script then a null // object may be present here. check for null to prevent potential NRE. if (outputItem != null) { LogHelper.WriteWithDateTime("info--StartHv:{0}", outputItem.BaseObject.ToString()); } } } } } catch (Exception ex) { LogHelper.WriteWithDateTime("ERROR--STARTHV:{0}", ex.Message); } return 1; } /* * vmname: VM name * return: Off for success case and Running for fail */ public VMState StopVMOnce(string vmname) { if (vmname == null || vmname.Equals("")) { LogHelper.Write("error--StopHv: Name can not be empty!"); return 0; } try { int nPastTimeinMs = 0; string runScript = stopVMTemplet; using (PowerShell psInstance = PowerShell.Create()) { // add hyperV management script, and invoke execution psInstance.AddScript(runScript); psInstance.Invoke(); // run specified command psInstance.AddCommand("StopVM"); psInstance.AddParameter("requestVMName", vmname); //psInstance.AddCommand("GetProc"); LogHelper.Write("info--StopHv: Call begininvoke start"); // prepare a new collection to store output stream objects PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>(); IAsyncResult async = psInstance.BeginInvoke<PSObject, PSObject>(null, outputCollection); LogHelper.Write("info--StopHv: Call begininvoke end"); while (async.IsCompleted == false) { LogHelper.Write("info--StopHv: Waiting for pipeline to finish..."); Thread.Sleep(1000); nPastTimeinMs += 1000; if (nPastTimeinMs > TIMEOUTFORSTOP) { LogHelper.Write("error--StopHv: StopHv timeout!"); throw (new TimeoutException("StopHv timeout")); } } LogHelper.Write("info--StopHv: Task finish"); if (psInstance.Streams.Error.Count > 0) { // default return is false foreach (ErrorRecord errorItem in psInstance.Streams.Error) { if (errorItem != null) { LogHelper.WriteWithDateTime("error--StopHv:{0}", errorItem.ToString()); } } } else { foreach (PSObject outputItem in outputCollection) { // if null object was dumped to the pipeline during the script then a null // object may be present here. check for null to prevent potential NRE. if (outputItem != null) { LogHelper.WriteWithDateTime("info--StopHv:{0}", outputItem.BaseObject.ToString()); } } } } } catch (Exception ex) { LogHelper.WriteWithDateTime("ERROR--STOPHV:{0}", ex.Message); } return 1; }
在執行StopVM時遇到一個很噁心的問題——卡在關機的過程中無法正常關機。對於這個問題懷疑過很多種可能,曾經一度認為網路服務未正常關閉導致的,後來發現並沒有那麼單純,到最後也沒有找到真正的原因。不過專案最後還是想到了一個歪門邪道的方法,那就是:先正常執行StopVM延時60秒結束(正常關機肯定能在60s內完成),檢查虛擬機器現行狀態,如果仍然是running,就用c#強制kill名為vmwp的程序(此程序為虛擬機器程序),不過這個程序會有保護,在被kill了之後會馬上重啟,此時虛擬機器裡的系統也再重啟,在這個時候再執行一次StopVM就能100%正常關機(因為此時虛擬機器的系統才剛剛啟動阻礙關機的服務還沒有起來)。這個辦法在想到的時候被同組的小夥伴黑成狗,不過最後還是用的這個辦法(再黑也要實現功能!!!)。