Permalink
332 lines (263 sloc) 11.6 KB
#
# Get-NestedVirtStatus
#
# Checks a virtualization host and VM for compatibility with Nested Virtualization
#
# Author: Allen Marshall, Theo Thompson
#
# Need to run elevated. Do that here.
#
# Get the ID and security principal of the current user account
$myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent();
$myWindowsPrincipal = New-Object System.Security.Principal.WindowsPrincipal($myWindowsID);
# Get the security principal for the administrator role
$adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator;
# Check to see if we are currently running as an administrator
if ($myWindowsPrincipal.IsInRole($adminRole)) {
# We are running as an administrator, so change the title and background colour to indicate this
$Host.UI.RawUI.WindowTitle = $myInvocation.MyCommand.Definition + "(Elevated)";
#$Host.UI.RawUI.BackgroundColor = "DarkBlue";
} else {
# We are not running as an administrator, so relaunch as administrator
# Create a new process object that starts PowerShell
$newProcess = New-Object System.Diagnostics.ProcessStartInfo "PowerShell";
# Specify the current script path and name as a parameter with added scope and support for scripts with spaces in it's path
$newProcess.Arguments = "& '" + $script:MyInvocation.MyCommand.Path + "'"
# Indicate that the process should be elevated
$newProcess.Verb = "runas";
# Start the new process
[System.Diagnostics.Process]::Start($newProcess) | Out-Null;
# Exit from the current, unelevated, process
Exit;
}
# Run code that needs to be elevated here...
#
# Host error strings
#
$HostCfgErrorMsgs = $null # for debug purposes
$HostCfgErrorMsgs = @{
"noHypervisor" = "Hypervisor is not running on this host";
"noFullHyp" = "Full Hyper-V role is not enabled on this host";
"BcdDisabled" = "Nested virtualization is disabled via BCD HYPERVISORLOADOPTIONS";
"VbsRunning" = "Virtualization Based Security is running";
"VbsRegKey" = "The VBS enable reg key is set";
"UnsupportedBuild" = "Nested virtualization requires a build later than 10565";
"UnsupportedProcessor" = "Running on an unsupported (AMD) processor";
"VbsPresent" = 'Virtualization Based Security is partly installed on you system. To completely remove Virtualizaiton Based Security, please follow instructions under "Remove Credential Guard" found here: https://technet.microsoft.com/en-us/library/mt483740%28v=vs.85%29.aspx';
}
$HostCfgErrors = $null
$HostCfgErrors = @()
#
# Grab some info about the machine and build
#
# get computer details
Write-Host "Getting system information..." -NoNewline
if($PSVersionTable.PSVersion.Major -ge 3){
$comp = Get-CimInstance -ClassName Win32_ComputerSystem
$proc = Get-CimInstance -ClassName Win32_Processor
}
else{
$comp = Get-WmiObject Win32_ComputerSystem
$proc = Get-WmiObject Win32_Processor
}
Write-Host "done."
# grab build info out of registry
Write-Host "Getting build information..." -NoNewline
$a = Get-ItemProperty -Path 'hklm:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'
Write-Host "done."
#
# setup an object to return
#
$HostNested = New-Object PSObject
# computer info
Add-Member -InputObject $HostNested NoteProperty -Name "Computer" -Value $comp.Name
Add-Member -InputObject $HostNested NoteProperty -Name "Manufacturer" -Value $comp.Manufacturer
Add-Member -InputObject $HostNested NoteProperty -Name "Model" -Value $comp.Model
# processor info
Add-Member -InputObject $HostNested NoteProperty -Name "ProccessorManufacturer" -Value $proc.Manufacturer
# build info
Add-Member -InputObject $HostNested NoteProperty -Name "Product Name" -Value $a.ProductName
Add-Member -InputObject $HostNested NoteProperty -Name "Installation Type" -Value $a.InstallationType
Add-Member -InputObject $HostNested NoteProperty -Name "Edition ID" -Value $a.EditionID
Add-Member -InputObject $HostNested NoteProperty -Name "Build Lab" -Value $a.BuildLabEx
# Hyper-V info
Add-Member -InputObject $HostNested NoteProperty -Name "HypervisorRunning" -Value $false
Add-Member -InputObject $HostNested NoteProperty -Name "FullHyperVRole" -Value $false
# Nested info
Add-Member -InputObject $HostNested NoteProperty -Name "HostNestedSupport" -Value $true
Add-Member -InputObject $HostNested NoteProperty -Name "HypervisorLoadOptionsPresent" -Value $false
Add-Member -InputObject $HostNested NoteProperty -Name "HypervisorLoadOptionsValue" -Value ""
Add-Member -InputObject $HostNested NoteProperty -Name "IumInstalled" -Value $false
Add-Member -InputObject $HostNested NoteProperty -Name "VbsRunning" -Value $false
Add-Member -InputObject $HostNested NoteProperty -Name "VbsRegEnabled" -Value $false
Add-Member -InputObject $HostNested NoteProperty -Name "BuildSupported" -Value $true
Add-Member -InputObject $HostNested NoteProperty -Name "VbsPresent" -Value $false
Write-Host "Validating host information..." -NoNewline
if ($a.BuildLabEx.split('.')[0] -lt 10565) {
$HostNested.HostNestedSupport = $false
$HostNested.BuildSupported = $false
$HostCfgErrors += ($HostCfgErrorMsgs["UnsupportedBuild"])
}
#
# Is this an intel processor
#
if($HostNested.ProccessorManufacturer -ne "GenuineIntel")
{
$HostCfgErrors += ($HostCfgErrorMsgs["UnsupportedProcessor"])
$HostNested.HostNestedSupport = $false
}
#
# Is this even a Hyper-V host?
#
# Is the hypervisor running?
$HostNested.HypervisorRunning = $comp.HypervisorPresent
if ($comp.HypervisorPresent -eq $false) {
$HostNested.HostNestedSupport = $false
$HostCfgErrors += ($HostCfgErrorMsgs["NoHypervisor"])
}
# get info about installed packages
$pkg = Get-WindowsOptionalFeature -FeatureName "Microsoft-Hyper-V" -Online
if ($pkg.State -eq "Enabled") {$HostNested.FullHyperVRole = $true}
# See if HYPERVISORLOADOPTIONS is present
# Make sure nested virtualization isn't explicitly disabled via BCD
$hvloadoptions = bcdedit /enum | Select-String "hypervisorloadoptions"
if ($hvloadoptions) {
$HostNested.HypervisorLoadOptionsPresent = $true
$setting = $hvloadoptions.line.split(' ')
if($hvloadoptions.line -match "OFFERNESTEDVIRT=FALSE") {
$HostNested.HostNestedSupport = $false
$HostCfgErrors += ($HostCfgErrorMsgs["BcdDisabled"])
}
for ($i = 1; $i -le $setting.Count)
{
$HostNested.HypervisorLoadOptionsValue += $setting[$i]
$i++
}
}
#
# Check for VSM
#
# Is IUM installed?
# N.B. The presence of the IUM feature doesn't mean it's actually running,
# so IUM being installed doesn't by itself preclude Nested
if(Get-WindowsOptionalFeature -Online | where FeatureName -eq IsolatedUserMode | where State -eq Enabled) {
$HostNested.IumInstalled = $true
}
# is VBS running?
$dg = Get-CimInstance -classname Win32_DeviceGuard -namespace root\Microsoft\Windows\DeviceGuard -ea SilentlyContinue
if ($dg.VirtualizationBasedSecurityStatus) {
$HostNested.VbsRunning = $true
$HostNested.HostNestedSupport = $false
$HostCfgErrors += ($HostCfgErrorMsgs["VbsRunning"])
}
# Is EnableVirtualizationBasedSecurity set in the registry?
$key = (Get-ItemProperty -Path 'HKLM:\System\CurrentControlSet\Control\DeviceGuard' -ErrorAction SilentlyContinue).EnableVirtualizationBasedSecurity
if ($key -eq 1) {
$HostNested.VbsRegEnabled = $true
$HostNested.HostNestedSupport = $false
$HostCfgErrors += ($HostCfgErrorMsgs["VbsRegKey"])
}
# Check for residual Device Guard EFI variables
if((Get-Command Confirm-SecureBootUEFI -ea SilentlyContinue) -and (Confirm-SecureBootUEFI -ea SilentlyContinue)){
$VbsEventErrors = Get-WinEvent -LogName System -FilterXPath "*[System[EventID=124]]" -ea SilentlyContinue
if(($VbsEventErrors.Count -gt 0)) {
# Check if event was generated from latest boot
$BootEvents = get-winevent -LogName System -FilterXPath "*[System/Provider[@Name='Microsoft-Windows-Kernel-General'] and System/EventID=12] "
$LastBoot = $BootEvents[0].TimeCreated # returns newest by default
$EfiBoot = $VbsEventErrors[0].TimeCreated
if($LastBoot -lt $EfiBoot){
$HostNested.VbsPresent = $true
$HostNested.HostNestedSupport = $false
$HostCfgErrors += ($HostCfgErrorMsgs["VbsPresent"])
}
}
}
#
# show results
#
Write-Host "done."
Write-Host
Write-Host ("The virtualization host " + $HostNested.Computer + " supports nested virtualization: ") -NoNewline
if ($HostNested.HostNestedSupport) {
Write-Host "YES" -ForegroundColor White -BackgroundColor Green
} else {
Write-Host "NO" -ForegroundColor White -BackgroundColor RED
Write-Host "The following host configuration errors have been detected:"
$HostCfgErrors
}
# dump the details
$HostNested
#
# Now get all VM info ======================================================================================================
#
Write-Host "Looking for VMs..." -NoNewline
$VmCfgErrorMsgs = $null # for debug purposes
$VmCfgErrorMsgs = @{
"DynMem" = "The VM has Dynamic Memory enabled.";
"ExposeVirtualizationExtensions" = "This VM is not configured to expose virtualization extensions.";
"Checkpoint" = "This VM has one or more production checkpoints.";
"Saved" = "This VM has been saved."
}
$VmCfgErrors = $null
$VmCfgErrors = @()
# Array to hold list of pertinent VM info
$vmInfoList = @()
# Array of all VMs on this host
$vms = [object[]] (Get-VM)
Write-Host ("found " + $vms.Count + " VMs.");
Write-Host "Validating virtual machines..." -NoNewline
# Walk the list of VMs and populate the relevant data
foreach ($vm in $vms) {
$vmInfo = New-Object PSObject
# VM info
Add-Member -InputObject $vmInfo NoteProperty -Name "Name" -Value $vm.VMName
Add-Member -InputObject $vmInfo NoteProperty -Name "SupportsNesting" -Value $true
Add-Member -InputObject $vmInfo NoteProperty -Name "ExposeVirtualizationExtensions" -Value $false
Add-Member -InputObject $vmInfo NoteProperty -Name "DynamicMemoryEnabled" -Value $vm.DynamicMemoryEnabled
Add-Member -InputObject $vmInfo NoteProperty -Name "SnapshotEnabled" -Value $false
Add-Member -InputObject $vmInfo NoteProperty -Name "State" -Value $vm.State
#
# VM eligibility validation
#
# is nested enabled on this VM?
$vmInfo.ExposeVirtualizationExtensions = (Get-VMProcessor -VM $vm).ExposeVirtualizationExtensions
if ($vmInfo.ExposeVirtualizationExtensions -eq $false) {
$vmInfo.SupportsNesting = $false
$VmCfgErrors += ($VmCfgErrorMsgs["ExposeVirtualizationExtensions"])
}
if ($vmInfo.DynamicMemoryEnabled -eq $true) {
$vmInfo.SupportsNesting = $false
$VmCfgErrors += ($VmCfgErrorMsgs["DynMem"])
}
if ($vm.ParentCheckpointId -ne $null) {
$vmInfo.SupportsNesting = $false
$VmCfgErrors += ($VmCfgErrorMsgs["Checkpoint"])
}
if ($vmInfo.State -eq 'Saved') {
$vmInfo.SupportsNesting = $false
$VmCfgErrors += ($VmCfgErrorMsgs["Saved"])
}
$vmInfoList += $vmInfo
}
Write-Host "done."
#
# display VM results
#
foreach ($vmInfo in $vmInfoList) {
Write-Host
Write-Host ("The virtual machine " + $vmInfo.Name + " supports nested virtualization: ") -NoNewline
if ($vmInfo.SupportsNesting) {
Write-Host "YES" -ForegroundColor White -BackgroundColor Green
} else {
Write-Host "NO" -ForegroundColor White -BackgroundColor RED
Write-Host "The following VM configuration errors have been detected:"
$VmCfgErrors
Write-Host
}
Write-Host
$vmInfo
Write-Host
}
# exit elevated process
Write-Host -NoNewLine "Press any key to continue...";
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown");