导出多个虚拟机
exporting multiple vms
我正在使用此 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("[==] = 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));
}
}
);
}
}
}`
如果我 select 多个虚拟机并尝试备份它们,除了一个以外的所有虚拟机都会立即失败。
我需要以某种方式让主机在单独的 powershell 中执行每个调用的命令。
你知道这是否可能吗?
Export-VM
是否适用于多个虚拟机?
----------------编辑 9:50 上午 UTC+1
好的 - 我尝试使用 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)
现在..它不再备份了。
另外..我没有收到任何错误消息。
为了使您的代码正常工作,您需要告诉 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)
欢迎您! ;)
我正在使用此 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("[==] = 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));
}
}
);
}
}
}`
如果我 select 多个虚拟机并尝试备份它们,除了一个以外的所有虚拟机都会立即失败。
我需要以某种方式让主机在单独的 powershell 中执行每个调用的命令。
你知道这是否可能吗?
Export-VM
是否适用于多个虚拟机?
----------------编辑 9:50 上午 UTC+1
好的 - 我尝试使用 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)
现在..它不再备份了。 另外..我没有收到任何错误消息。
为了使您的代码正常工作,您需要告诉 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)
欢迎您! ;)