/
Get-NestedVirtStatus.ps1
327 lines (262 loc) · 11.6 KB
/
Get-NestedVirtStatus.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
#
# 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."
}
# 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
Add-Member -InputObject $vmInfo NoteProperty -Name "VmCfgErrors" -Value @()
#
# VM eligibility validation
#
# is nested enabled on this VM?
$vmInfo.ExposeVirtualizationExtensions = (Get-VMProcessor -VM $vm).ExposeVirtualizationExtensions
if ($vmInfo.ExposeVirtualizationExtensions -eq $false) {
$vmInfo.SupportsNesting = $false
$vmInfo.VmCfgErrors += ($VmCfgErrorMsgs["ExposeVirtualizationExtensions"])
}
if ($vmInfo.DynamicMemoryEnabled -eq $true) {
$vmInfo.SupportsNesting = $false
$vmInfo.VmCfgErrors += ($VmCfgErrorMsgs["DynMem"])
}
if ($vm.ParentCheckpointId -ne $null) {
$vmInfo.SupportsNesting = $false
$vmInfo.VmCfgErrors += ($VmCfgErrorMsgs["Checkpoint"])
}
if ($vmInfo.State -eq 'Saved') {
$vmInfo.SupportsNesting = $false
$vmInfo.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:"
$vmInfo.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");