上一篇贴了创建的脚本,这篇说一下怎么在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%正常关机(因为此时虚拟机的系统才刚刚启动阻碍关机的服务还没有起来)。这个办法在想到的时候被同组的小伙伴黑成狗,不过最后还是用的这个办法(再黑也要实现功能!!!)。