How to use uniquely identify a virtual machine in Hyper-V

When managing a large number of virtual machines, there is often a need to tag it in some way with one or more properties uniquely identifying it for administrative purposes. One example would be to identify a virtual machine as belonging to a person, team or business unit.

The Hyper-V WMI namespace has a number of BIOS properties which can be set when a virtual machine is turned off. As these properties are part of the virtual machine configuration, they are separate from the VHD or backing storage used by the virtual machine. These properties can also be read from within a guest operating system.

To start with, let’s look at the following four properties and the default values they are initialized to when a virtual machine is created:

Property Default value
BIOSSerialNumber    Randomly generated
BaseBoardSerialNumber Same value as BIOSSerialNumber
ChassisSerialNumber Same value as BIOSSerialNumber
ChassisAssetTag Randomly generated (but different to BIOSSerialNumber

All these properties are numeric and in the format "XXXX-XXXX-XXXX-XXXX-XXXX-XXXX-XX".

Windows provides WMI classes that expose these settings inside a guest operating system. The table below shows the relationship between the WMI properties of the virtual machine and WMI properties as seen by a guest operating system.

Property of Msvm_VirtualSystemSettingData WMI class & property in guest operating system
BIOSSerialNumber Win32_BIOS.SerialNumber
BaseBoardSerialNumber Win32_BaseBoard.SerialNumber
ChassisSerialNumber Win32_SystemEnclosure.SerialNumber
ChassisAssetTag Win32_SystemEnclosure.SMBIOSAssetTag

To illustrate how these values can be queried, I set the values to something less random and more easily identifiable. Here’s a partial output of a query against Msvm_VirtualSystemSettingData obtained using the wbemtest application on the parent partition. (Ignore the BIOSGUID property for a few moments).

instance of Msvm_VirtualSystemSettingData
{
BaseBoardSerialNumber = "2222-2222-2222-2222-2222-2222-22";
BIOSGUID = "{AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE}";
BIOSSerialNumber = "1111-1111-1111-1111-1111-1111-11";
ChassisAssetTag = "4444-4444-4444-4444-4444-4444-44";
ChassisSerialNumber = "3333-3333-3333-3333-3333-3333-33";
};

The next step was to generate something to query the WMI properties inside the guest operating system. I used a bit of scriptomatic assistance to come up with the following bit of VBScript – there’s plenty of other alternatives around of course including wbemtest again, a bit of PowerShell, ...

 Const wbemFlagReturnImmediately = &h10
 Const wbemFlagForwardOnly = &h20
  
 Set objWMIService = GetObject("winmgmts:\\.\root\CIMV2") 
  
 set colBIOS = objWMIService.ExecQuery( _
  "SELECT SerialNumber FROM Win32_BIOS", _
  "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly) 
  
 set colBB = objWMIService.ExecQuery( _
  "SELECT SerialNumber FROM " & _
  "Win32_BaseBoard", _
  "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly) 
  
 Set colSE = objWMIService.ExecQuery( _
  "SELECT SerialNumber,SMBIOSAssetTag " & _
  "FROM Win32_SystemEnclosure", _
  "WQL", wbemFlagReturnImmediately + wbemFlagForwardOnly) 
  
 For Each objItem in colBIOS
    WScript.Echo _
      "BIOS:            SerialNumber:   " & _
      objItem.SerialNumber
 Next 
  
 For Each objItem in colBB
    WScript.Echo _
      "Baseboard:       SerialNumber:   " & _
      objItem.SerialNumber
 Next 
  
 For Each objItem In colSE
    WScript.Echo _
      "SystemEnclosure: SerialNumber:   " & _
      objItem.SerialNumber
    WScript.Echo _
      "SystemEnclosure: SMBIOSAssetTag: " & _
      objItem.SMBIOSAssetTag
 Next 

This yielded the following output:

tag1

So the last problem I had to solve was the BIOSGUID value which I’d set in the virtual machine configuration to AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE. I use the word “problem” because I couldn’t see where or if this was propagated to the guest operating system in the WMI namespace. Nothing like a good challenge… :)

As searching the WMI namespace drew blank (or to be more accurate I missed it), I turned to some other thoughts. First was a registry search, but that also drew a blank.

I did know that the BIOS GUID is used during PXE boot – here’s a screenshot of the same virtual machine configured with a legacy network adapter for PXE install – you can see the contrived GUID being displayed:

tag2

Next call was a utility I found from an Internet Search called ROM BIOS Explorer. Here’s a screenshot of it running inside the guest operating system. As you can see from the hex-dump on the left hand side, starting at the highlight at offset 0x49, you can see the contrived GUID clearly. The utility also indicates it’s in the “Type 1: System Information” structure in the BIOS.

tag3

So that means the information is there – it was just a question of how to access it from inside the guest operating system. Next stop was an Internet search for Type 1: System Information which yielded (among others), this document about SMBIOS on Microsoft.com.

This shows that the table contains a Serial Number and UUID (another term for a GUID). So back to the Internet to refine the search to include the term “UUID” which led me to a pretty old SMS document which had exactly what I was looking for: Type 1, System Information UUID is exposed in Win32_ComputerSystemProduct.

Back to scriptomatic to do a query, and it was there all along!

tag4

There's also one other useful link I found along the way. To see a sample script on how to modify Msvm_VirtualSystemSettingData please see here.

Cheers,

John.

PS Thanks to my colleague Frank Berreth for pulling much of the information for this post together.