Hyper-V WMI Using PowerShell Scripts – Part 3 (KVP's - Guest OS Version)

Update 12/5/12

A lot has changed since 2008 and many things have stayed the same…  I wanted to provide an update to some of the most commonly viewed posts and this was one of them.

For updated information on this topic please refer to my latest post Retrieving the IP Address Of A VM In Hyper-V .


Original Post

In part 1 we went over basic scripts and tools for gathering some generic information about virtual machines and in part 2 we went over VHD creation and WMI job’s.  In part 3 I am going to cover getting more detailed information about a guest operating system by using the KVP Exchange integration component.  KVP stands for Key Value Pair this is a service that runs in the guest operating system and allows some limited information to be passed from the guest to the host or parent and vice-verse.  For now we are going to focus only on the intrinsic KVP’s these are provided by default on virtual machines that have the integration components installed.  The intrinsic KVP’s include: FullyQualifiedDomainName, OsName, OsVersion, CSDVersion, OsMajorVersion, OsMinorVersion, OsBuildNumber, OsPlatformID, ServicePackMajor, SuiteMask, ProductType, ProcessorArhitecture.

I’ll start with the PowerShell script and results and then explain how to decipher each of the KVP’s values but first I want to thank Ed one of our top notch developers that provided me this script...

In the gray box is the body of the script, it’s a bit different then what we have seen in the past primarily because is what looks like a function at the top.  This function looking thing is a PowerShell filter, what the filter does is take a bunch of XML known in WMI as an “embedded instance" and converts it into objects.  If you want to see the XML in it’s raw form remove the "|Import-CimXml” from the last line of the script and you’ll see how handy this little filter is.

So what’s happening in this script?  I will ignore the filter for a moment so the first line is the the $Vm = Get-Wmi… So the first line should look pretty common now, we are getting a Msvm_ComputerSystem WMI object for a given virtual machine “Server 2008 – Test1".  The second line is new, we are running an Association query to get a Msvm_KvpExchangeCompoents WMI object for this VM, associations are an optimization in WMI you can think of them like a SQL join statement “Please give me all of the X that corresponds to Y”.  The third line is just taking the GuestIntrinsicExchangeItems property of the Msvm_KvpExchangeCompoents and piping or sending it (that’s the | character) to the Import-CimXml filter that’s written above.  Now for the filter, so all this filter is doing is using an XML xpath query to go over each “Instance/Property” node and adding it’s name and value to this CimObj object and then returning that object…

WMIKVP.ps1 PowerShell Script

filter Import-CimXml { $CimXml = [Xml]$_ $CimObj = New-Object -TypeName System.Object foreach ($CimProperty in $CimXml.SelectNodes("/INSTANCE/PROPERTY")) { $CimObj | Add-Member -MemberType NoteProperty -Name $CimProperty.NAME -Value $CimProperty.VALUE } $CimObj }

$Vm = Get-WmiObject -Namespace root\virtualization -Query "Select * From Msvm_ComputerSystem Where ElementName='Server 2008 - Test1'" $Kvp = Get-WmiObject -Namespace root\virtualization -Query "Associators of {$Vm} Where AssocClass=Msvm_SystemDevice ResultClass=Msvm_KvpExchangeComponent"

$Kvp.GuestIntrinsicExchangeItems | Import-CimXml


Output of the WMIKVP.ps1 Script

PS C:\> . 'D:\BlogsDemo\powerShell\Demo\WMIKVP.ps1'

Caption : Data : AUTOBVT-M02LJSS Description : ElementName : Name : FullyQualifiedDomainName Source : 2

Caption : Data : Windows Server (R) 2008 Enterprise Description : ElementName : Name : OSName Source : 2

Caption : Data : 6.0.6001 Description : ElementName : Name : OSVersion Source : 2

Caption : Data : Service Pack 1 Description : ElementName : Name : CSDVersion Source : 2

Caption : Data : 6 Description : ElementName : Name : OSMajorVersion Source : 2

Caption : Data : 0 Description : ElementName : Name : OSMinorVersion Source : 2

Caption : Data : 6001 Description : ElementName : Name : OSBuildNumber Source : 2

Caption : Data : 2 Description : ElementName : Name : OSPlatformId Source : 2

Caption : Data : 1 Description : ElementName : Name : ServicePackMajor Source : 2

Caption : Data : 0 Description : ElementName : Name : ServicePackMinor Source : 2

Caption : Data : 274 Description : ElementName : Name : SuiteMask Source : 2

Caption : Data : 3 Description : ElementName : Name : ProductType Source : 2

Caption : Data : 9 Description : ElementName : Name : ProcessorArchitecture Source : 2

Ok now how do you decipher all of these values like SuiteMask?   All of this data except the fully qualified domain name come from a Windows API GetVersionEx but what you really want to look at is the OSVERSIONINFOEX structure.  That documents each of these values, for example SuiteMask has a value of 274 above that's 0x112 and according to the documents that means this guest has: Remote Desktop support, Terminal Services is installed, and it's running an Enterprise SKU of Windows... 

There's a lot more you can do with the KVP's such as pushing custom data into the guest from the parent partition/host or providing data from the guest so that the parent partition/host can query it.  I can provide samples for this in a future post but only if you want me to - so tell me, actually tell me what posts you want maybe networking or offline vhd servicing or maybe import/export?

--Taylor Brown
--Hyper-V test team