Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] [HyperV2012R2+] Refactor for performance #225

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -377,6 +377,7 @@
<Compile Include="Virtualization\Config\LibraryItem.cs" />
<Compile Include="Virtualization\LogicalDisk.cs" />
<Compile Include="Virtualization\DvdDriveInfo.cs" />
<Compile Include="Virtualization\CimSessionMode.cs" />
<Compile Include="Virtualization\MonitoredObjectAlert.cs" />
<Compile Include="Virtualization\MonitoredObjectEvent.cs" />
<Compile Include="Virtualization\MountedDiskInfo.cs" />
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;

namespace SolidCP.Providers.Virtualization
{
public enum CimSessionMode
{
DCom = 0,
WSMan = 1
}
}
Original file line number Diff line number Diff line change
@@ -55,6 +55,7 @@ public enum SummaryInformationRequest
GuestOperatingSystem = 106,
Snapshots = 107,
AsynchronousTasks = 108,
HealthState = 109
HealthState = 109,
VirtualSystemSubType = 135 //VM Generation
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using SolidCP.Providers.HostedSolution;
using Microsoft.Management.Infrastructure;
using SolidCP.Providers.HostedSolution;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -85,6 +86,27 @@ public static ConcreteJob CreateFromWmiObject(ManagementObject objJob)
return job;
}

public static ConcreteJob CreateFromCimObject(CimInstance cimJob)
{
if (cimJob == null || cimJob.CimInstanceProperties.Count == 0)
return null;

var objJob = cimJob.CimInstanceProperties;

ConcreteJob job = new ConcreteJob();
job.Id = (string)objJob["InstanceID"].Value;
job.JobState = (ConcreteJobState)Convert.ToInt32(objJob["JobState"].Value);
job.Caption = (string)objJob["Caption"].Value;
job.Description = (string)objJob["Description"].Value;
job.StartTime = (System.DateTime)objJob["StartTime"].Value;
// TODO proper parsing of WMI time spans, e.g. 00000000000001.325247:000
job.ElapsedTime = DateTime.Now; //wmi.ToDateTime((string)objJob["ElapsedTime"]);
job.ErrorCode = Convert.ToInt32(objJob["ErrorCode"].Value);
job.ErrorDescription = (string)objJob["ErrorDescription"].Value;
job.PercentComplete = Convert.ToInt32(objJob["PercentComplete"].Value);
return job;
}

public static ConcreteJob CreateFromPSObject(Collection<PSObject> objJob)
{
if (objJob == null || objJob.Count == 0)
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using Microsoft.Management.Infrastructure;
using SolidCP.Providers.HostedSolution;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@@ -10,9 +12,99 @@

namespace SolidCP.Providers.Virtualization
{
public static class VirtualMachineHelper
public class VirtualMachineHelper
{
public static OperationalStatus GetVMHeartBeatStatus(PowerShellManager powerShell, string name)
private PowerShellManager _powerShell;
private MiManager _mi;
public VirtualMachineHelper(PowerShellManager powerShellManager, MiManager mi)
{
_powerShell = powerShellManager;
_mi = mi;
}

public static VirtualMachine CreateVirtualMachineFromCimInstance(CimInstance cimInsVm)
{
if (cimInsVm == null || cimInsVm.CimInstanceProperties.Count == 0)
return null;

var objVm = cimInsVm.CimInstanceProperties;

VirtualMachine vm = new VirtualMachine();
vm.VirtualMachineId = (string)objVm["Name"].Value;
vm.Name = (string)objVm["ElementName"].Value;
vm.State = (VirtualMachineState)Convert.ToInt32(objVm["EnabledState"].Value);
vm.Status = Convert.ToString(objVm["Status"].Value);
vm.Uptime = Convert.ToInt64(objVm["OnTimeInMilliseconds"].Value);
return vm;
}

public CimInstance GetSummaryInformation(string vmId, params SummaryInformationRequest[] requestedInformation)
{
if (string.IsNullOrWhiteSpace(vmId)) {
HostedSolutionLog.LogWarning("VM identifier cannot be empty.", nameof(vmId));
}
if (requestedInformation == null || requestedInformation.Length == 0) {
HostedSolutionLog.LogWarning("At least one SummaryInformationRequest must be provided.", nameof(requestedInformation));
}

CimInstance managementService = _mi.GetCimInstance("Msvm_VirtualSystemManagementService");
if (managementService == null) {
HostedSolutionLog.LogWarning("Failed to retrieve Msvm_VirtualSystemManagementService instance.");
}

uint[] reqif = new uint[requestedInformation.Length];
for (int i = 0; i < requestedInformation.Length; i++)
reqif[i] = (uint)requestedInformation[i];

CimInstance vmInstance = _mi.GetCimInstance("Msvm_ComputerSystem", "Name = '{0}'", vmId);
CimInstance settingData = _mi.GetAssociatedCimInstance(vmInstance, "Msvm_VirtualSystemSettingData", "Msvm_SettingsDefineState"); //Optimizated query
//CimInstance settingData = GetCimInstance("Msvm_VirtualSystemSettingData", "InstanceID Like 'Microsoft:{0}%'", vmId); //this is slower ~6 times that two the above query

if (settingData == null)
HostedSolutionLog.LogWarning($"Virtual machine with ID '{vmId}' not found.");

var inParams = new CimMethodParametersCollection
{
CimMethodParameter.Create("SettingData", new CimInstance[] { settingData }, CimType.ReferenceArray, CimFlags.None),
CimMethodParameter.Create("RequestedInformation", reqif, CimFlags.None),
};

CimMethodResult result = _mi.InvokeMethod(managementService, "GetSummaryInformation", inParams);

if (result.ReturnValue.Value is uint retVal && retVal != 0){
HostedSolutionLog.LogError(new Exception($"GetSummaryInformation returned error code: {retVal}"));
}

object summaryObj = result.OutParameters["SummaryInformation"].Value;
if (summaryObj is CimInstance[] summaryArray)
{
return summaryArray.FirstOrDefault();
}
else
{
return null;
}
}

public OperationalStatus GetVMHeartBeatStatusFromGetVmResult(Collection<PSObject> result, string name)
{
OperationalStatus status = OperationalStatus.None;
try
{
var statusString = TryToGetStatusString(result, "PrimaryOperationalStatus");
status = (OperationalStatus)Enum.Parse(typeof(OperationalStatus), statusString);
}
catch
{
HostedSolution.HostedSolutionLog.LogWarning("GetVMHeartBeatStatus: can not get OperationalStatus from Get-VM result");
status = GetVMHeartBeatStatus("PrimaryStatusDescription"); //try to get it again, but from Get-VMIntegrationService
}

return status;

}

public OperationalStatus GetVMHeartBeatStatus(string name)
{
OperationalStatus status = OperationalStatus.None;

@@ -21,7 +113,7 @@ public static OperationalStatus GetVMHeartBeatStatus(PowerShellManager powerShel
cmd.Parameters.Add("VMName", name);
cmd.Parameters.Add("Name", "HeartBeat");

Collection<PSObject> result = powerShell.Execute(cmd, true);
Collection<PSObject> result = _powerShell.Execute(cmd, true);
if (result != null && result.Count > 0)
{
//var statusString = result[0].GetProperty("PrimaryOperationalStatus");
@@ -33,7 +125,7 @@ public static OperationalStatus GetVMHeartBeatStatus(PowerShellManager powerShel
return status;
}

private static string TryToGetStatusString(Collection<PSObject> result, string propertyName, bool isLast = false) //burn in hell MS for your bugs!
private string TryToGetStatusString(Collection<PSObject> result, string propertyName, bool isLast = false) //burn in hell MS for your bugs!
{
string status = null;
try
@@ -53,7 +145,7 @@ public static OperationalStatus GetVMHeartBeatStatus(PowerShellManager powerShel
return status;
}

private static string ConvertToOperationalStatusTypeString(string str)
private string ConvertToOperationalStatusTypeString(string str)
{
switch (str)
{
@@ -80,15 +172,15 @@ private static string ConvertToOperationalStatusTypeString(string str)
return str;
}

public static int GetVMProcessors(PowerShellManager powerShell, string name)
public int GetVMProcessors(string name)
{
int procs = 0;

Command cmd = new Command("Get-VMProcessor");

cmd.Parameters.Add("VMName", name);

Collection<PSObject> result = powerShell.Execute(cmd, true);
Collection<PSObject> result = _powerShell.Execute(cmd, true);
if (result != null && result.Count > 0)
{
procs = Convert.ToInt32(result[0].GetProperty("Count"));
@@ -97,7 +189,7 @@ public static int GetVMProcessors(PowerShellManager powerShell, string name)
return procs;
}

public static void UpdateProcessors(PowerShellManager powerShell, VirtualMachine vm, int cpuCores, int cpuLimitSettings, int cpuReserveSettings, int cpuWeightSettings)
public void UpdateProcessors(VirtualMachine vm, int cpuCores, int cpuLimitSettings, int cpuReserveSettings, int cpuWeightSettings)
{
Command cmd = new Command("Set-VMProcessor");

@@ -107,45 +199,118 @@ public static void UpdateProcessors(PowerShellManager powerShell, VirtualMachine
cmd.Parameters.Add("Reserve", cpuReserveSettings);
cmd.Parameters.Add("RelativeWeight", cpuWeightSettings);

powerShell.Execute(cmd, true);
_powerShell.Execute(cmd, true);
}

public static void Delete(PowerShellManager powerShell, string vmName, string vmId, string server, string clusterName)
public void Delete(string vmName, string vmId, string clusterName)
{
if (!String.IsNullOrEmpty(clusterName))
{
Command cmdCluster = new Command("Remove-ClusterGroup");
cmdCluster.Parameters.Add("VMId", vmId);
cmdCluster.Parameters.Add("RemoveResources");
cmdCluster.Parameters.Add("Force");
powerShell.Execute(cmdCluster, false);
_powerShell.Execute(cmdCluster, false);
}
Command cmd = new Command("Remove-VM");
cmd.Parameters.Add("Name", vmName);
if (!string.IsNullOrEmpty(server)) cmd.Parameters.Add("ComputerName", server);
cmd.Parameters.Add("Force");
powerShell.Execute(cmd, false, true);
_powerShell.Execute(cmd, true, true);
}
public static void Stop(PowerShellManager powerShell, string vmName, bool force, string server)

public void Stop(string vmName, bool force)
{
Command cmd = new Command("Stop-VM");

cmd.Parameters.Add("Name", vmName);
if (force) cmd.Parameters.Add("Force");
if (!string.IsNullOrEmpty(server)) cmd.Parameters.Add("ComputerName", server);
//if (!string.IsNullOrEmpty(reason)) cmd.Parameters.Add("Reason", reason);
try
{
powerShell.Execute(cmd, false, true);
_powerShell.Execute(cmd, true, true);
}
catch
{
cmd = new Command("Stop-VM");
cmd.Parameters.Add("Name", vmName);
cmd.Parameters.Add("TurnOff");
powerShell.Execute(cmd, false);
_powerShell.Execute(cmd);
}

}

protected VirtualMachine GetVirtualMachineCim(string vmId, bool extendedInfo) //examples of MI
{
CimInstance cimVm = _mi.GetCimInstanceWithSelect(
"Msvm_ComputerSystem",
"Name, ElementName, EnabledState, Status, OnTimeInMilliseconds",
"Name = '{0}'", vmId); //Name = "GUID"
VirtualMachine vm = VirtualMachineHelper.CreateVirtualMachineFromCimInstance(cimVm);

if (vm != null)
{
CimInstance cimSettings = _mi.GetAssociatedCimInstance(cimVm, "Msvm_VirtualSystemSettingData", "Msvm_SettingsDefineState");
var objSettings = cimSettings.CimInstanceProperties;

CimInstance cimSummary = GetSummaryInformation(vmId,
SummaryInformationRequest.Heartbeat,
SummaryInformationRequest.MemoryUsage,
SummaryInformationRequest.ProcessorLoad,
SummaryInformationRequest.NumberOfProcessors);
var objSummary = cimSummary.CimInstanceProperties;

vm.CpuUsage = Convert.ToInt32(objSummary["ProcessorLoad"].Value);
vm.Version = Convert.ToString(objSettings["Version"].Value);

if (Convert.ToDouble(vm.Version) > Convert.ToDouble(Constants.ConfigurationVersion))
vm.RamUsage = Convert.ToInt32(Convert.ToUInt64(objSummary["MemoryUsage"].Value) / Constants.Size1M);
else
vm.RamUsage = Convert.ToInt32(Convert.ToUInt64(objSummary["MemoryAvailable"].Value) / Constants.Size1M);

CimInstance cimRamInfo = _mi.GetCimInstanceWithSelect(
"Msvm_MemorySettingData",
"VirtualQuantity",
"InstanceID Like 'Microsoft:{0}%'", vmId);
var ramInfo = cimRamInfo.CimInstanceProperties;
vm.RamSize = Convert.ToInt32(ramInfo["VirtualQuantity"].Value);

bool isDynamicMemoryEnabled = Convert.ToBoolean(ramInfo["DynamicMemoryEnabled"].Value);

vm.Generation = Convert.ToString(objSettings["VirtualSystemSubType"].Value).EndsWith(":2") ? 2 : 1;
vm.ProcessorCount = Convert.ToInt32(objSummary["NumberOfProcessors"].Value);

string parentRelPath = Convert.ToString(objSettings["Parent"].Value);
if (!string.IsNullOrEmpty(parentRelPath))
{
vm.ParentSnapshotId = parentRelPath.Split(new[] { "InstanceID=\"" }, StringSplitOptions.None)[1].Split('"')[0].Split(':')[1];
}

vm.Heartbeat = (OperationalStatus)Convert.ToInt32(objSummary["Heartbeat"].Value);
vm.CreatedDate = (System.DateTime)objSettings["CreationTime"].Value;

vm.ReplicationState = (ReplicationState)Convert.ToInt32(objSummary["ReplicationState"].Value);

//var commands = new List<Command>
//{
// new Command("Get-VM") { Parameters = { { "Id", vmId } } },
// new Command("Select-Object") { Parameters = { { "Property", new string[] { "IsClustered" } } } }
//};
//Collection<PSObject> result = PowerShell.Execute(commands, true);
//vm.IsClustered = result[0].GetBool("IsClustered");

//if (extendedInfo)
//{

//}

//if (isDynamicMemoryEnabled)
//{
// vm.DynamicMemory = MemoryHelper.GetDynamicMemory(PowerShell, vm.Name);
//}

}

return vm;
}
}
}

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
using Microsoft.Management.Infrastructure;
using Microsoft.Management.Infrastructure.Options;
using System;
using System.Linq;
using System.Text;

namespace SolidCP.Providers.Virtualization
{
public class MiManager : IDisposable //MI/CIM is WMIv2
{
private CimSession _session;
private readonly object _disposeThreadSafetyLock = new object();
private readonly string _namespacePath;

public bool IsDisposed { get; private set; } = false;

public MiManager(string targetComputer, CimSessionMode cimSessionMode, string namespacePath)
{
CimSessionOptions options;

switch (cimSessionMode)
{
case CimSessionMode.DCom:
options = new DComSessionOptions(); // old (WMI)
((DComSessionOptions)options).Impersonation = ImpersonationType.Impersonate;
break;
case CimSessionMode.WSMan:
options = new WSManSessionOptions(); // new MI (CIM)
break;
default:
throw new ArgumentException("Invalid CIM session option.", nameof(cimSessionMode));
}
//CimCredential Credentials = new CimCredential(PasswordAuthenticationMechanism.Default, "domain", "username", "securepassword");
//options.AddDestinationCredentials(Credentials);
string target = string.IsNullOrWhiteSpace(targetComputer) ? null : targetComputer;
_session = CimSession.Create(target, options);
_namespacePath = namespacePath;
}

public CimInstance GetCimInstance(string className)
{
return EnumerateCimInstances(className).FirstOrDefault();
}

/// <summary>
/// IMPORTANT! Use GetCimInstance without filter if possible (especially if it gets Accociations), as it is faster;
/// otherwise, you will likely have to use GetCimInstanceWithSelect.
/// </summary>
public CimInstance GetCimInstance(string className, string filter, params object[] args)
{
return GetCimInstanceWithSelect(className, null, filter, args);
}

public CimInstance GetAssociatedCimInstance(CimInstance sourceInstance, string resultClassName)
{
return EnumerateAssociatedInstances(sourceInstance, null, resultClassName).FirstOrDefault();
}

public CimInstance GetAssociatedCimInstance(CimInstance sourceInstance, string resultClassName, string associationClassName)
{
return EnumerateAssociatedInstances(sourceInstance, associationClassName, resultClassName).FirstOrDefault();
}

/// <summary>
/// Retrieves a single instance of the specified CIM class using a WQL SELECT query.
/// IMPORTANT! To improve performance, avoid using arg select "*" or "null". Instead, specify only the required properties.
/// </summary>
public CimInstance GetCimInstanceWithSelect(string className, string select, string filter, params object[] args)
{
if (string.IsNullOrWhiteSpace(className)) {
throw new ArgumentException("Class name cannot be empty.", nameof(className));
}

var queryBuilder = new StringBuilder();
queryBuilder.Append("SELECT")
.Append(" ")
.Append(string.IsNullOrWhiteSpace(select) ? "*" : select.Trim());

queryBuilder.Append(" ")
.Append("FROM")
.Append(" ")
.Append(className.Trim());

if (!string.IsNullOrWhiteSpace(filter)) {
queryBuilder.Append(" ")
.Append("WHERE")
.Append(" ")
.Append(filter.Trim());
}

string query = queryBuilder.ToString();
if (args != null && args.Length > 0) {
query = string.Format(query, args);
}
return QueryCimInstances(query).FirstOrDefault();
}

public CimClass GetCimClass(string className)
{
return _session.GetClass(_namespacePath, className, null);
}

/// <summary>
/// Queries instances of the specified CIM class.
/// </summary>
public CimInstance[] EnumerateCimInstances(string className)
{
AssertNotDisposed();
if (string.IsNullOrWhiteSpace(className)){
throw new ArgumentException("Class name cannot be empty.", nameof(className));
}

return _session.EnumerateInstances(_namespacePath, className).ToArray();
}

/// <summary>
/// IMPORTANT! Use EnumerateCimInstances if possible, as it is faster; otherwise, you will likely have to use SELECT.
/// Queries instances of the specified CIM class.
/// WQL - https://learn.microsoft.com/en-us/windows/win32/wmisdk/wql-sql-for-wmi.
/// </summary>
public CimInstance[] QueryCimInstances(string query)
{
AssertNotDisposed();
if (string.IsNullOrWhiteSpace(query)){
throw new ArgumentException("Query cannot be empty.", nameof(query));
}
return _session.QueryInstances(_namespacePath, "WQL", query).ToArray();
}

/// <summary>
/// Retrieves an array of CIM instances that are associated with the specified source instance using the given association parameters.
/// </summary>
/// <param name="sourceInstance">The source instance from which to retrieve associated instances.</param>
/// <param name="associationClassName">
/// =============================
/// IMPORTANT! If the association class is not specified, performance WILL BE significantly reduced.
/// =============================
/// The name of the association class that defines the relationship between the source and target objects.
/// Use null if no specific association class filter is needed.
/// </param>
/// <param name="resultClassName">
/// The name of the target (result) class. Use null if no specific result class filter is needed.
/// </param>
/// <param name="sourceRole">
/// Optional. The role of the source instance in the association. Pass null if not required.
/// </param>
/// <param name="resultRole">
/// Optional. The role of the target instance in the association. Pass null if not required.
/// </param>
/// <returns>
/// An array of CIM instances that are associated with the given source instance according to the specified parameters.
/// </returns>
public CimInstance[] EnumerateAssociatedInstances(
CimInstance sourceInstance,
string associationClassName,
string resultClassName,
string sourceRole = null,
string resultRole = null
)
{
AssertNotDisposed();

return _session.EnumerateAssociatedInstances(
_namespacePath,
sourceInstance,
associationClassName,
resultClassName,
sourceRole,
resultRole
).ToArray();
}

/// <summary>
/// Invokes the specified method on a given CIM instance.
/// </summary>
/// <param name="instance">The CIM instance.</param>
/// <param name="methodName">The method name to invoke.</param>
/// <param name="parameters">Optional method parameters.</param>
/// <returns>The result of the method invocation.</returns>
public CimMethodResult InvokeMethod(CimInstance instance, string methodName, CimMethodParametersCollection parameters = null)
{
AssertNotDisposed();

if (instance == null)
throw new ArgumentNullException(nameof(instance));
if (string.IsNullOrWhiteSpace(methodName))
throw new ArgumentException("Method name cannot be empty.", nameof(methodName));

return _session.InvokeMethod(instance, methodName, parameters);
}

internal void AssertNotDisposed()
{
lock (_disposeThreadSafetyLock)
{
if (IsDisposed)
{
throw new ObjectDisposedException(ToString());
}
}
}

public void Dispose()
{
if (!IsDisposed)
{
_session?.Dispose();
_session = null;
IsDisposed = true;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -60,6 +60,7 @@ public void Dispose()
if (RunSpace != null && RunSpace.RunspaceStateInfo.State == RunspaceState.Opened)
{
RunSpace.Close();
RunSpace.Dispose();
RunSpace = null;
}
}
@@ -78,6 +79,12 @@ public Collection<PSObject> Execute(Command cmd, bool addComputerNameParameter)
{
return Execute(cmd, addComputerNameParameter, false);
}

public Collection<PSObject> Execute(IEnumerable<Command> cmd, bool addComputerNameParameter)
{
return ExecuteInternal(cmd, addComputerNameParameter, false);
}

public Collection<PSObject> Execute(Command cmd, bool addComputerNameParameter, bool withExceptions)
{
if (isStatic)
@@ -86,6 +93,11 @@ public Collection<PSObject> Execute(Command cmd, bool addComputerNameParameter,
return ExecuteInternal(cmd, addComputerNameParameter, withExceptions);
}

public Collection<PSObject> Execute(IEnumerable<Command> cmd, bool addComputerNameParameter, bool withExceptions)
{
return ExecuteInternal(cmd, addComputerNameParameter, withExceptions);
}

///<summary>
///IMPORTANT: It is not recommended to use this method if the task/job can be implemented via WMI,
///as PowerShell does not guarantee that the session will remain open, which may result in the loss of the Job ID.
@@ -134,28 +146,36 @@ public Collection<PSObject> ExecuteFromStaticObj(Command cmd, bool addComputerNa
}
return results;
}
private Collection<PSObject> ExecuteInternal(Command cmd, bool addComputerNameParameter, bool withExceptions)//, bool asJobScript, bool ignoreStaticCheck)

private Collection<PSObject> ExecuteInternal(Command commands, bool addComputerNameParameter, bool withExceptions)
{
return ExecuteInternal(new List<Command> { commands }, addComputerNameParameter, withExceptions);
}

private Collection<PSObject> ExecuteInternal(IEnumerable<Command> commands, bool addComputerNameParameter, bool withExceptions)
{
HostedSolutionLog.LogStart("Execute");

List<object> errorList = new List<object>();

HostedSolutionLog.DebugCommand(cmd);
Collection<PSObject> results = null;

// Add computerName parameter to command if it is remote server
if (addComputerNameParameter)
{
if (!string.IsNullOrEmpty(_remoteComputerName))
cmd.Parameters.Add("ComputerName", _remoteComputerName);
}

// Create a pipeline
Pipeline pipeLine = RunSpace.CreatePipeline();
using (pipeLine)
{
// Add the command
pipeLine.Commands.Add(cmd);
var commandsList = commands.ToList();

if (addComputerNameParameter && !string.IsNullOrWhiteSpace(_remoteComputerName)) {
commandsList[0].Parameters.Add("ComputerName", _remoteComputerName.Trim());
}
foreach (Command cmd in commandsList)
{
HostedSolutionLog.DebugCommand(cmd);
// Add the command
pipeLine.Commands.Add(cmd);
}

// Execute the pipeline and save the objects returned.
results = pipeLine.Invoke();

Original file line number Diff line number Diff line change
@@ -35,6 +35,7 @@
<PlatformTarget>AnyCPU</PlatformTarget>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.Management.Infrastructure, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
<Reference Include="Microsoft.Storage.Vds">
<HintPath>..\..\Lib\References\Microsoft\Microsoft.Storage.Vds.dll</HintPath>
</Reference>
@@ -55,6 +56,7 @@
<Compile Include="..\VersionInfo.cs">
<Link>VersionInfo.cs</Link>
</Compile>
<Compile Include="MiManager.cs" />
<Compile Include="Constants.cs" />
<Compile Include="Extensions\PSObjectExtension.cs" />
<Compile Include="Extensions\StringExtensions.cs" />
Original file line number Diff line number Diff line change
@@ -103,8 +103,7 @@ internal ManagementObject GetRelatedWmiObject(ManagementObject obj, string class
{
ManagementObjectCollection col = obj.GetRelated(className);
ManagementObjectCollection.ManagementObjectEnumerator enumerator = col.GetEnumerator();
enumerator.MoveNext();
return (ManagementObject)enumerator.Current;
return enumerator.MoveNext() ? (ManagementObject)enumerator.Current : null;
}

internal void Dump(ManagementBaseObject obj)
Original file line number Diff line number Diff line change
@@ -39,11 +39,6 @@
<HintPath>..\..\Lib\References\Microsoft\Microsoft.Storage.Vds.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="SolidCP.Providers.Virtualization.HyperV2012R2, Version=1.2.1.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\SolidCP.Server\bin\HyperV2012R2\SolidCP.Providers.Virtualization.HyperV2012R2.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="System" />
<Reference Include="System.Configuration" />
<Reference Include="System.Core" />
@@ -78,6 +73,10 @@
<Name>SolidCP.Providers.HostedSolution</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\SolidCP.Providers.Virtualization.HyperV-2012R2\SolidCP.Providers.Virtualization.HyperV2012R2.csproj">
<Project>{ee40516b-93df-4cab-80c4-64dce0b751cc}</Project>
<Name>SolidCP.Providers.Virtualization.HyperV2012R2</Name>
</ProjectReference>
<ProjectReference Include="..\SolidCP.Server.Utils\SolidCP.Server.Utils.csproj">
<Project>{e91e52f3-9555-4d00-b577-2b1dbdd87ca7}</Project>
<Name>SolidCP.Server.Utils</Name>
Original file line number Diff line number Diff line change
@@ -30,6 +30,14 @@
Text="*" meta:resourcekey="ServerNameValidator" Display="Dynamic" SetFocusOnError="true" />
</td>
</tr>
<tr id="ServerCimSessionModeRow" runat="server">
<td colspan="2">
<asp:RadioButtonList ID="radioCimSessionMode" runat="server">
<asp:ListItem Value="0" meta:resourcekey="radioCimSessionModeDCom" Selected="True">DCom</asp:ListItem>
<asp:ListItem Value="1" meta:resourcekey="radioCimSessionModeWSMan">WSMan (experemental)</asp:ListItem>
</asp:RadioButtonList>
</td>
</tr>
<tr id="ServerErrorRow" runat="server">
<td colspan="2">
<asp:Label ID="locErrorReadingNetworksList" runat="server"
Original file line number Diff line number Diff line change
@@ -63,7 +63,10 @@ void IHostingServiceProviderSettings.BindSettings(StringDictionary settings)
{
txtServerName.Text = settings["ServerName"];
radioServer.SelectedIndex = (txtServerName.Text == "") ? 0 : 1;

radioCimSessionMode.SelectedValue = settings["CimSessionMode"];
radioCimSessionMode.SelectedIndex = string.IsNullOrEmpty(radioCimSessionMode.SelectedValue)
? 0 : radioCimSessionMode.SelectedIndex;

// bind networks
BindNetworksList();

@@ -205,10 +208,14 @@ void IHostingServiceProviderSettings.BindSettings(StringDictionary settings)

void IHostingServiceProviderSettings.SaveSettings(StringDictionary settings)
{
if (radioServer.SelectedIndex == 0)
if (radioServer.SelectedIndex == 0){
settings["ServerName"] = "";
else
settings["CimSessionMode"] = "0";
}
else{
settings["ServerName"] = txtServerName.Text.Trim();
settings["CimSessionMode"] = radioCimSessionMode.SelectedValue;
}

// MaintenanceMode
settings["MaintenanceMode"] = radioMaintenanceMode.SelectedValue;
@@ -450,11 +457,13 @@ private StringDictionary ConvertArrayToDictionary(string[] settings)
private void ToggleControls()
{
ServerNameRow.Visible = (radioServer.SelectedIndex == 1);
ServerCimSessionModeRow.Visible = (radioServer.SelectedIndex == 1);

txtRamReserve.Enabled = true;
if (radioServer.SelectedIndex == 0)
{
txtServerName.Text = "";
txtServerName.Text = "";
radioCimSessionMode.SelectedIndex = 0;
}
else
{