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: