Create a new Hyper-V VM (using WMI) with specific hardware - c#

I'm wanting to create a new Hyper-V VM with a determined amount of RAM, network card, number of processor cores, and attach a VHD file to the IDE controller.
The problem is that the Msvm_ResourceAllocationSettingData is not very easy to work with. The code I'm using doesn't work (this is code to attach a VHD to an existing VM, however I would also like to use it when creating a new VHD too).
public void AttachVhd(IdeChannel ideChannel, String vhdPath) {
// Get VirtualSystemSettingData
ManagementObject vssd = this.GetVirtualSystemSettingData();
// Get the IDE Controller
ManagementObject ideController = this.GetResourceAllocationSettingData(ResourceType.IdeController, ResourceSubType.IdeController);
// Create synthetic disk:
ManagementObject syntheticDiskRasd = this.GetResourceAllocationSettingData(ResourceType.Disk, ResourceSubType.DiskSynthetic);
syntheticDiskRasd["Parent"] = ideController.Path;
syntheticDiskRasd["Address"] = ideChannel == IdeChannel.Primary ? "0" : "1";
this.AddVirtualSystemResources(syntheticDiskRasd);
// Attach it
ManagementObject vhdRasd = this.GetResourceAllocationSettingData(ResourceType.StorageExtent, ResourceSubType.Vhd); ;
vhdRasd["Parent"] = syntheticDiskRasd.Path;
vhdRasd["Connection"] = new String[] { vhdPath };
this.AddVirtualSystemResources( vhdRasd );
// Cleanup
vhdRasd.Dispose();
syntheticDiskRasd.Dispose();
ideController.Dispose();
vssd.Dispose();
}
private ManagementObject GetResourceAllocationSettingData(ResourceType resourceType, ResourceSubType resourceSubType)
{
String desiredSubType = ResourceSubTypeStrings.GetString(resourceSubType); // Scout.Common.Extensions.GetDescription( resourceType );
using(ManagementObjectCollection settingsDatas = _vm.GetRelated("Msvm_VirtualSystemSettingData"))
foreach(ManagementObject settingData in settingsDatas)
{
using(ManagementObjectCollection rasds = settingData.GetRelated("Msvm_ResourceAllocationSettingData"))
foreach(ManagementObject rasd in rasds)
{
ResourceType rasdResourceType = (ResourceType)(UInt16)rasd["ResourceType"];
String rasdResourceSubType = (String)rasd["ResourceSubType"];
String rasdOtherType = (String)rasd["OtherResourceType"];
if( rasdResourceType == resourceType && rasdResourceSubType == desiredSubType )
{
return rasd;
}
}
}
return null;
}
private void AddVirtualSystemResources(ManagementObject rasd)
{
using (ManagementObject vmService = HyperV.GetManagementService())
{
ManagementBaseObject inParams = vmService.GetMethodParameters("AddVirtualSystemResources");
inParams["TargetSystem"] = _vm;
inParams["ResourceSettingsData"] = rasd.GetText(TextFormat.CimDtd20);
ManagementBaseObject outParams = vmService.InvokeMethod("AddVirtualSystemResources", inParams, options: null);
String[] addedResources = (String[])outParams["NewResources"];
OperationReturnCode returnValue = (OperationReturnCode)(UInt32)outParams["ReturnValue"];
if (returnValue == OperationReturnCode.JobStarted)
{
String jobPath = (String)outParams["Job"];
HyperV.MonitorJob(jobPath);
}
else if (returnValue == OperationReturnCode.Completed)
{
}
else
{
throw new ApplicationException( returnValue.ToString() );
}
}
}

Rather than find your problem, can I point you to an example that works?
See WmiCalls.DeployVirtualMachine in my Apache CloudStack Hyper-V plugin
Post a comment if you need additional detail, and I will update the answer.

Related

Object not resolving while using WMI for HyperV

I am using the official example from Microsoft docs to use WMI to start and shut down the virtual machine but Utility and ReturnCode objects aren't getting resolved. When I build the application I get
CS0103 The name 'Utility' does not exist in the current context
I am clueless
ManagementObject vm = Utility.GetTargetComputer(vmName, scope);
&
if ((UInt32)outParams["ReturnValue"] == ReturnCode.Started)
https://learn.microsoft.com/en-us/windows/win32/hyperv_v2/requeststatechange-msvm-computersystem
Running everything on Server 2019 with Hyper-V running proper.
Here is the complete code:
using System;
using System.Management;
namespace HyperVSamples
{
public class RequestStateChangeClass
{
public static void RequestStateChange(string vmName, string action)
{
ManagementScope scope = new ManagementScope(#"\\.\root\virtualization\v2", null);
ManagementObject vm = Utility.GetTargetComputer(vmName, scope);
if (null == vm)
{
throw new ArgumentException(
string.Format(
"The virtual machine '{0}' could not be found.",
vmName));
}
ManagementBaseObject inParams = vm.GetMethodParameters("RequestStateChange");
const int Enabled = 2;
const int Disabled = 3;
if (action.ToLower() == "start")
{
inParams["RequestedState"] = Enabled;
}
else if (action.ToLower() == "stop")
{
inParams["RequestedState"] = Disabled;
}
else
{
throw new Exception("Wrong action is specified");
}
ManagementBaseObject outParams = vm.InvokeMethod(
"RequestStateChange",
inParams,
null);
if ((UInt32)outParams["ReturnValue"] == ReturnCode.Started)
{
if (Utility.JobCompleted(outParams, scope))
{
Console.WriteLine(
"{0} state was changed successfully.",
vmName);
}
else
{
Console.WriteLine("Failed to change virtual system state");
}
}
else if ((UInt32)outParams["ReturnValue"] == ReturnCode.Completed)
{
Console.WriteLine(
"{0} state was changed successfully.",
vmName);
}
else
{
Console.WriteLine(
"Change virtual system state failed with error {0}",
outParams["ReturnValue"]);
}
}
public static void Main(string[] args)
{
if (args != null && args.Length != 2)
{
Console.WriteLine("Usage: <application> vmName action");
Console.WriteLine("action: start|stop");
return;
}
RequestStateChange(args[0], args[1]);
}
}
}
You have to use a Query instead now:
ManagementScope scope = new ManagementScope(#"root\virtualization\v2");
ObjectQuery query = new ObjectQuery(#"SELECT * FROM Msvm_ComputerSystem WHERE ElementName = '" + vmName + "'");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection collection = searcher.Get();
ManagementObject vm = null;
foreach (ManagementObject obj in collection)
{
vm = obj;
break;
}
For the ReturnCode use your own constant instead. You can look them up here: https://learn.microsoft.com/en-us/previous-versions/windows/desktop/virtual/requeststatechange-msvm-computersystem
Something like this:
if ((UInt32)outParams["ReturnValue"] == 0)
{
...
}
0 == all good. Use UInt32 not UInt16!
Remember to run your app as administrator!

Issues with ambiguous call

I'm having hard time figuring out what the problem is. I'm trying to make sort of process monitor which loads processes list, ID, username of owner,memory usage and description.. and this error is giving me really big headache.
private void Button1_Click(object sender, EventArgs e)
{
Process[] procList = Process.GetProcesses();
foreach (Process process in procList)
{
// get status
string status = (process.Responding == true ? "Responding" : "Not responding");
// get username and description
string query = "SELECT * FROM Win32_Process WHERE ProcessID = " + process.Id;
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
ManagementObjectCollection processList = searcher.Get();
dynamic response = new ExpandoObject();
response.Description = "";
response.Username = "Unknown";
foreach (ManagementObject obj in processList)
{
// get username
string[] argList = new string[] { string.Empty, string.Empty };
int returnValue = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
if (returnValue == 0)
response.Username = argList[0];
if (obj["ExecutablePath"] != null)
{
try
{
FileVersionInfo info = FileVersionInfo.GetVersionInfo(obj["ExecutablePath"].ToString());
response.Description = info.FileDescription;
}
catch { }
}
}
// get memory usage
int memsize = 0; // memsize in Megabyte
PerformanceCounter PC = new PerformanceCounter();
PC.CategoryName = "Process";
PC.CounterName = "Working Set - Private";
PC.InstanceName = process.ProcessName;
memsize = Convert.ToInt32(PC.NextValue()) / (int)(1024);
memsize = (memsize / 1024);
PC.Close();
PC.Dispose();
ListViewItem item = new ListViewItem();
item.Text = process.Id.ToString();
item.SubItems.Add(process.ProcessName);
item.SubItems.Add(status);
item.SubItems.Add(response.Username);
item.SubItems.Add(memsize.ToString() + " MB");
item.SubItems.Add(response.Description);
listView1.Items.Add(item);
}
}
When i try debugging the program, it outputs few of them without any problem, (see here -> https://i.imgur.com/D4ftBgb.png) and then error shows up -> https://i.imgur.com/m1R90hz.png
Because you use dynamic, method overload resolution is delayed until runtime. You have a null response.Username or response.Description, so the dynamic runtime doesn't know which overload to call. Compare:
public class Test
{
public static void Main()
{
dynamic bar = null;
try
{
Foo(bar);
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
}
private static void Foo(string f) { }
private static void Foo(int? o) { }
}
This throws the same exception, because both overloads can accept a null, and there is no further type information present.
To resolve this, either specify the overload explicitly by casting to string:
Foo((string)bar);
Or in your case, SubItems.Add((string)response.Username).
Or simply don't use dynamic to stuff your variables in, but keep them both declared as separate variables: string description = "", username = "".
The type of both your response.Username and response.Description is dynamic. The ListViewSubItemCollection.Add() can't decide which overload to use, therefore, you need to convert them to string.
Try the following:
string username = Convert.ToString(response.Username);
string description = Convert.ToString(response.Description);
ListViewItem item = new ListViewItem();
item.Text = process.Id.ToString();
item.SubItems.Add(process.ProcessName);
item.SubItems.Add(status);
item.SubItems.Add(username);
item.SubItems.Add(memsize.ToString() + " MB");
item.SubItems.Add(description);
listView1.Items.Add(item);
The best long term solution is to remove your use of dynamic and use an explicit class with Description and Username properties.
The most direct fix is to change:
response.Description = info.FileDescription;
to:
response.Description = info.FileDescription ?? "";
Why is that necessary (the ?? "")? It will allows the overload resolution to work correctly since Description will never be null. The reason why it doesn't work when null is that a null property of an ExpandoObject has no type associated with it. This is different to a normal class whereby the compiler knows that the type of the property is string.

Assign vlan to network adapter via wmi classes

Problem : Can't assign vlan to hyper-v virtual machine using Msvm_VirtualEthernetSwitchManagementService, and AddFeatureSettings method.
Can someone point me what am I doing wrong?
Also I've noticed that if I use WMI classes to create vNIC I'm not getting instance of Msvm_EthernetPortAllocationSettingData, but if I assign vNIC manually it get's created.. I'm having trouble with creating Msvm_EthernetPortAllocationSettingData via WMI also.
From code bellow I'm getting ReturnValue of 4096, which means that method was executed.. but no vlan was assigned.
ManagementPath syntheticAdapterSettingDataC = new ManagementPath("Msvm_EthernetSwitchPortVlanSettingData");
String syntheticVlanAdapterId = String.Format("{0}\\C\\952C5004-4465-451C-8CB8-FA9AB382B773\\{1}", adapter.GetPropertyValue("InstanceID"), Guid.NewGuid());
ManagementClass syntheticAdapterClassC =
new ManagementClass(scope, syntheticAdapterSettingDataC, objectOptions)
{
["AccessVlanId"] = 55,
["Caption"] = "Ethernet Switch Port VLAN Settings",
["Description"] = "Represents the vlan setting data.",
["ElementName"] = "Ethernet Switch Port VLAN Settings",
["InstanceID"] = syntheticVlanAdapterId,
["NativeVlanId"] = 0,
["OperationMode"] = 1,
["PrimaryVlanId"] = 0,
["PruneVlanIdArray"] = null,
["PvlanMode"] = 0,
["SecondaryVlanId"] = 0,
["SecondaryVlanIdArray"] = null,
["TrunkVlanIdArray"] = null,
};
var syntheticAdapterC = syntheticAdapterClassC.CreateInstance();
ManagementPath VirtualEthernetSwitchManagementServicePath= new ManagementPath("Msvm_VirtualEthernetSwitchManagementService");
ManagementClass VirtualEthernetSwitchManagementServiceClass = new ManagementClass(scope, VirtualEthernetSwitchManagementServicePath, objectOptions);
ManagementBaseObject inParams = VirtualEthernetSwitchManagementServiceClass.GetMethodParameters("AddFeatureSettings");
string queryFeature = string.Format("select * from Msvm_FeatureSettingData Where InstanceID = 'Microsoft:Definition\\\\952C5004-4465-451C-8CB8-FA9AB382B773\\\\Default'");
ManagementObjectSearcher searcherFeature = new ManagementObjectSearcher(scope, new ObjectQuery(queryFeature));
ManagementObjectCollection features = searcherFeature.Get();
ManagementObject feature = null;
foreach (ManagementObject instance in features)
{
feature = instance;
break;
}
string[] syntheticAdapterSettingsC = new string[1];
syntheticAdapterSettingsC[0] = syntheticAdapterC.GetText(TextFormat.CimDtd20);
inParams["AffectedConfiguration"] = feature.GetText(TextFormat.CimDtd20);
inParams["FeatureSettings"] = syntheticAdapterSettingsC;
ManagementObject service = null;
foreach (ManagementObject instance in VirtualEthernetSwitchManagementServiceClass.GetInstances())
{
service = instance;
}
ManagementBaseObject vlanOut = service.InvokeMethod("AddFeatureSettings", inParams, null);
After experimenting I've found an answer. What you need to do is create (or point to one if you have one already) instance of Msvm_EthernetPortAllocationSettingData with Msvm_VirtualSystemManagementService class using "AddResourceSettings" method.
To use "AddResourceSettings" method you will need to define :
AffectedConfiguration property, which is an instance of Msvm_VirtualSystemSettingData class
ResourceSettings property, which is an instance of Msvm_EthernetPortAllocationSettingData, but you need to put this instance in array.
Now you are ready to assign vlan. You will need to create instance of Msvm_EthernetSwitchPortVlanSettingData with Msvm_VirtualSystemManagementService class and "AddFeatureSettings" method.
To use "AddFeatureSettings" method you will need to define :
AffectedConfiguration, which is an instance of Msvm_EthernetPortAllocationSettingData
FeatureSettings, which is an instance of Msvm_EthernetSwitchPortVlanSettingData, which is also array
And that is that..
Cheers!
ya..know its kinda old, but lets save headache of other people trying to implement this. Following code will assign Network Adapter to a VM and set VLAN. Keep in mind, my '_dataFields' is struct with virtual machine data, so you will have to change few things here.
Add new Network Adapter and set VLAN
/// <summary>
/// For the given virtual machine, this sample adds a new Network Adapter device and
/// connects it to the specified switch. Note that in order to add a new Network Adapter
/// device to the virtual machine, the virtual machine must be in the power off state.
/// Also note that the maximum number of Network Adapter devices that may be configured
/// on a virtual machine is 8.
/// </summary>
public void ConnectVmToSwitch()
{
using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))
//
// Find the Ethernet switch we want to connect to.
//
using (ManagementObject ethernetSwitch = NetworkUtils.FindEthernetSwitch(_dataFields.SwitchName, _dataFields._scope))
//
// Find the virtual machine we want to connect.
//
using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))
//
// Get the virtual machine's settings object which is used to make configuration changes.
//
using (ManagementObject virtualMachineSettings = WmiUtils.GetVirtualMachineSettings(virtualMachine))
//
// Add a new synthetic Network Adapter device to the virtual machine.
//
using (ManagementObject syntheticAdapter = NetworkUtils.AddSyntheticAdapter(virtualMachine, _dataFields._scope))
//
// Now that we have added a network adapter to the virtual machine we can configure its
// connection settings.
//
using (ManagementObject connectionSettingsToAdd = NetworkUtils.GetDefaultEthernetPortAllocationSettingData(_dataFields._scope))
{
connectionSettingsToAdd["Parent"] = syntheticAdapter.Path.Path;
connectionSettingsToAdd["HostResource"] = new string[] { ethernetSwitch.Path.Path };
//
// Now add the connection settings.
//
using (ManagementBaseObject addConnectionInParams = managementService.GetMethodParameters("AddResourceSettings"))
{
addConnectionInParams["AffectedConfiguration"] = virtualMachineSettings.Path.Path;
addConnectionInParams["ResourceSettings"] = new string[] { connectionSettingsToAdd.GetText(TextFormat.WmiDtd20) };
using (ManagementBaseObject addConnectionOutParams = managementService.InvokeMethod("AddResourceSettings", addConnectionInParams, null))
{
WmiUtils.ValidateOutput(addConnectionOutParams, _dataFields._scope);
if (_dataFields.VlanID > 0)
{
string[] syntheticAdapterResult = (string[])addConnectionOutParams["ResultingResourceSettings"]; // Msvm_EthernetPortAllocationSettingData return object
string syntheticAdapterPath = syntheticAdapterResult[0]; // Msvm_EthernetPortAllocationSettingData path
using (ManagementClass vlanSettingsData = new ManagementClass("Msvm_EthernetSwitchPortVlanSettingData"))
{
vlanSettingsData.Scope = _dataFields._scope;
using (ManagementObject vlanData = vlanSettingsData.CreateInstance())
{
vlanData["AccessVlanId"] = _dataFields.VlanID;
vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;
// Modify the VM settings.
using (ManagementBaseObject inParams = managementService.GetMethodParameters("AddFeatureSettings"))
{
inParams["AffectedConfiguration"] = syntheticAdapterPath;
inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };
using (ManagementBaseObject outParams = managementService.InvokeMethod("AddFeatureSettings", inParams, null))
{
WmiUtils.ValidateOutput(outParams, _dataFields._scope);
}
}
}
}
}
}
}
}
}
Original code for assigning switch to the VM is from https://github.com/microsoft/Windows-classic-samples/blob/1d363ff4bd17d8e20415b92e2ee989d615cc0d91/Samples/Hyper-V/Networking/cs/ConnectVmToSwitch.cs i've just extended it to support VLAN usage. I dont have any parameters in call, since all data is in struct.
Add / Modify VLAN on existing network adapter on VM
/// <summary>
/// Gets any virtual machine's management object
/// </summary>
/// <param name="managementObject">Any management object</param>
/// <returns>Any virtual machine's management object.</returns>
public static ManagementObject
GetVirtualMachineManagementObject(ManagementObject managementObject, string className)
{
using (ManagementObjectCollection settingsCollection = managementObject.GetRelated(className))
{
ManagementObject virtualMachineSettings = GetFirstObjectFromCollection(settingsCollection);
return virtualMachineSettings;
}
}
/// <summary>
/// For the given virtual machine, this sample will add / modfiy VLAN on existing network adapter
/// </summary>
public void SetVLANToVMNetworkAdapter()
{
ManagementObject syntheticAdapter = null;
bool vlanAlreadySet = false;
using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))
//
// Find the virtual machine we want to connect.
//
using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))
//
// Now that we have added a network adapter to the virtual machine we can configure its
// connection settings.
//
using (ManagementObjectCollection findConnections = NetworkUtils.FindConnections(virtualMachine, _dataFields._scope))
{
if (findConnections.Count > 0)
{
foreach (ManagementObject connection in findConnections)
{
using (ManagementObjectCollection vmSwitches = connection.GetRelated("Msvm_SyntheticEthernetPortSettingData"))
{
if (vmSwitches.Count > 0)
{
foreach (ManagementObject vmSwitch in vmSwitches)
{
if (vmSwitch["ElementName"].ToString() == _dataFields.NetworkAdapterName)
{
//
// Got adapter on VM, lock it to connection object since we need connection path
// for vlan modifications
//
syntheticAdapter = connection;
//
// Got VLAN defiinition based on connection lock for vlan modifications
//
using (ManagementObjectCollection vmSwitcheVLANs = syntheticAdapter.GetRelated("Msvm_EthernetSwitchPortVlanSettingData"))
{
if (vmSwitcheVLANs.Count > 0)
vlanAlreadySet = true;
}
break;
}
}
}
}
}
}
if (syntheticAdapter != null && _dataFields.VlanID > 0)
{
string syntheticAdapterPath = syntheticAdapter.Path.Path;
if (vlanAlreadySet)
{
// VLAN is already set on adapter, change operation
// Modify the VM settings.
using (ManagementObject vlanData = WmiUtils.GetVirtualMachineManagementObject(syntheticAdapter, "Msvm_EthernetSwitchPortVlanSettingData"))
{
vlanData["AccessVlanId"] = _dataFields.VlanID;
vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;
using (ManagementBaseObject inParams = managementService.GetMethodParameters("ModifyFeatureSettings"))
{
inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };
using (ManagementBaseObject outParams = managementService.InvokeMethod("ModifyFeatureSettings", inParams, null))
{
WmiUtils.ValidateOutput(outParams, _dataFields._scope);
}
}
}
}
else
{
using (ManagementClass vlanSettingsData = new ManagementClass("Msvm_EthernetSwitchPortVlanSettingData"))
{
vlanSettingsData.Scope = _dataFields._scope;
using (ManagementObject vlanData = vlanSettingsData.CreateInstance())
{
vlanData["AccessVlanId"] = _dataFields.VlanID;
vlanData["OperationMode"] = (uint)_dataFields.VLANOperationalModes;
using (ManagementBaseObject inParams = managementService.GetMethodParameters("AddFeatureSettings"))
{
inParams["AffectedConfiguration"] = syntheticAdapterPath;
inParams["FeatureSettings"] = new string[] { vlanData.GetText(TextFormat.CimDtd20) };
using (ManagementBaseObject outParams = managementService.InvokeMethod("AddFeatureSettings", inParams, null))
{
WmiUtils.ValidateOutput(outParams, _dataFields._scope);
}
}
}
}
}
}
}
}
Delete VLAN from network adapter on VM
/// <summary>
/// For the given virtual machine, this sample will delete VLAN on existing network adapter
/// </summary>
public void RemoveVLANFromVMNetworkAdapter()
{
using (ManagementObject managementService = WmiUtils.GetVirtualMachineManagementService(_dataFields._scope))
//
// Find the virtual machine we want to connect.
//
using (ManagementObject virtualMachine = WmiUtils.GetVirtualMachine(_dataFields.VmName, _dataFields._scope))
//
// Now that we have added a network adapter to the virtual machine we can configure its
// connection settings.
//
using (ManagementObjectCollection findConnections = NetworkUtils.FindConnections(virtualMachine, _dataFields._scope))
{
if (findConnections.Count > 0)
{
foreach (ManagementObject connection in findConnections)
{
// Get network adapter on virtual machine
using (ManagementObjectCollection vmSwitches = connection.GetRelated("Msvm_SyntheticEthernetPortSettingData"))
{
if (vmSwitches.Count > 0)
{
foreach (ManagementObject vmSwitch in vmSwitches)
{
if (vmSwitch["ElementName"].ToString() == _dataFields.NetworkAdapterName)
{
// Get vlan settings data from network adapter
using (ManagementObjectCollection vmSwitcheVLANs = connection.GetRelated("Msvm_EthernetSwitchPortVlanSettingData"))
{
if (vmSwitcheVLANs.Count > 0)
{
// Get first objecz
using (ManagementObject vlanData = WmiUtils.GetFirstObjectFromCollection(vmSwitcheVLANs))
{
using (ManagementBaseObject inParams = managementService.GetMethodParameters("RemoveFeatureSettings"))
{
// Remove it
inParams["FeatureSettings"] = new string[] { vlanData.Path.Path };
using (ManagementBaseObject outParams = managementService.InvokeMethod("RemoveFeatureSettings", inParams, null))
{
WmiUtils.ValidateOutput(outParams, _dataFields._scope);
}
}
}
}
}
}
}
}
}
}
}
}
}
Keep in mind, i don't use general network adapter name, i'm using personalized ones when VM is being created. This way i can easily get adapter data when required.
Those who want to add personalized names for adapters can edit AddSyntheticAdapter(ManagementObject virtualMachine, ManagementScope scope) function and include different name in adapterToAdd["ElementName"] object.
Hope this helps to brave souls who are developing via WMI! :)

Check If Property Exists On Object C#

I am using a wmi call to get some info shown below
var queryObj = new ObjectQuery("SELECT * FROM Win32_Processor");
var vmSearcher = new ManagementObjectSearcher(queryObj);
foreach (ManagementObject MO in vmSearcher.Get())
{
if (MO.GetType().GetProperty("AddressWidth") != null)
{
Value = MO["AddressWidth"].ToString();
}
//TRY TO FORCE TO NOT EXIST TO TEST..IS THIS THE WAY TO FORCE A
//PROPERTY OUT??
MO["CurrentClockSpeed"] = null;
if (MO.GetType().GetProperty("CurrentClockSpeed") != null)
{
Value2 = MO["CurrentClockSpeed"].ToString();
}
}
The problem is some machines have some properties and others have other properties
How do I check if a property exists or not on a machine?
What I have isn't working
What I ultimately want is to simply print out properties of my choosing (like the on in the code sample) if they exist
public static object TryGetProperty(ManagementObject wmiObj, string propertyName)
{
object retval;
try
{
retval = wmiObj.GetPropertyValue(propertyName);
}
catch (System.Management.ManagementException ex)
{
retval = null;
}
return retval;
}

Using ManagementObjectSearcher to get an exact BitLocker WMI value

Good Day All,
I am having an issue with ManagementObjectSearcher. I am trying to query the exact value that i want but cannot find any reference to the precise syntax requirements and I continually receive an error when trying to finish out the code to be what I need it to be.
the specific portion of code that is presenting the issue is when I check for the drives Encryption state(I know for a fact that my disk is not encrypted on this machine, which is why that is the only value i have if'd currently). Any assistance in getting this code to pull the correct value would be greatly appreciated.
I've tried both the "=" method and the "LIKE" method with no change in output.
using Microsoft.Win32;
using System;
using System.Drawing;
using System.IO;
using System.Management;
using System.Windows.Forms;
public Form1()
{
InitializeComponent();
// Check for OS Version
string OSVer = Convert.ToString(Registry.GetValue("HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", "ProductName", null));
OSDialog.Text = OSVer;
// Check Architecture
if (Directory.Exists("C:\\Program Files (x86)"))
{
ArchitectureDialog.Text = "64 Bit";
}
else
{
ArchitectureDialog.Text = "32 Bit";
}
// Check Encryption
ManagementObjectSearcher Collect = new ManagementObjectSearcher("SELECT ProtectionStatus FROM Win32_EncryptableVolume WHERE DriveLetter = 'C:'");
string Encryption = Collect.ToString();
if (Encryption == "0")
{
EncryptionDialog.Text = "Disk is not Encrypted";
EncryptionDialog.ForeColor = Color.Green;
}
}
private void Cancel_Click(object sender, EventArgs e)
{
Close();
}
Getting BitLocker information from WMI requires elevated permissions. Your code has to be running as an admin and you have to ask for elevated privileges. So, I don't use ManagementObjectSearcher to obtain BitLocker info. Instead, I do something similar to the following (modified to your scenario - but not tested as shown):
ManagementObject GetBitLockerManager( string driveLetter )
{
var path = new ManagementPath( );
path.Server = string.Empty;
path.NamespacePath = #"\ROOT\CIMV2\Security\MicrosoftVolumeEncryption";
path.ClassName = "Win32_EncryptableVolume";
var options = new ConnectionOptions( );
options.Impersonation = ImpersonationLevel.Impersonate;
options.EnablePrivileges = true;
options.Authentication = AuthenticationLevel.PacketPrivacy;
var scope = new ManagementScope( path, options );
var mgmt = new ManagementClass( scope, path, new ObjectGetOptions( ) );
mgmt.Get( );
return mgmt
.GetInstances( )
.Cast<ManagementObject>( )
.FirstOrDefault
( vol =>
string.Compare
(
vol[ "DriveLetter" ] as string,
driveLetter,
true
) == 0
);
}
OK so I figured it out, thank you for all of the assistance provided. Code is below.
ManagementObjectSearcher Encryption = new ManagementObjectSearcher(#"root\cimv2\Security\MicrosoftVolumeEncryption", "SELECT * FROM Win32_EncryptableVolume");
foreach (ManagementObject QueryObj in Encryption.Get())
{
string EncryptionStatus = QueryObj.GetPropertyValue("ProtectionStatus").ToString();
if (EncryptionStatus == "0")
{
EncryptionDialog.Text = "Unencrypted";
}
else if (EncryptionStatus == "1")
{
EncryptionDialog.Text = "Encrypted - SysPrep will not complete";
}
else if (EncryptionStatus == "2")
{
EncryptionDialog.Text = "Cannot Determine Encryption";
}
}

Categories