Private/Confirm-Win32ToolkitGuestInternet.ps1
|
function Confirm-Win32ToolkitGuestInternet { <# .SYNOPSIS Verifies (and best-effort repairs) that the guest has working outbound internet, over PowerShell Direct. Returns $true once the guest can resolve DNS and fetch Microsoft's connectivity probe. .DESCRIPTION Windows Update in the guest needs real internet. On a NESTED Hyper-V guest using the 'Default Switch' (NAT/ICS) — the toolkit's default — outbound routing usually works but the switch's DNS proxy is flaky, so name resolution fails and Windows Update sits idle. This checks connectivity and, if it's not working, repairs the guest side: renews DHCP, sets a public DNS resolver on the active adapter, and flushes the cache — then re-tests, up to a timeout. HOST-ONLY; all guest work runs inside the VM via Invoke-Command over the VMBus (5.1-safe cmdlets only). .PARAMETER VMName The test VM. .PARAMETER Credential Guest local-admin credential for PowerShell Direct. .PARAMETER TimeoutSeconds Overall budget for reach-or-repair-and-retry. Default 120. .PARAMETER FallbackDns Public resolvers set on the guest adapter during repair. Default Cloudflare + Google. .OUTPUTS [bool] $true if the guest reached the internet (possibly after repair), else $false. #> [CmdletBinding()] [OutputType([bool])] param( [Parameter(Mandatory)] [ValidateNotNullOrEmpty()] [string]$VMName, [Parameter(Mandatory)] [ValidateNotNull()] [pscredential]$Credential, [int]$TimeoutSeconds = 120, [string[]]$FallbackDns = @('1.1.1.1', '8.8.8.8') ) # Runs in the guest: true only if there's a default gateway, DNS resolves, and the MS probe returns # its known body. Kept 5.1-safe (the PS-Direct endpoint is Windows PowerShell 5.1). $probe = { $cfg = Get-NetIPConfiguration -ErrorAction SilentlyContinue | Where-Object { $_.IPv4DefaultGateway } if (-not $cfg) { return $false } try { $null = Resolve-DnsName 'www.msftconnecttest.com' -Type A -ErrorAction Stop } catch { return $false } try { $r = Invoke-WebRequest 'http://www.msftconnecttest.com/connecttest.txt' -UseBasicParsing -TimeoutSec 10 -ErrorAction Stop return ([string]$r.Content -match 'Microsoft Connect Test') } catch { return $false } } $deadline = (Get-Date).AddSeconds([Math]::Max(15, $TimeoutSeconds)) $attempt = 0 while ($true) { $attempt++ $ok = [bool](Invoke-Command -VMName $VMName -Credential $Credential -ScriptBlock $probe -ErrorAction SilentlyContinue) if ($ok) { return $true } if ((Get-Date) -ge $deadline) { return $false } Write-Verbose "Guest internet not confirmed (attempt $attempt) — repairing DHCP/DNS in the guest..." Invoke-Command -VMName $VMName -Credential $Credential -ScriptBlock { param($dns) & ipconfig /renew | Out-Null & ipconfig /flushdns | Out-Null $ad = Get-NetAdapter -Physical -ErrorAction SilentlyContinue | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1 if ($ad -and $dns) { try { Set-DnsClientServerAddress -InterfaceIndex $ad.ifIndex -ServerAddresses $dns -ErrorAction Stop } catch { } } } -ArgumentList (, $FallbackDns) -ErrorAction SilentlyContinue Start-Sleep -Seconds 8 } } |