Scripting Hyper-V: Using Associations

I would like to take a moment to talk about some “scripting technique” for how to get the best results out of your code.  With our WMI interfaces there are often multiple ways to get results, but some are more efficient than others.  Let’s say that I wanted to get an instance of a network adapter that is connected to a virtual machine called “Home Server”.  I could do that using the following PowerShell code:

$vm = gwmi MSVM_ComputerSystem -filter "ElementName='Home Server'" -namespace "root\virtualization" 
$query = "Select * from Msvm_SyntheticEthernetPort where SystemName='" + $vm.Name + "'" 
$vnic = gwmi -query $query -namespace "root\virtualization"

This code gets the virtual machine object, and then searches through all instances of Msvm_SyntheticEthernetPort on the physical system to find the one that is connected to the virtual machine.  This works but will require a lot of work to be performed by Hyper-V, and this work will increase as the number of virtual machines (and network adapters) on the physical system increase.

Alternatively I can use this PowerShell code:

$vm = gwmi MSVM_ComputerSystem -filter "ElementName='Home Server'" -namespace "root\virtualization" 
$vnic = gwmi -query "Associators of {$vm} where ResultClass = Msvm_SyntheticEthernetPort" -namespace "root\virtualization"

This code looks through all class instances that are associated with the virtual machine.  This is much more efficient, and it will require the same amount of work by Hyper-V no matter how many virtual machines you have configured on the server.

In the Hyper-V WMI object model – all classes are linked together with “associations” – which is what you use to get from one class to another in a scalable fashion.  But in order to use them you need to know how classes are associated with each other.  The first thing to know is that for one class to be associated with another class, there will actually be a third class that is involved to create the actual connection.  For instance:

Msvm_SwitchPort is associated to Msvm_VirtualSwitch, and the association class that ties them together is Msvm_HostedAccessPoint.  You can piece this information together by reading the MSDN documentation – but it is not always readily apparent.  The easiest way that I have found for discovering this information is by using PowerShell directly.  In the example I have shown above, I can find out which classes are associated with the virtual machine by running the following command:

gwmi -query "Associators of {$vm}" -namespace "root\virtualization"

Which provides this sort of output:


Where you can see a list of all the associated classes.  The following code:

gwmi -query "References of {$vm}" -namespace "root\virtualization"

Will then show you all of the association classes that are being used to tie the above classes to the virtual machine object:


As you can see the last two properties of each association class are the full paths of the two classes that are being associated together.  Now that you know how this all works – I strongly encourage you to use associations whenever possible, and to only use “Select *” when there is no other way to achieve the results you want.

One final note – to get an association in VBScript you need to know both the association class and the result class.  You then use code like this:

Set InternalLanEndPoint = (InternalEthernetPort.Associators_("CIM_DeviceSAPImplementation", "Cim_LanEndpoint")).ItemIndex(0)

Here you call “.Associators_” on your object and first specify the association class followed by the result class that you want.