我正在使用此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)
现在..根本不再备份了。 另外..我没有收到任何错误消息。
答案 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)
你很好! ;)