导出多个vms

时间:2015-01-07 07:37:34

标签: backup virtual-machine hyper-v

我正在使用此C#代码在虚拟机管理器中完全备份我的虚拟机:

using Microsoft.SystemCenter.VirtualMachineManager;
using Microsoft.SystemCenter.VirtualMachineManager.UIAddIns;
using Microsoft.SystemCenter.VirtualMachineManager.UIAddIns.ContextTypes;
using Microsoft.VirtualManager.Remoting;
using System;
using System.AddIn;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Forms;

namespace Microsoft.VirtualManager.UI.AddIns.BackupAddIn
{
    [AddIn("Make Backup")]
    public class BackupAddIn : ActionAddInBase
    {
        protected const string PowershellPath = "%WINDIR%\\System32\\WindowsPowershell\\v1.0\\powershell.exe";
        protected const string DefaultDirectory = "you don't need to know this";
        protected const string WildcardVMName = "{{VMName}}";
        protected const string WildcardError = "{{Error}}";
        protected const string BackupDirectoryBase = "{{Base}}";
        protected const string BackupDirectoryName = "{{Name}}";
        protected const string BackupDirectoryDate = "{{Date}}";

        public enum JobState { Initialized, Success, Fail };

        protected const string BackupDirectoryTemplate = BackupDirectoryBase + "\\" + BackupDirectoryName + "\\" + BackupDirectoryDate + "\\";
        protected static readonly ReadOnlyCollection<string> AllowedBackupStates = new ReadOnlyCollection<string>(new string[] { "PowerOff", "Paused"/*, "Saved"*/});


        public override bool CheckIfEnabledFor(IList<ContextObject> contextObjects)
        {
            if (contextObjects != null && contextObjects.Count > 0)
            {
                foreach (var host in contextObjects.OfType<HostContext>())
                {
                    if (host.ComputerState != ComputerState.Responding)
                    {
                        return false;
                    }
                }
                return true;
            }

            return false;
        }

        public override void PerformAction(IList<ContextObject> contextObjects)
        {
            if (contextObjects != null)
            {
                // check if we have VMs selected
                var VMs = contextObjects.OfType<VMContext>();
                if (VMs != null && VMs.Count() > 0)
                {
                    // check if VMs are in a good state
                    var badVMs = VMs.Where(vm => AllowedBackupStates.Contains(vm.Status.ToString()) == false).ToArray();
                    if (badVMs != null && badVMs.Length > 0)
                    {
                        MessageBox.Show("Backup not possible!\r\nThe following VMs are still running:\r\n\r\n" + string.Join(", ", badVMs.Select(vm => vm.Name)));
                    }
                    else
                    {
                        // ask for backup directory
                        string backupDir = Microsoft.VisualBasic.Interaction.InputBox("Enter the export path for the selected virtual machine(s) on the host.", "Export path", DefaultDirectory);
                        if (string.IsNullOrEmpty(backupDir) == false)
                        {
                            if (backupDir.EndsWith("\\"))
                            {
                                backupDir = backupDir.Substring(0, backupDir.Length - 1);
                            }

                            // go
                            foreach (var vm in VMs)
                            {
                                exportVM(vm, backupDir);
                            }
                        }
                    }
                }
            }
        }

        public string getDate()
        {
            var date = DateTime.Now;
            return date.Year.ToString()
                + (date.Month < 10 ? "0" : "") + date.Month.ToString()
                + (date.Day < 10 ? "0" : "") + date.Day.ToString()
                + "-"
                + (date.Hour < 10 ? "0" : "") + date.Hour.ToString()
                + (date.Minute < 10 ? "0" : "") + date.Minute.ToString();
        }

        public void ManageJob(string name, JobState state, string message = null)
        {
            string command;
            if (state == JobState.Initialized)
            {
                command = string.Format("${0} = New-SCExternalJob -Name \"{0}\"", name);
            }
            else if (state == JobState.Success)
            {
                command = string.Format("Set-SCExternalJob -Job (Get-SCJob -Name \"{0}\")[0] -Complete -InfoMessage \"" + (string.IsNullOrEmpty(message) ? "Backup successfully completed." : message) + "\"", name);
            }
            else
            {
                command = string.Format("Set-SCExternalJob -Job (Get-SCJob -Name \"{0}\")[0] -Failed -InfoMessage \"" + (string.IsNullOrEmpty(message) ? "Backup FAILED." : message) + "\"", name);
            }

            PowerShellContext.ExecuteScript<Host>(
                command,
                (profiles, error) =>
                {
                    if (error != null)
                    {
                        MessageBox.Show("Cannot modify job state\r\nError: " + error.Problem);
                    }
                }
            );
        }

        public void exportVM(VMContext vm, string backupDir)
        {
            string date = getDate();
            string fullBackupDir = BackupDirectoryTemplate.Replace(BackupDirectoryBase, backupDir).Replace(BackupDirectoryName, vm.Name).Replace(BackupDirectoryDate, date);
            string jobname = "Backup_" + vm.Name.Replace("-", "_").Replace(" ", "_");
            string command = string.Format("Export-VM -Name '{0}' -Path '{1}'", vm.Name, fullBackupDir);

            execPSScript(jobname, command, vm, WildcardVMName + ": Backup successful.", WildcardVMName + ": Backup FAILED!\r\nError: " + WildcardError);
        }

        public String scvmmPsCommand(string command, VMContext vm)
        {
            return string.Format("Invoke-SCScriptCommand -Executable \"{0}\" -VMHost (Get-SCVMHost -ID \"{1}\") -CommandParameters \"{2}\" -RunAsynchronously -TimeoutSeconds 360000", PowershellPath, vm.VMHostId.ToString(), command);
        }

        public void execPSScript(string jobname, string command, VMContext vm, string successMessage, string errorMessage)
        {
            ManageJob(jobname, JobState.Initialized);
            PowerShellContext.ExecuteScript<Host>(
                scvmmPsCommand(command, vm),
                (vms, error) =>
                {
                    if (error != null)
                    {
                        ManageJob(jobname, JobState.Fail, errorMessage.Replace(WildcardVMName, vm.Name).Replace(WildcardError, error.Problem));
                    }
                    else
                    {
                        ManageJob(jobname, JobState.Success, successMessage.Replace(WildcardVMName, vm.Name));
                    }
                }
            );
        }
    }
}`

如果我选择多个vms并尝试备份它们,则除了一个之外的所有vms都会立即失败。

我需要以某种方式让主机在单独的PowerShell中执行每一个被调用的命令。

你知道这是否可能?

Export-VM是否适用于多个虚拟机?

---------------编辑UTC时间上午9:50

好的 - 我尝试使用cmd.exe启动每个PowerShell作为这样的新任务:

string.Format(Invoke-SCScriptCommand -Executable \"%WINDIR%\\System32\\cmd.exe\" -VMHost (Get-SCVMHost -ID \"{1}\") -CommandParameters \"START powershell {2}\" -RunAsynchronously -TimeoutSeconds 360000", PowershellPath, vm.VMHostId.ToString(), command)

现在..根本不再备份了。 另外..我没有收到任何错误消息。

1 个答案:

答案 0 :(得分:0)

要使代码生效,您需要告诉cmd.exe您希望它执行命令。只需将/C放在您的命令之前:

string.Format("Invoke-SCScriptCommand -Executable \"%WINDIR%\\System32\\cmd.exe\" -VMHost (Get-SCVMHost -ID \"{1}\") -CommandParameters \"/C START powershell {2}\" -RunAsynchronously -TimeoutSeconds 360000", PowershellPath, vm.VMHostId.ToString(), command)

你很好! ;)