#PSTip Pause after UEFI boot failure when using Hyper-V Generation 2 virtual machines
Hyper-V in Windows 8.1 and Windows Server 2012 R2 introduced Generation 2 virtual machines, which provides new feature and better performance. One of the new features is UEFI, a replacement of the traditional BIOS. When troubleshooting boot problems on Generation 2 virtual machines, for example as part of a new image build, one of the issues is that the boot process is so fast it is hard to follow what is happening.
For advanced users, there is a CIM property in the Msvm_VirtualSystemSettingData class called PauseAfterBootFailure:
Get-CimClass -Namespace 'Root\Virtualization\V2' -ClassName Msvm_VirtualSystemSettingData |
Select-Object -ExpandProperty CimClassProperties | where name -eq "PauseAfterBootFailure"
Name : PauseAfterBootFailure
Value :
CimType : Boolean
Flags : Property, NullValue
Qualifiers : {read, write}
ReferenceClassName :
This property is by default set to $false. During troubleshooting it might be useful to enable this setting. Normally we would expect to accomplish this is by leveraging the CIM cmdlets:
Get-CimInstance -Namespace Root\Virtualization\V2 -ClassName Msvm_VirtualSystemSettingData -Filter "ElementName = 'Demo-VM'" | Set-CimInstance -Property @{PauseAfterBootFailure=$true} –PassThru
Alternatively, by using Get-WmiObject:
$vm = Get-WmiObject -Class Msvm_VirtualSystemSettingData -Namespace Root\Virtualization\V2 -Filter "ElementName = 'Demo-VM'" $vm.PauseAfterBootFailure = $true $vm.Put()
Although these commands does not produce any error messages, the property remains unchanged.
The reason for this is that the original WMI APIs did not provide a way to pass a WMI instance as the argument to a method directly; to pass an object to a method, you would serialize it into an embedded instance, a string representation of the object in XML form (using the ManagementObject.GetText method).
The Hyper-V WMI provider continues to expect any input objects in embedded-instance format, but the CimInstance objects retrieved by the CIM cmdlets do not currently provide a convenience method for serializing an object into an embedded instance.
#Virtual System Management Service
$VSMS = Get-CimInstance -Namespace root/virtualization/v2 -Class Msvm_VirtualSystemManagementService
#Virtual Machine
$VM = Get-CimInstance -Namespace root/virtualization/v2 -Class Msvm_ComputerSystem -Filter "ElementName='Demo-VM'"
#Setting Data
$SD = $vm | Get-CimAssociatedInstance -ResultClassName Msvm_VirtualSystemSettingData -Association Msvm_SettingsDefineState
#Update boot option
$SD.PauseAfterBootFailure = $True
#Create embedded instance
$cimSerializer = [Microsoft.Management.Infrastructure.Serialization.CimSerializer]::Create()
$serializedInstance = $cimSerializer.Serialize($SD, [Microsoft.Management.Infrastructure.Serialization.InstanceSerializationOptions]::None)
$embeddedInstanceString = [System.Text.Encoding]::Unicode.GetString($serializedInstance)
#Modify the system settings
Invoke-CimMethod -CimInstance $VSMS -MethodName ModifySystemSettings @{SystemSettings = $embeddedInstanceString}
When the PauseAfterBootFailure property is set to $true, the specified virtual machine will ask the user to press a key when a boot attempt failed:
The same technique can be used to modify other writable properties in the Msvm_VirtualSystemSettingData class.
Thanks to Brian Young at Microsoft for his assistance explaining this behavior.
Share on: