Hyper-V配置(四)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a5nan/article/details/50904886

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

猜你喜欢

转载自blog.csdn.net/a5nan/article/details/50904886