How do you attach a Virtual Network Adapter to a VM Using WMI?
I am looking for samples or information on how to attach an external virtual network adapter to an instance of a VM. I have been able to successfully integrate with Hyper-V using WMI and C#. Any language sample would be great (vbscript, powershell, etc)
I believe it is related to Msvm_ExternalEthernetPort, but I don't see how to associate this to an instance of VM (Msvm_ComputerSystem).
Thanks!
Answers
Assuming you already have a virtual switch (virtual network), you’ll need to:
1. Create switch port on the virtual switch (“CreateSwitchPort” method of Msvm_VirtualSwitchManagementService).
2. Add either an Msvm_SyntheticEthernetPortSettingData or Msvm_EmulatedEthernetPortSettingData to the Computer system. “Synthetic” shows up as “Network Adapter” and “Emulated” shows up as “Legacy Network Adapter” in the Hyper-V UI.
3. Set the connection property of the setting data to the switch port you created in step 1.
The Msvm_ExternalEthernertPort represents a physical NIC so it's only useful in terms of the virtual switch connecting to the physical network.
This posting is provided "AS IS" with no warranties, and confers no rights.
You will need to create a switch port for the VM NIC to use when connecting to the virtual network. It sounds as if you are trying to re-use a port that is for the physical NIC to use when it connects to the virtual switch.
For step 2, you should use the AddVirtualSystemResources method of Msvm_VirtualSystemManagementService to add an Msvm_SyntheticEthernetPortSettingData to a virtual machine.
If you do a “SELECT * from Msvm_SyntheticEthernetPortSettingData” you should find an instance with “Default” in the instance ID that holds all the default values.
This posting is provided "AS IS" with no warranties, and confers no rights.
AggieMatt,
So far so good.
Before going into the next step, I'd like to add some comments related to your previous post:
1. You don't need to call NewGUID() method to get a new GUID and use it in the call CreateSwitchPort. The second parameter is just the name of the Port so you can use $PortName
2. When calling CreateSwitchPort, it is recommended to store the output to a variable ( which is of type ConcreteJob). And you can check some properties of this job to verify whether the call is successful or not. One of the properties is CreatedSwicthPort that points you to the full WMI PATH of the newly created port.
So your call should be:
$Status = $VSwitch_Mgmt.CreateSwitchPort$$VSwitch, $PortName, $PortName, $Scope)
$NewPortPath = $Status.CreatedSwitchPort
With that, we can look at the next step which would be to create a new instance of Msvm_SyntheticPortSettingData.
From previous posts, Keith mentions that you can query all instances of this class including the Default one. I think that is the trick!
You should find the default instance and create a new instance by simply cloning the default instance.
Let's assume that you have found one and stored it in variable called $Default
So here are the next steps:
# Clone it
$NewSyntheticNIC = $Default.psbase.Clone()
# Assign the switch port to this NIC
$NewSyntheticNIC.Connection = $NewPortPath ( # see how it is useful now to save $Status.CreatedSwitchPort!)
#Now you have everything, then call AddVirtualSystemResources
$VM_ServiceMgmt.AddVirtualSystemResources($VM.__PATH, $NewSyntheticNIC.psbase.gettext(1))
Hope that helps!
/Dung
PS: Stephen,
Thanks for your kind words! At least you have found my blog useful!
Turns out I was getting Invalid Parameter. I added these lines of code and everything worked.
NewSyntheticNic.SetPropertyValue(
"ElementName", "Network Adapter"); string[] guids = new string[1];guids[0] =
"{" + System.Guid.NewGuid() + "}";NewSyntheticNic.SetPropertyValue(
"VirtualSystemIdentifiers", guids);In the end this process added a new adapter to the VM with the appropriate connection. The original adapter was still set to Not Connected in Hyper-V. I did not want add a new one, but change the original one. Thankfully, I was able to resolve this by:
1. Obtain an instance to the VM.
2. Obtain an instance to the particular SwitchPort. (Network Name + "_ExternalPort")
3. Get an instance of the VM's Msvm_VirtualSystemSettingData.
4. Get an instance of the VM's Msvm_SyntheticEthernetPortSettingData by (pseudo-select) Select * from Msvm_VirtualSystemSettingDataComponent where the GroupComponent is Like %Msvm_VirtualSystemSettingData.Path% and PartComponent is Like %Msvm_SyntheticEthernetPortSettingData%
5. Set the Msvm_SyntheticEthernetPortSettingData.Connection equal to the SwitchPort.Path from step 2
6. Finally call ModifyVirtualSystemResources with the VM from step1 and the Msvm_SyntheticEthernetPortSettingData from step 4.
I want to thank everyone for their help. I would not have been able to solve this without these responses to my post and Dung's blog on How to Modify Resources of VM: modifying the location of the vhd file was key to me solving this.
All Replies
Assuming you already have a virtual switch (virtual network), you’ll need to:
1. Create switch port on the virtual switch (“CreateSwitchPort” method of Msvm_VirtualSwitchManagementService).
2. Add either an Msvm_SyntheticEthernetPortSettingData or Msvm_EmulatedEthernetPortSettingData to the Computer system. “Synthetic” shows up as “Network Adapter” and “Emulated” shows up as “Legacy Network Adapter” in the Hyper-V UI.
3. Set the connection property of the setting data to the switch port you created in step 1.
The Msvm_ExternalEthernertPort represents a physical NIC so it's only useful in terms of the virtual switch connecting to the physical network.
This posting is provided "AS IS" with no warranties, and confers no rights.
The last step will be to commit the change to the computer system:
4. Call the method ModifyVirtualSystemResources (of Msvm_VirtualSystemManagementService) and pass 2 parameters: the fully qualified PATH of the virtual machine, and a pointer to the Msvm_SyntheticEthernetPortSettingData instance,
HTH
/Dung
Thank you for your responses. I see the logical connection now.
In the Virtual Network Manager settings the Virtual Adapter already exists. Let's call it slot1. This is the virtual adapter that I want to programatically attach to a new VM. Using CIM Studio I found this in msvm_SwitchPort table with Element name "slot1_ExternalPort". Given this, I think the following steps are:
1. find the switch port that has already been created using WQL: Select * from msvm_SwitchPort where ElementName = 'slot1_ExternalPort'.
2. Add the Msvm_SyntheticEthernetPortSettingData and set connection property to the switch port that was found in step 1. How do I Add this? Is this a WQL insert or is there a method to do this? I want to take the default values when creating this class and only modify the Connection property. I don't see an easy way to do this and hopefully there is an Add method that I'm missing.3: Call the method ModifyVirtualSystemResources (of Msvm_VirtualSystemManagementService) and pass 2 parameters: a reference to the virtual machine, and a pointer to the Msvm_SyntheticEthernetPortSettingData instance from step 2.
I appreciate the help!!
-Kevin
You will need to create a switch port for the VM NIC to use when connecting to the virtual network. It sounds as if you are trying to re-use a port that is for the physical NIC to use when it connects to the virtual switch.
For step 2, you should use the AddVirtualSystemResources method of Msvm_VirtualSystemManagementService to add an Msvm_SyntheticEthernetPortSettingData to a virtual machine.
If you do a “SELECT * from Msvm_SyntheticEthernetPortSettingData” you should find an instance with “Default” in the instance ID that holds all the default values.
This posting is provided "AS IS" with no warranties, and confers no rights.
The CreateSwitchPort method takes a parameter of Msvm_SwitchService according to prelim doc on MSDN. When I use CIM Studio I can not find Msvm_SwitchService. I then looked for CIM_SwitchService, but it has No instances available. I think this is odd since I do have another VM machine configured with a virtual network adapter.
What is the ScopeOfResidence parameter? This is a string.
Thanks
- Try Msvm_VirtualSwitch, which derives from CIM_SwitchService.
Yep yep.
There are some changes in the naming of WMI class between RC and Beta releases. The correct class is Msvm_VirtualSwictch.
As for Scope of Residence, it is used to control access to a Hyper-V object (VM, switch) using AzMan scope.
Basically you create roles in AzMAn ( Authorization Manager) by assigning tasks to this role. Then you give this role to users and finally create a scope that conatins roles and users.
Assign this scope to Hyper-V objects by setting its scope of residence attribute to the scope name defined in AzMan , you can the control who does what with those objects.
Hope that helps
?Dung
I'm working with Kevin on this. Is it clear to you that we are trying to connect a virtual network adapter that already exists in Hyper-V to a VM that we just (programmatically) imported? Or do you think we are trying to build a virtual network adapter and switch in Virtual Network Manager?
To put it another way, right click on a VM in Hyper-V Manager, select settings, select network adapter and change it from not connected to New Virtual Network and press OK. Not, Virtual Network Manager, Add External, name the new virtual network, set the connection type to external and select the physical NIC to connect this network to.
Your posts seem to be guiding us towards #2 and not #1. If that's already clear, I'm sorry, I just don't want to waste your time answering the wrong question.
Thanks,
Steve
BTW, Dung - Great blog posts on how to programmatically import and control VM's. Without that we wouldn't have gotten this far.
I think I figured out Part 1 (Create a new SwitchPort)
#Create a new SWITCH PORT
$VSwitch_Mgmt = gwmi -namespace root/virtualization Msvm_VirtualSwitchManagementService
$VSwitch = gwmi -namespace root/virtualization Msvm_VirtualSwitch
$newGuid = [guid]::NewGuid().ToString()
$PortName = "NEWVIRTUALPORT"
$Scope = ""
$VSwitch_Mgmt.CreateSwitchPort($VSwitch, $newGuid, $PortName, $Scope)
# Check your handy work:
gwmi -namespace root/virtualization Msvm_SwitchPort | Select ElementName, NameI can't seem to find the proper method for "Adding a new Virtual System Resource" using the AddVirtualSystemResources method of the Msvm_VirtualSystemManagementService Class
Specifically, the input into the ADD method is "ResourceSettingData", but I can't figure out how to make a new Msvm_SyntheticEthernetPortSettingData to pass into the method.
AggieMatt,
So far so good.
Before going into the next step, I'd like to add some comments related to your previous post:
1. You don't need to call NewGUID() method to get a new GUID and use it in the call CreateSwitchPort. The second parameter is just the name of the Port so you can use $PortName
2. When calling CreateSwitchPort, it is recommended to store the output to a variable ( which is of type ConcreteJob). And you can check some properties of this job to verify whether the call is successful or not. One of the properties is CreatedSwicthPort that points you to the full WMI PATH of the newly created port.
So your call should be:
$Status = $VSwitch_Mgmt.CreateSwitchPort$$VSwitch, $PortName, $PortName, $Scope)
$NewPortPath = $Status.CreatedSwitchPort
With that, we can look at the next step which would be to create a new instance of Msvm_SyntheticPortSettingData.
From previous posts, Keith mentions that you can query all instances of this class including the Default one. I think that is the trick!
You should find the default instance and create a new instance by simply cloning the default instance.
Let's assume that you have found one and stored it in variable called $Default
So here are the next steps:
# Clone it
$NewSyntheticNIC = $Default.psbase.Clone()
# Assign the switch port to this NIC
$NewSyntheticNIC.Connection = $NewPortPath ( # see how it is useful now to save $Status.CreatedSwitchPort!)
#Now you have everything, then call AddVirtualSystemResources
$VM_ServiceMgmt.AddVirtualSystemResources($VM.__PATH, $NewSyntheticNIC.psbase.gettext(1))
Hope that helps!
/Dung
PS: Stephen,
Thanks for your kind words! At least you have found my blog useful!
Thanks a bunch Dung!! You are truly amazing!!
I did finally get it to work (Here is the final PowerShell I used):
## Create a new SwitchPort
$VSwitch_Mgmt = gwmi -namespace root/virtualization Msvm_VirtualSwitchManagementService
$VSwitch = gwmi -namespace root/virtualization Msvm_VirtualSwitch
$PortName = "MyPortName"
$Scope = ""
$Status = $VSwitch_Mgmt.CreateSwitchPort($VSwitch, $PortName, $PortName, $Scope)
$NewPortPath = $Status.CreatedSwitchPort
## Add a new SyntheticEthernetPort
$DefaultNIC = gwmi -namespace root/virtualization Msvm_SyntheticEthernetPortSettingData | where {$_.InstanceID -like "*Default*"}
$NewSyntheticNIC = $DefaultNIC.psbase.Clone()
$NewSyntheticNIC.Connection = $NewPortPath
$NewSyntheticNIC.ElementName = "Network Adapter"
$SyntheticNICGUID = [guid]::NewGuid().ToString()
$NewSyntheticNIC.VirtualSystemIdentifiers = "{" + $SyntheticNICGUID + "}"
## Apply the settings to the selected computer
$VM_Mgmt = get-wmiobject -namespace root\virtualization Msvm_VirtualSystemManagementService
$VMName = "MyVMName"
$VM = get-wmiobject -namespace root\virtualization Msvm_ComputerSystem | where {$_.ElementName -like $VMName}
$VM_Mgmt.AddVirtualSystemResources($VM.__PATH, $NewSyntheticNIC.psbase.gettext(1))- Proposed As Answer byVirtQA Wednesday, September 09, 2009 7:12 AM
I'm making progress. However, when I call AddVirtualSystemResources I get back a Concrete_Job (4096) that ultimately errors with a JobState of 10. (exception).
string
[] conns = new string[1];conns[0] = (
string) SwitchPort.GetPropertyValue("__PATH");NewSyntheticNic.SetPropertyValue(
"Connection", conns); ManagementBaseObject inAddParams = mVMClass.GetMethodParameters("AddVirtualSystemResources"); ManagementBaseObject outAddParams;inAddParams.SetPropertyValue(
"TargetSystem", VM); string[] sRes = new string[1];sRes[0] = NewSyntheticNic.GetText(System.Management.
TextFormat.CimDtd20);inAddParams.SetPropertyValue(
"ResourceSettingData", sRes);outAddParams = mVMClass.InvokeMethod(
"AddVirtualSystemResources", inAddParams, null);I think the problem may be in cloning the NewSystheticNic in C#. Assuming the obj is the default instance then
ManagementObject) obj;// set obj to default instance
....
defNicSet = obj.Clone();
Should the instanceId remain the same?
Thanks Again.
Turns out I was getting Invalid Parameter. I added these lines of code and everything worked.
NewSyntheticNic.SetPropertyValue(
"ElementName", "Network Adapter"); string[] guids = new string[1];guids[0] =
"{" + System.Guid.NewGuid() + "}";NewSyntheticNic.SetPropertyValue(
"VirtualSystemIdentifiers", guids);In the end this process added a new adapter to the VM with the appropriate connection. The original adapter was still set to Not Connected in Hyper-V. I did not want add a new one, but change the original one. Thankfully, I was able to resolve this by:
1. Obtain an instance to the VM.
2. Obtain an instance to the particular SwitchPort. (Network Name + "_ExternalPort")
3. Get an instance of the VM's Msvm_VirtualSystemSettingData.
4. Get an instance of the VM's Msvm_SyntheticEthernetPortSettingData by (pseudo-select) Select * from Msvm_VirtualSystemSettingDataComponent where the GroupComponent is Like %Msvm_VirtualSystemSettingData.Path% and PartComponent is Like %Msvm_SyntheticEthernetPortSettingData%
5. Set the Msvm_SyntheticEthernetPortSettingData.Connection equal to the SwitchPort.Path from step 2
6. Finally call ModifyVirtualSystemResources with the VM from step1 and the Msvm_SyntheticEthernetPortSettingData from step 4.
I want to thank everyone for their help. I would not have been able to solve this without these responses to my post and Dung's blog on How to Modify Resources of VM: modifying the location of the vhd file was key to me solving this.
- Dear kbreton,
Would you so kind to post the entire code on how to add the nic and activate it?
Thanks in advance,
Luís Silva
