Last active
November 1, 2022 15:53
-
-
Save jurbanek/6411a39b613169a86602d0877fc4d555 to your computer and use it in GitHub Desktop.
Hyper-V Network Fix
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<# | |
.SYNOPSIS | |
Apply a defined IP network to the Hyper-V Default Switch | |
.DESCRIPTION | |
Apply a defined IP network to the Hyper-V Default Switch | |
After host restart, the Hyper-V Default Switch IP network changes to a non-deterministic value. The Default Switch | |
provides DHCP and NAT services to allow VM's to communicate to the outside and Internet. The changing IP network | |
presents challenges for VM's with static IP addresses on the Default Switch. | |
This script defines a network (in the form of the actual interface IP and prefix length) and will add the network | |
(as an additional IP address) to the Default Switch's VM-facing interface and restart necessary services. | |
.NOTES | |
Removing the current address and replacing it with a new one does not seem to function reliably given Hyper-V internals. | |
The reliable way to provide static addressing (and still provide NAT for outside access) is by adding an IP address. | |
Given specific services to be restarted, administrative privileges are required. | |
At times the restart of the Internet Connection Sharing (ICS/SharedAccess) service fails, but the service does pick up | |
the configuration changes. ICS is responsible for the NAT services. | |
Windows 11 22H2 changed "vSwitch (Default Switch)" interface to be hidden by default. Get-NetAdapter now searches hidden | |
adapters as well. To find your interface/adapter anme (if different), use Get-NetAdapter -IncludeHidden. | |
.INPUTS | |
None | |
.OUTPUTS | |
None | |
.EXAMPLE | |
#> | |
[CmdletBinding()] | |
Param() | |
$Config = @{} | |
# Desired IPv4 address assigned to Hyper-V default network interface. Represents the default gateway for the network | |
$Config.Add('IPv4Address', '172.30.144.1') | |
# Desired IPv4 netmask for Hyper-V default network. Hyper-V defaults to a 255.255.240.0, a /20 | |
$Config.Add('IPv4PrefixLength', 20) | |
# Name of the Hyper-V default network interface | |
$Config.Add('InterfaceAlias', 'vEthernet (Default Switch)') | |
# Do not set the InterfaceIndex, will be determined at runtime based on the InterfaceAlias | |
$Config.Add('InterfaceIndex', $null) | |
# Duration to wait after restarting services | |
$Config.Add('SleepSeconds', 12) | |
# Verify running as Administrator (for service restarts) or error and stop | |
try { | |
$WindowsIdentity = [System.Security.Principal.WindowsIdentity]::GetCurrent() | |
$WindowsPrincipal = New-Object -TypeName System.Security.Principal.WindowsPrincipal -ArgumentList $WindowsIdentity | |
if($WindowsPrincipal.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)) { | |
Write-Information ($MyInvocation.MyCommand.Name + ': ' + $WindowsPrincipal.Identity.Name + ' running as Administrator') -InformationAction Continue | |
} | |
else { | |
throw ($WindowsPrincipal.Identity.Name + ' NOT running as Administrator. Elevate and try again. Stop') | |
} | |
} | |
catch { | |
$Msg = $MyInvocation.MyCommand.Name + ': Error verifying running as Administrator. Stop' + "`n" | |
$Msg += $_.Exception.Message | |
Write-Error $Msg -ErrorAction Stop | |
} | |
# Determine the adapter/interface Index value or error and stop | |
try { | |
$NetAdapter = Get-NetAdapter -IncludeHidden -InterfaceAlias $Config.InterfaceAlias -ErrorAction Stop | |
$Config.InterfaceIndex = $NetAdapter.InterfaceIndex | |
Write-Information ($MyInvocation.MyCommand.Name + ': Found interface: ' + $Config.InterfaceAlias + '. Index: ' + $Config.InterfaceIndex) -InformationAction Continue | |
} | |
catch { | |
$Msg = $MyInvocation.MyCommand.Name + ': Failed to locate interface: ' + $Config.InterfaceAlias + '. Stop' + "`n" | |
$Msg += $_.Exception.Message | |
Write-Error $Msg -ErrorAction Stop | |
} | |
# Determine if desired address is assigned | |
try { | |
if(Get-NetIPAddress -InterfaceIndex $Config.InterfaceIndex -IPAddress $Config.IPv4Address -PrefixLength $Config.IPv4PrefixLength -ErrorAction SilentlyContinue) { | |
Write-Information ($MyInvocation.MyCommand.Name + ': Found : ' + $Config.IPv4Address + '/' + $Config.IPv4PrefixLength + '. No action required') -InformationAction Continue | |
$RestartRequired = $false | |
} | |
else { | |
Write-Information ($MyInvocation.MyCommand.Name + ': Did not find: ' + $Config.IPv4Address + '/' + $Config.IPv4PrefixLength + '. Adding') -InformationAction Continue | |
New-NetIPAddress -IPAddress $Config.IPv4Address -PrefixLength $Config.IPv4PrefixLength -AddressFamily IPv4 -InterfaceIndex $Config.InterfaceIndex -ErrorAction Stop | Out-Null | |
$RestartRequired = $true | |
} | |
} | |
catch { | |
$Msg = $MyInvocation.MyCommand.Name + ': Failed to add address: ' + $Config.IPv4Address + '/' + $Config.IPv4PrefixLength + '. Stop' + "`n" | |
$Msg += $_.Exception.Message | |
Write-Error $Msg -ErrorAction Stop | |
} | |
# Restart Services - if vmms fails, stop. If ICS fails, not always an indication of failure - don't understand why | |
if($RestartRequired) { | |
try { | |
Write-Information ($MyInvocation.MyCommand.Name + ': Restarting Hyper-V Virtual Machine Management Service') -InformationAction Continue | |
Restart-Service -Name 'vmms' -ErrorAction Stop | |
} | |
catch { | |
$Msg = $MyInvocation.MyCommand.Name + ': Error restarting Hyper-V Virtual Machine Management Service. Stop' + "`n" | |
$Msg += $_.Exception.Message | |
Write-Error $Msg -ErrorAction Stop | |
} | |
Write-Information ($MyInvocation.MyCommand.Name + ': Sleeping for ' + $Config.SleepSeconds + ' seconds') -InformationAction Continue | |
Start-Sleep -Seconds $Config.SleepSeconds | |
try { | |
Write-Information ($MyInvocation.MyCommand.Name + ': Restarting Internet Connection Sharing (ICS) Service') -InformationAction Continue | |
Restart-Service -Name 'SharedAccess' -ErrorAction Stop | |
} | |
catch { | |
# Not using Write-Error to stop here given this is frequently NOT an error condition and the end of the script | |
Write-Information $_.Exception.Message -InformationAction Continue | |
Write-Information ($MyInvocation.MyCommand.Name + ': Error restarting Internet Connection Sharing (ICS) service. Verify VM connectivity anyway as the service frequently picks up the changes') -InformationAction Continue | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Windows 11 22H2 changed "vSwitch (Default Switch)" interface to be hidden by default.
Get-NetAdapter
now searches hiddenadapters as well. To find your interface/adapter name (if different), use
Get-NetAdapter -IncludeHidden
.