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:
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:
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.
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!
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.
Comments
Anonymous
January 01, 2003
PingBack from http://www.keyongtech.com/2376720-determine-host-pc-name-fromAnonymous
January 01, 2003
If you are scripting virtual machine management activities, you will need to uniquely identify and sortAnonymous
September 14, 2011
How do you deal with cases were more then one of the virtual machines has been imported from a single exported virtual machine? Even when Copy is used the BIOS GUID are not altered, invalidating the uniqueness of this field.