How many virtual processors does a virtual machine have?

A recent forum poster asked:

How do I write a script that figures out how many virtual processors a virtual machine has, when it is offline (i.e. not running)?

His question showed that he had made a classic mistake when working with the Hyper-V WMI APIs.  You see Hyper-V usually has two WMI objects for many parts of the virtual machine – one of them representing the settings and one of them representing the live object itself.

Case in hand: for a virtual processor you have “MSVM_Processor” which represents the live object, and you have “MSVM_ProcessorSettingData” which represents its settings.

Looking at the wrong object at the wrong time can cause problems.  Live objects should be used for gathering usage information about running virtual machines – settings object should be used for getting and setting configuration details.  90% of the time – the settings object is what you want (and 90% of the time it is the object that ends with the string “SettingData”).

Here is a simple script that gets a virtual machines processor count using both objects:

# Prompt for the Hyper-V Server to use
$HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
# Prompt for the virtual machine to use
$VMName = Read-Host "Specify the name of the virtual machine"
# Get the management service
$VMMS = gwmi -namespace root\virtualization Msvm_VirtualSystemManagementService -computername $HyperVServer
# Get the virtual machine object
$VM = gwmi MSVM_ComputerSystem -filter "ElementName='$VMName'" -namespace "root\virtualization" -computername $HyperVServer
# Set the stage
Write-host "There are two ways to get a virtual machines processor count, the wrong way and the right way..."
# Let's do the wrong way first
# Get the virtual processor objects
$vProcs = $vm.GetRelated("MSVM_Processor")
Write-host "Doing it the wrong way (using Msvm_Processor):"
write-host "The" $VMName "virtual machine is configured with" $vProcs.count "virtual processors."
# Now let's do it the right way
# SettingType = 3 ensures that we do not get snapshots
$SystemSettingData = $VM.getRelated("Msvm_VirtualSystemSettingData") | where {$_.SettingType -eq 3}
# Get the processor setting data
$ProcSetting = $SystemSettingData.getRelated("Msvm_ProcessorSettingData") | select -first 1
Write-host "Doing it the right way (using Msvm_ProcessorSettingData):"
write-host "The" $VMName "virtual machine is configured with" $ProcSetting.VirtualQuantity "virtual processors."

If I run this on a running virtual machine – both methods return the same thing:


But if the virtual machine is not running – only the MVSM_ProcessorSettingData actually tells me what I want to know: