Get Hyper-V guest data without XML parsing

I recently needed to query the Hyper-V KVP Exchange data for a guest VM to find the currently configured IPv4 address of the VM’s network adapter. A quick search of the Internet reveals that the Msvm_KvpExchangeComponent WMI class is the source of this information and there are at least two blog posts that cover it well:

However, in both of these blogs, the actual data comes back as XML which is then parsed using XPath. The original XML looks something like this:

<INSTANCE CLASSNAME="Msvm_KvpExchangeDataItem">
 <PROPERTY NAME="Data" TYPE="string">
  <VALUE>169.254.103.5</VALUE>
 </PROPERTY>
 <PROPERTY NAME="Name" TYPE="string">
  <VALUE>RDPAddressIPv4</VALUE>
 </PROPERTY>
 <PROPERTY NAME="Source" TYPE="uint16">
  <VALUE>2</VALUE>
 </PROPERTY>
</INSTANCE>

As soon as I saw this XML I recognised it as the DMTF CIM XML format – the same format that the new PowerShell v3 CIM Cmdlets use to transport CIM instances over HTTP (I believe). If this is the format used by PowerShell, it seemed a reasonable assumption  that PowerShell or the .NET Framework must already have an implementation for deserializing this XML properly so I don’t have to code it myself.

With Reflector in hand, I started my investigation at ManagementBaseObject.GetText which converts to XML but I couldn’t find any complementary methods to go the other direction. I then proceeded to look at ManageBaseObject’s implementation of the ISerializable interface and corresponding constructor but that appears to use binary serialization of COM types.

Finally, I turned to the CimInstance class and its implementation of ISerializable and discovered the CimDeserializer. Unfortunately the CimDeserializer methods take a byte array as input and I had strings. So assuming round-tripping should work, I looked to the CimSerializer and tried passing it a CimInstance and inspected the byte array that was returned – every second byte is zero, and the rest fit within 7-bits… smells like Unicode.

Taking a small gamble I took the strings from the Msvm_KvpExchangeComponent instance, used System.Text.Encoding.Unicode to convert them to byte arrays and passed them to CimDeserializer.DeserializeInstance. Huzzah! Properly deserialized Msvm_KvpExchangeDataItem instances.

And here is the final PowerShell script to return the items for a given VM name: https://gist.github.com/jstangroome/6068782