Customizing The Key Value Pair (KVP) Integration Component

This is effectively and update from one my very old posts Hyper-V WMI: KVP Exchange aka Data Exchange (Retrieving and Modifying Parent/Host KVP’s) which still receives a lot of traffic.  The same code from back in 2008 still works today even on Windows Server 2012 – however with Windows Server 2012 we have introduced a new version of our WMI API’s (WMI v2) and for future releases the old code may stop working as we have not committed to (or not to) supporting the old version 1 API’s.  In the case of the Msvm_KvpExchangeComponent class not much has changed – literally the only difference between the version 1 sample and version 2 sample below is the ‘\v2’ in the namespace, this is not true for most other components.

 

Adding/Modifying Key Value Pairs From A Guest

Adding values from within the guest is as simple as creating a new registry value under the HKLM\Software\Microsoft\Virtual Machine\Guest section of the registry.  You do have to be an administrator in the VM in order to access this section of the registry.  Retreating the value from the host or a remote machine with permissions on the host is just a WMI query away.

Adding A New Key Value Pair In The Guest

$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest“
Set-ItemProperty -Path $regPath -Name "Status" -Value “Ready" -Type String

Modifying the value is as easy as just changing the value above…

Reading The Value From The Host – Using WMI Version 2 Namespace

$vm = Get-WmiObject -Namespace root\virtualization \v2 -Class `
    Msvm_ComputerSystem -Filter {ElementName = 'Vm1' }

$vm.GetRelated("Msvm_KvpExchangeComponent").GuestExchangeItems | % { `
    $GuestExchangeItemXml = ([XML]$_).SelectSingleNode(`
        "/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text() = 'Status']")

    if ($GuestExchangeItemXml -ne $null)
    {
        $GuestExchangeItemXml.SelectSingleNode(`
            "/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()").Value
    }
}

Reading The Value From The Host – Using WMI Version 1 Namespace

$vm = Get-WmiObject -Namespace root\virtualization -Class `
    Msvm_ComputerSystem -Filter {ElementName = 'Vm1'}

$vm.GetRelated("Msvm_KvpExchangeComponent").GuestExchangeItems | % { `
    $GuestExchangeItemXml = ([XML]$_).SelectSingleNode(`
        "/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text() = 'Status']")

    if ($GuestExchangeItemXml -ne $null)
    {
        $GuestExchangeItemXml.SelectSingleNode(`
            "/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()").Value
    }
}

Adding/Modifying Key Value Pairs From A Host

To add a key value pair from the host you must get the instance of the management service as well as the VM.  You must also create a new instance of the Msvm_KvpExchangeDataItem class – I build the path to this class using the instance of the management service such that if the script is running remotely it will connect to the right server.  Once you have the new instance of the class you just need to specify the Name, Data and Source parameters (source must be 0).  Then just call the AddKvpItems Method providing the instance of the VM and the instance of the created class.

Querying for key value pairs created from the host is very similar to ones from the guest except that you have to go though one more association to get to the Msvm_KvpExchangeComponentSettingsData class other than that it’s pretty much the same process.  Modifying and deleting values is almost the same as creating them – you just specify the same Key name as the value you wish to update/delete and call the Modify or Delete method.

Note that the example below utilizes the V2 namespace, if you are using Windows Server 2008 or R2 you can remove the \v2 and the script will work just fine.

Adding A New Key Value Pair

$VmMgmt = Get-WmiObject -Namespace root\virtualization \v2 -Class `
Msvm_VirtualSystemManagementService

$vm = Get-WmiObject -Namespace root\virtualization \v2 -Class `
Msvm_ComputerSystem -Filter {ElementName= 'VM1' }

$kvpDataItem = ([WMIClass][String]::Format("\\{0}\{1}:{2}", `
$VmMgmt.ClassPath.Server, `
$VmMgmt.ClassPath.NamespacePath, `
"Msvm_KvpExchangeDataItem")).CreateInstance()

$kvpDataItem.Name = "Name"
$kvpDataItem.Data = "Data"
$kvpDataItem.Source = 0

$VmMgmt.AddKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))

Querying For Key Value Pairs In The Guest

$regPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\External"
Get-ItemProperty -Path $regPath -Name "Name"

Querying For Key Value Pairs On The Host

$VmMgmt = Get-WmiObject -Namespace root\virtualization \v2 -Class `
Msvm_VirtualSystemManagementService

$vm = Get-WmiObject -Namespace root\virtualization \v2 -Class `
Msvm_ComputerSystem -Filter {ElementName= 'VM1' }

($vm.GetRelated("Msvm_KvpExchangeComponent")[0] `
).GetRelated("Msvm_KvpExchangeComponentSettingData").HostExchangeItems | % { `
$GuestExchangeItemXml = ([XML]$_).SelectSingleNode(`
"/INSTANCE/PROPERTY[@NAME='Name']/VALUE[child::text() = 'Name2']")

if ($GuestExchangeItemXml -ne $null)
{
$GuestExchangeItemXml.SelectSingleNode(`
"/INSTANCE/PROPERTY[@NAME='Data']/VALUE/child::text()").Value
}
}

Modifying Key Value Pairs

$VmMgmt = Get-WmiObject -Namespace root\virtualization \v2 -Class `
Msvm_VirtualSystemManagementService

$vm = Get-WmiObject -Namespace root\virtualization \v2 -Class `
Msvm_ComputerSystem -Filter {ElementName= 'VM1' }

$kvpDataItem = ([WMIClass][String]::Format("\\{0}\{1}:{2}", `
$VmMgmt.ClassPath.Server, `
$VmMgmt.ClassPath.NamespacePath, `
"Msvm_KvpExchangeDataItem")).CreateInstance()

$kvpDataItem.Name = "Name"
$kvpDataItem.Data = "Data2"
$kvpDataItem.Source = 0

$VmMgmt.ModifyKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))

Removing Key Value Pairs

$VmMgmt = Get-WmiObject -Namespace root\virtualization \v2 -Class `
Msvm_VirtualSystemManagementService

$vm = Get-WmiObject -Namespace root\virtualization \v2 -Class `
Msvm_ComputerSystem -Filter {ElementName='VM1'}

$kvpDataItem = ([WMIClass][String]::Format("\\{0}\{1}:{2}", `
$VmMgmt.ClassPath.Server, `
$VmMgmt.ClassPath.NamespacePath, `
"Msvm_KvpExchangeDataItem")).CreateInstance()

$kvpDataItem.Name = "Name"
$kvpDataItem.Data = [String]::Empty
$kvpDataItem.Source = 0

$VmMgmt.RemoveKvpItems($Vm, $kvpDataItem.PSBase.GetText(1))

 

-taylorb

Comments

  • Anonymous
    December 11, 2012
    Hi Taylor Small question. Is it working for Windows 8 Hyper-V? Under Win8 I can't find classes Msvm_ComputerSystem and Msvm_VirtualSystemManagementService.

  • Anonymous
    December 11, 2012
    Anton, Yes it is - but you first have to enable the Hyper-V role and the classes are under the rootvirtualizationv2 namespace. -taylor

  • Anonymous
    December 17, 2012
    Taylor - Is there an event that can be trapped in the guest OS (i.e., through Task Scheduler) that could in effect "wake" on addition or removal of a KVP pushed through from the host?

  • Anonymous
    January 28, 2013
    This is fantastic information. I am going to incorporate this immediately into the solution I am building for System Center + HVR (basically making these PS scripts work within System Center Orchestrator). I will give you all due credits and cross-reference this post when I publish my solution. Thanks for sharing! :D

  • Anonymous
    March 25, 2013
    Is there a way to get guest's free memory (memory utilization) using KVP? Obs.: The guest is not using dynamic memory.

  • Anonymous
    March 26, 2013
    @Mike Stopper - Mike, there is not but that is a great idea and I'll see if we can incorporate that into a future release. @Ussantos - The only way to accomplish that would be to have a service in the guest to 'publish' this information into the registry.

  • Anonymous
    April 16, 2013
    Taylor, I see when reading the KvpDataItem you are manually parsing the simplified MOF as an XML string but when writing it you are able to create an instance of Msvm_KvpExchangeDataItem and then serialize it into MOF with GetText(1).  Is there any wayt that the read can be simplified by serializing the text into a Msvm_KvpExchangeDataItem?

  • Anonymous
    September 18, 2013
    The comment has been removed

  • Anonymous
    September 19, 2013
    Ross, With Windows 8.1 and Windows Server 2012 R2 you must now utilize the rootvirtualizationv2 namespace.  We have started a porting guide at social.technet.microsoft.com/.../19192.hyper-v-wmi-v2-porting-guide.aspx. -taylor