Private/TestHyperVExternalvSwitch.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
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
function TestHyperVExternalvSwitch {
    [CmdletBinding(DefaultParameterSetName='ExternalNetworkVM')]
    Param(
        [Parameter(Mandatory=$False)]
        [string]$DownloadDirectory = "$HOME\Downloads",

        [Parameter(Mandatory=$False)]
        [switch]$AllowRestarts,

        [Parameter(Mandatory=$False)]
        [switch]$SkipHyperVInstallCheck,

        [Parameter(Mandatory=$False)]
        [switch]$SkipPreDownloadCheck
    )

    #region >> Variable/Parameter Transforms and PreRun Prep

    Push-Location

    if (!$SkipHyperVInstallCheck) {
        try {
            $HyperVFeaturesInstallResults = InstallHyperVFeatures -ParentFunction $MyInvocation.MyCommand.Name
        }
        catch {
            Write-Error $_
            Write-Error "The InstallHyperVFeatures function (as executed by the $($MyInvocation.MyCommand.Name) function) failed! Halting!"
            $global:FunctionResult = "1"
            Pop-Location
            return
        }
        try {
            $InstallContainersFeatureDismResult = InstallFeatureDism -Feature Containers -ParentFunction $MyInvocation.MyCommand.Name
        }
        catch {
            Write-Error $_
            Write-Error "The InstallFeatureDism function (as executed by the $($MyInvocation.MyCommand.Name) function) failed! Halting!"
            $global:FunctionResult = "1"
            Pop-Location
            return
        }

        if ($HyperVFeaturesInstallResults.InstallResults.Count -gt 0) {
            if (!$AllowRestarts) {
                Write-Warning "You must restart $env:ComputerName before the TestHyperVExternalvSwitch function can proceed! Halting!"
                # IMPORTANT NOTE: The below Write-Output "RestartNeeded" is necessary
                Write-Output "RestartNeeded"
                $global:FunctionResult = "1"
                Pop-Location
                return
            }
            else {
                Restart-Computer -Confirm:$False -Force
            }
        }
    }
    else {
        if (![bool]$(Get-Module -ListAvailable -Name Hyper-V) -and ![bool]$(Get-Module -Name Hyper-V)) {
            Write-Error "Hyper-V does not appear to be installed on $env:ComputerName! Try the function again without the -SkipHyperVInstallCheck switch. Halting!"
            $global:FunctionResult = "1"
            Pop-Location
            return
        }
    }

    # Set some other variables that we will need
    <#
    $NextHop = $(Get-NetRoute -AddressFamily IPv4 | Where-Object {$_.NextHop -ne "0.0.0.0"} | Sort-Object RouteMetric)[0].NextHop
    $PrimaryIP = $(Find-NetRoute -RemoteIPAddress $NextHop | Where-Object {$($_ | Get-Member).Name -contains "IPAddress"}).IPAddress
    $NicInfo = Get-NetIPAddress -IPAddress $PrimaryIP
    $NicAdapter = Get-NetAdapter -InterfaceAlias $NicInfo.InterfaceAlias
    #>

    $PrimaryIfIndex = $(Get-CimInstance Win32_IP4RouteTable | Where-Object {
        $_.Destination -eq '0.0.0.0' -and $_.Mask -eq '0.0.0.0'
    } | Sort-Object Metric1)[0].InterfaceIndex
    $NicInfo = Get-CimInstance Win32_NetworkAdapterConfiguration | Where-Object {$_.InterfaceIndex -eq $PrimaryIfIndex}
    $PrimaryIP = $NicInfo.IPAddress | Where-Object {TestIsValidIPAddress -IPAddress $_}
    $NextHop = $NicInfo.DefaultIPGateway[0]

    $HostNameBIOSInfo = Get-CimInstance Win32_BIOS
    $IntegrationServicesRegistryPath = "HKLM:\SOFTWARE\Microsoft\Virtual Machine\Guest\Parameters"
    $HostNameIntegrationServicesPresent = Test-Path $IntegrationServicesRegistryPath

    if ($HostNameBIOSInfo.SMBIOSBIOSVersion -match "Hyper-V|VirtualBox|VMWare|Xen" -or
    $HostNameBIOSInfo.Manufacturer -match "Hyper-V|VirtualBox|VMWare|Xen" -or
    $HostNameBIOSInfo.Name -match "Hyper-V|VirtualBox|VMWare|Xen" -or
    $HostNameBIOSInfo.SerialNumber -match "Hyper-V|VirtualBox|VMWare|Xen" -or
    $HostNameBIOSInfo.Version -match "Hyper-V|VirtualBox|VMWare|Xen|VRTUAL" -or
    $HostNameIntegrationServicesPresent) {
        $IsVirtual = $True
    }
    else {
        $IsVirtual = $False
    }

    # If there are any pre-existing running VMs using an External vSwitch, assume that External vSwitch works
    [System.Collections.ArrayList][Array]$ExternalvSwitches = Get-VMSwitch -SwitchType External
    if ($ExternalvSwitches.Count -gt 0) {
        $RunningVMs = Get-VM | Where-Object {$_.State -eq "Running"}

        if ($RunningVMs.Count -gt 0) {
            [System.Collections.ArrayList]$FoundRunningVMUsingExternalvSwitch = @()
            foreach ($VMObject in $RunningVMs) {
                if ($ExternalvSwitches.Name -contains $VMObject.NetworkAdapters.SwitchName) {
                    $null = $FoundRunningVMUsingExternalvSwitch.Add($VMObject)
                }
            }
        }
    }

    # If we're on BareMetal or if there are already Hyper-V VMs that are 'Running' that use an External vSwitch,
    # then we can assume External vSwitch works, and we're done here...
    if ($IsVirtual -eq $False -or $FoundRunningVMUsingExternalvSwitch.Count -gt 0) {
        [pscustomobject]@{
            ExternalvSwitchWorks                = $True
            CanReachInternet                    = $True
            CanReachRouter                      = $True
            VirtualizationExtensionsExposed     = $True
            MacAddressSpoofingEnabled           = $True
        }
        return
    }

    # If we reached this point in the function, we have established that the machine that the function is being run on
    # is Virtual

    if (!$NicInfo.DHCPEnabled) {
        Write-Error "The Test-HyperVExternalvSwitch function failed because the External Network (i.e. the Host network) does not appear to have DHCP already available! Try the New-DHCPServer function! Halting!"
        $global:FunctionResult = "1"
        return
    }

    if (!$DownloadDirectory) {
        $DownloadDirectory = "$HOME\Downloads"
    }

    # Write the Universal Unsecure Vagrant Private Key to filesystem
    # From: https://github.com/hashicorp/vagrant/blob/master/keys
    $VagrantPrivKey = @"
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEA6NF8iallvQVp22WDkTkyrtvp9eWW6A8YVr+kz4TjGYe7gHzI
w+niNltGEFHzD8+v1I2YJ6oXevct1YeS0o9HZyN1Q9qgCgzUFtdOKLv6IedplqoP
kcmF0aYet2PkEDo3MlTBckFXPITAMzF8dJSIFo9D8HfdOV0IAdx4O7PtixWKn5y2
hMNG0zQPyUecp4pzC6kivAIhyfHilFR61RGL+GPXQ2MWZWFYbAGjyiYJnAmCP3NO
Td0jMZEnDkbUvxhMmBYSdETk1rRgm+R4LOzFUGaHqHDLKLX+FIPKcF96hrucXzcW
yLbIbEgE98OHlnVYCzRdK8jlqm8tehUc9c9WhQIBIwKCAQEA4iqWPJXtzZA68mKd
ELs4jJsdyky+ewdZeNds5tjcnHU5zUYE25K+ffJED9qUWICcLZDc81TGWjHyAqD1
Bw7XpgUwFgeUJwUlzQurAv+/ySnxiwuaGJfhFM1CaQHzfXphgVml+fZUvnJUTvzf
TK2Lg6EdbUE9TarUlBf/xPfuEhMSlIE5keb/Zz3/LUlRg8yDqz5w+QWVJ4utnKnK
iqwZN0mwpwU7YSyJhlT4YV1F3n4YjLswM5wJs2oqm0jssQu/BT0tyEXNDYBLEF4A
sClaWuSJ2kjq7KhrrYXzagqhnSei9ODYFShJu8UWVec3Ihb5ZXlzO6vdNQ1J9Xsf
4m+2ywKBgQD6qFxx/Rv9CNN96l/4rb14HKirC2o/orApiHmHDsURs5rUKDx0f9iP
cXN7S1uePXuJRK/5hsubaOCx3Owd2u9gD6Oq0CsMkE4CUSiJcYrMANtx54cGH7Rk
EjFZxK8xAv1ldELEyxrFqkbE4BKd8QOt414qjvTGyAK+OLD3M2QdCQKBgQDtx8pN
CAxR7yhHbIWT1AH66+XWN8bXq7l3RO/ukeaci98JfkbkxURZhtxV/HHuvUhnPLdX
3TwygPBYZFNo4pzVEhzWoTtnEtrFueKxyc3+LjZpuo+mBlQ6ORtfgkr9gBVphXZG
YEzkCD3lVdl8L4cw9BVpKrJCs1c5taGjDgdInQKBgHm/fVvv96bJxc9x1tffXAcj
3OVdUN0UgXNCSaf/3A/phbeBQe9xS+3mpc4r6qvx+iy69mNBeNZ0xOitIjpjBo2+
dBEjSBwLk5q5tJqHmy/jKMJL4n9ROlx93XS+njxgibTvU6Fp9w+NOFD/HvxB3Tcz
6+jJF85D5BNAG3DBMKBjAoGBAOAxZvgsKN+JuENXsST7F89Tck2iTcQIT8g5rwWC
P9Vt74yboe2kDT531w8+egz7nAmRBKNM751U/95P9t88EDacDI/Z2OwnuFQHCPDF
llYOUI+SpLJ6/vURRbHSnnn8a/XG+nzedGH5JGqEJNQsz+xT2axM0/W/CRknmGaJ
kda/AoGANWrLCz708y7VYgAtW2Uf1DPOIYMdvo6fxIB5i9ZfISgcJ/bbCUkFrhoH
+vq/5CIWxCPp0f85R4qxxQ5ihxJ0YDQT9Jpx4TMss4PSavPaBH3RXow5Ohe+bYoQ
NE5OgEXk2wVfZczCZpigBKbKZHNYcelXtTt/nP3rsCuGcM4h53s=
-----END RSA PRIVATE KEY-----
"@


    if (!$(Test-Path "$HOME\.ssh")) {
        $null = New-Item -ItemType Directory -Path "$HOME\.ssh"
    }
    $VagrantInsecurePrivKeyPath = "$HOME\.ssh\insecure_vagrant_private_key.pem"
    if (!$(Test-Path $VagrantInsecurePrivKeyPath)) {
        $VagrantPrivKey | Out-File $VagrantInsecurePrivKeyPath -Encoding ASCII

        if ($PSVersionTable.PSEdition -eq "Core") {
            $FixVPermsAsString = ${Function:FixVagrantPrivateKeyPerms}.Ast.Extent.Text
            Invoke-WinCommand -ComputerName localhost -ScriptBlock {
                Invoke-Expression $args[0]
                FixVagrantPrivateKeyPerms -PathToPrivateKey $args[1]
            } -ArgumentList $FixVPermsAsString,$VagrantInsecurePrivKeyPath
        }
        else {
            FixVagrantPrivateKeyPerms -PathToPrivateKey $VagrantInsecurePrivKeyPath
        }
    }

    <#
    if ([Environment]::OSVersion.Version -lt [version]"10.0.17063") {
        if (![bool]$(Get-Command curl -ErrorAction SilentlyContinue) -or
        $(Get-Command curl -ErrorAction SilentlyContinue).CommandType -eq "Alias"
        ) {
            $InstallCurlResults = Install-Program -ProgramName curl -CommandName curl -UseChocolateyCmdLine
        }
    }
    $CurlCmd = $(Get-Command curl -CommandType Application -All).Source
    if ($CurlCmd.Count -gt 1) {
        $CurlCmd = $(Get-Command curl -CommandType Application -All | Where-Object {$_.Source -match "x64"}).Source
        if (!$CurlCmd) {
            $CurlCmd = $(Get-Command curl -CommandType Application -All).Source[-1]
        }
    }
    #>


    if (![bool]$(Get-Command ssh -ErrorAction SilentlyContinue)) {
        if (![bool]$(Get-Module -ListAvailable ProgramManagement)) {Install-Module ProgramManagement}
        if (![bool]$(Get-Module ProgramManagement)) {Import-Module ProgramManagement}
        $InstallOpenSSHResult = Install-Program -ProgramName openssh -CommandName ssh.exe -ExpectedInstallLocation "C:\Program Files\OpenSSH-Win64"

        if (![bool]$(Get-Service ssh-agent -ErrorAction SilentlyContinue)) {
            if (Test-Path "C:\Program Files\OpenSSH-Win64\install-sshd.ps1") {
                & "C:\Program Files\OpenSSH-Win64\install-sshd.ps1"
            }
            else {
                Write-Warning "Unable to find 'C:\Program Files\OpenSSH-Win64\install-sshd.ps1'! The services 'ssh-agent' and 'sshd' will NOT be installed."
            }
        }
    }

    #endregion >> Variable/Parameter Transforms and PreRun Prep


    #region >> Main Body

    $DeployVMSplatParams = @{
        VagrantBox              = "centos/7"
        VagrantProvider         = "hyperv"
        VMName                  = "CentOS7vSwitchTest"
        VMDestinationDirectory  = $DownloadDirectory
        Memory                  = 1024
        CPUs                    = 1
        ErrorAction             = "SilentlyContinue"
        ErrorVariable           = "DVMErr"
        SkipHyperVInstallCheck  = $True
    }

    try {
        $DeployVMResult = Deploy-HyperVVagrantBoxManually @DeployVMSplatParams
        if (!$DeployVMResult -or
        [bool]$($($DVMErr | Out-String) -match "one of the Hyper-V components is not running") -or
        [bool]$($($DVMErr | Out-String) -match "The operation has timed out")
        ) {
            throw "The Deploy-HyperVVagrantBoxManually function failed! Halting!"
        }
        $VMDeployed = $True
    }
    catch {
        if ([bool]$($($DVMErr | Out-String) -match "one of the Hyper-V components is not running")) {
            if ($IsVirtual) {
                $VirtualizationExtensionsExposed = $False
            }
            else {
                Write-Error "One or more Hyper-V components is not installed! Please check the Hyper-V features that are currenly enabled! Halting!"
                $global:FunctionResult = "1"
                Pop-Location
                return
            }
        }
        elseif ([bool]$($($DVMErr | Out-String) -match "The operation has timed out")) {
            Write-Warning "https://vagrantcloud.com appears to be throttling traffic. Sleeping for 5 minutes before trying again..."
            Start-Sleep -Seconds 300

            try {
                $DeployVMResult = Deploy-HyperVVagrantBoxManually @DeployVMSplatParams
                if (!$DeployVMResult -or
                [bool]$($($DVMErr | Out-String) -match "one of the Hyper-V components is not running") -or
                [bool]$($($DVMErr | Out-String) -match "The operation has timed out")
                ) {
                    throw "The Deploy-HyperVVagrantBoxManually function failed! Halting!"
                }
                $VMDeployed = $True
            }
            catch {
                if ([bool]$($($DVMErr | Out-String) -match "one of the Hyper-V components is not running")) {
                    if ($IsVirtual) {
                        $VirtualizationExtensionsExposed = $False
                    }
                    else {
                        Write-Error "One or more Hyper-V components is not installed! Please check the Hyper-V features that are currenly enabled! Halting!"
                        $global:FunctionResult = "1"
                        Pop-Location
                        return
                    }
                }
                else {
                    Write-Error $_
                    Write-Host "Errors for the Deploy-HyperVVagrantBoxManually function are as follows:"
                    Write-Error $($DVMErr | Out-String)

                    if ($DeployVMResult.VMName -ne $null) {
                        $DestroyVMOutput = Manage-HyperVVM -VmName $DeployVMResult.VMName -Destroy -ErrorAction SilentlyContinue
                    }
                    if ($DeployVMResult.ExternalSwitchCreated -eq $True) {
                        Remove-VMSwitch "ToExternal" -Force -ErrorAction SilentlyContinue
                    }
                    if ($DeployVMResult.TempHyperVVMLocation -ne $null) {
                        if (Test-Path $DeployVMResult.TempHyperVVMLocation) {
                            Remove-Item $DeployVMResult.TempHyperVVMLocation -Recurse -Force
                        }
                    }
                    if ($DeployVMResult.BoxFileLocation -ne $null) {
                        if (Test-Path $DeployVMResult.BoxFileLocation) {
                            Remove-Item $DeployVMResult.BoxFileLocation -Force
                        }
                    }
                    
                    $global:FunctionResult = "1"
                    Pop-Location
                    return
                }
            }
        }
        else {
            Write-Error $_
            Write-Host "Errors for the Deploy-HyperVVagrantBoxManually function are as follows:"
            Write-Error $($DVMErr | Out-String)

            if ($DeployVMResult.VMName -ne $null) {
                $DestroyVMOutput = Manage-HyperVVM -VmName $DeployVMResult.VMName -Destroy -ErrorAction SilentlyContinue
            }
            if ($DeployVMResult.ExternalSwitchCreated -eq $True) {
                Remove-VMSwitch "ToExternal" -Force -ErrorAction SilentlyContinue
            }
            if ($DeployVMResult.TempHyperVVMLocation -ne $null) {
                if (Test-Path $DeployVMResult.TempHyperVVMLocation) {
                    Remove-Item $DeployVMResult.TempHyperVVMLocation -Recurse -Force
                }
            }
            if ($DeployVMResult.BoxFileLocation -ne $null) {
                if (Test-Path $DeployVMResult.BoxFileLocation) {
                    Remove-Item $DeployVMResult.BoxFileLocation -Force
                }
            }
            
            $global:FunctionResult = "1"
            Pop-Location
            return
        }
    }

    if (!$VMDeployed -and $DeployVMResult -eq "RestartNeeded") {
        if (!$AllowRestarts) {
            Write-Warning "You must restart $env:ComputerName before the TestHyperVExternalvSwitch can proceed! Halting!"
            # IMPORTANT NOTE: The below Write-Output "RestartNeeded" is necessary
            Write-Output "RestartNeeded"
            $global:FunctionResult = "1"
            Pop-Location
            return
        }
        else {
            Restart-Computer -Confirm:$False -Force
        }
    }

    if ($VMDeployed) {
        try {
            $CustomCentOSVM = Get-VM -Name $DeployVMResult.VMName

            if ($CustomCentOSVM.State -eq "Running") {
                # Give the CentOS7 VM 120 seconds to report its IP
                $counter = 0
                while (!$VMIPv4Address -and $counter -le 4) {
                    $counter++
                    Write-Host "Waiting for $($CustomCentOSVM.Name) to report its IP Address..."
                    Start-Sleep -Seconds 30
                    $VMIPv4Address = $(Get-VMNetworkAdapter -VMName $CustomCentOSVM.Name).IPAddresses | Where-Object {TestIsValidIPAddress -IPAddress $_}
                }

                if ($VMIPv4Address) {
                    # If $HOME\.ssh\known_hosts already exists, make sure there is NOT a line in there already regarding $VMIPv4Address
                    # If there is, remove it
                    if (Test-Path "$HOME\.ssh\known_hosts") {
                        $KnownHostsContent = Get-Content "$HOME\.ssh\known_hosts"
                        $PotentialLineToRemove = $KnownHostsContent -match $VMIPv4Address
                        if ($PotentialLineToRemove) {
                            $UpdatedKnownHostsContent = $KnownHostsContent | Where-Object {$_ -ne $PotentialLineToRemove}
                            Set-Content -Path "$HOME\.ssh\known_hosts" -Value $UpdatedKnownHostsContent
                        }
                    }

                    # Now we can start issuing ssh commands through our CentOS7 VM to see if the External vSwitch actually works
                    # If it does, we know that MacAddress spoofing is enabled on the hypervisor and that the hypervisor is
                    # most likely Hyper-V
                    $PingRouterResult = ssh -o "StrictHostKeyChecking=no" -o "IdentitiesOnly=yes" -i "$VagrantInsecurePrivKeyPath" -t vagrant@$VMIPv4Address "ping -c 1 '$NextHop' >/dev/null && echo True" 2>$null
                    if ($PingRouterResult -eq "True") {$CanReachRouter = $True}
                    $PingInternetResult = ssh -o "StrictHostKeyChecking=no" -o "IdentitiesOnly=yes" -i "$VagrantInsecurePrivKeyPath" -t vagrant@$VMIPv4Address "ping -c 1 '8.8.8.8' >/dev/null && echo True" 2>$null
                    if ($PingInternetResult -eq $True) {$CanReachInternet = $True}

                    if (!$CanReachInternet -and !$CanReachRouter) {
                        $ExternalvSwitchWorks = $False
                    }
                    else {
                        Write-Host "External vSwitch $($(Get-VMSwitch -SwitchType External).Name) can reach the internet!" -ForegroundColor Green
                        $ExternalvSwitchWorks = $True
                    }
                }
                else {
                    $MacAddressSpoofingEnabled = $False
                }
            }
        }
        catch {
            Write-Error $_

            if ($DeployVMResult.VMName -ne $null) {
                $DestroyVMOutput = Manage-HyperVVM -VmName $DeployVMResult.VMName -Destroy -ErrorAction SilentlyContinue
            }
            if ($DeployVMResult.ExternalSwitchCreated) {
                Remove-VMSwitch "ToExternal" -Force -ErrorAction SilentlyContinue
            }
            if ($DeployVMResult.TempHyperVVMLocation -ne $null) {
                if (Test-Path $DeployVMResult.TempHyperVVMLocation) {
                    Remove-Item $DeployVMResult.TempHyperVVMLocation -Recurse -Force
                }
            }
            if ($DeployVMResult.BoxFileLocation -ne $null) {
                if (Test-Path $DeployVMResult.BoxFileLocation) {
                    Remove-Item $DeployVMResult.BoxFileLocation -Force
                }
            }

            $global:FunctionResult = "1"
            Pop-Location
            return
        }
    }

    # Cleanup
    if ($DeployVMResult.VMName -ne $null) {
        $DestroyVMOutput = Manage-HyperVVM -VmName $DeployVMResult.VMName -Destroy -ErrorAction SilentlyContinue
    }
    if ($DeployVMResult.ExternalSwitchCreated) {
        Remove-VMSwitch "ToExternal" -Force -ErrorAction SilentlyContinue
    }
    if ($DeployVMResult.TempHyperVVMLocation -ne $null) {
        if (Test-Path $DeployVMResult.TempHyperVVMLocation) {
            Remove-Item $DeployVMResult.TempHyperVVMLocation -Recurse -Force
        }
    }
    if ($DeployVMResult.BoxFileLocation -ne $null) {
        if (Test-Path $DeployVMResult.BoxFileLocation) {
            Remove-Item $DeployVMResult.BoxFileLocation -Force
        }
    }

    $Output = [ordered]@{
        ExternalvSwitchWorks    = if ($ExternalvSwitchWorks -eq $null -or $ExternalvSwitchWorks -eq $False) {$False} else {$True}
        CanReachInternet        = if ($CanReachInternet -eq $null -or $CanReachInternet -eq $False) {$False} else {$True}
        CanReachRouter          = if ($CanReachRouter -eq $null -or $CanReachRouter -eq $False) {$False} else {$True}
    }

    if ($IsVirtual) {
        if ($VMDeployed) {
            $Output.Add("VirtualizationExtensionsExposed",$True)
        }
        else {
            $Output.Add("VirtualizationExtensionsExposed",$False)
        }

        if ($MacAddressSpoofingEnabled -eq $False) {
            $Output.Add("MacAddressSpoofingEnabled",$False)
        }
        elseif ($ExternalvSwitchWorks -eq $True) {
            $Output.Add("MacAddressSpoofingEnabled",$True)
        }
        elseif ($VirtualizationExtensionsExposed -eq $False -or $VirtualizationExtensionsExposed -eq $null) {
            $Output.Add("MacAddressSpoofingEnabled","Unknown")
        }
        else {
            $Output.Add("MacAddressSpoofingEnabled",$False)
        }
    }

    [pscustomobject]$Output

    Pop-Location
    
    #endregion >> Main Body
}