Configuring VM Networking on a Hyper-V NAT Switch

Server Hero Network Cable Port
In this post, I will explain some methods you can use to configure the IPv4 address configuration of a Hyper-V virtual machine that is connected to a NAT virtual switch on Windows 10 or Windows Server 2016 (WS2016).
 

 

The Problem

The virtual switch does not have a way to dynamically assign IPv4 configurations to connected virtual machines. So, we need to rely on something else. That something else is usually a DHCP server on the LAN.
Virtual machines that are connected to a NAT virtual switch are in an isolated broadcast domain, a different one to the LAN. The NAT switch does not have flat, 2-way routing to the LAN that the host is connected to. The virtual switch is an internal virtual switch that the host NATs to the LAN. This means that, by default, the virtual machines can connect to the LAN, but the LAN cannot connect to the virtual machines. And even if we do create NAT rules, the virtual switch remains a separate broadcast domain from the LAN.
The effect of this is that any DHCP services that you have running on the LAN cannot reach the virtual machines on a NAT virtual switch, and we have to manually assign IPv4 address configurations in each guest OS; you could do this by hand, but that’s time-consuming, and I have a few other ways that you can consider.

DHCP in the Virtual Switch

As I said, the virtual switch is somewhat isolated from the LAN, especially from broadcast-based services such as DHCP. You can deploy your own DHCP server(s) as virtual machines that are connected to the virtual switch. The scope of these servers is limited to the virtual switch, so there is no impact on the LAN, and network administrators should not have a problem with your DHCP servers being deployed on the NAT virtual switch.
However, don’t ever let these DHCP servers connect to an external virtual switch; they will interfere with normal LAN operations and land you in some very hot water (figuratively and maybe literally) with the network administrators once they track you down.

Inject an IPv4 Configuration from The Host

It is possible to use the Msvm_GuestNetworkAdapterConfiguration WMI class to inject an IP configuration into a virtual machine from the host. The WMI coding can be pretty messy, but Pavel Ptacek shared a PowerShell function called Set-VMNetworkConfiguration on GitHub that we can use. Copy the function, paste it into a new PowerShell script, and add a single line of PowerShell at the end of the script to call the function:

Get-VMNetworkAdapter -VMName Petri-VM1 -Name "Network Adapter" | Set-VMNetworkConfiguration -IPAddress 192.168.0.31 -Subnet 255.255.255.0 -DNSServer 208.67.222.222 -DefaultGateway 192.168.0.1

You can re-use the above line, over and over, on each required virtual machine without having to log in; go into Control Panel, type in a bunch of settings, and log out again.
Note that this WMI functionality has been around since Windows Server 2012 (WS2012) Hyper-V.

PowerShell Direct

WS2016 introduced new functionality where we can use PowerShell remoting to log into a virtual machine from the host via the VM Bus, even if the virtual machine has no network connectivity. We can then use this functionality to assign an IP address configuration. You would run the following commands, line by line, at an elevated PowerShell prompt from the host.

Start off by logging into the virtual machine; you will need a guest OS administrator account and password:

Enter-PSSession -VMName Petri-VM1

Retrieve the name of the adapter you want to configure:

Get-NetAdapter

Set the IP address, subnet mask, and default gateway of the required adapter using the next line:

New-NetIPAddress -InterfaceAlias "Ethernet 2" -IPAddress 192.168.0.31 -PrefixLength 24 -DefaultGateway 192.168.0.1

Configure the DNS settings using the following command:

Set-DnsClientServerAddress -InterfaceAlias "Ethernet 2" -ServerAddresses "208.67.222.222,208.67.220.220"

Exit the PowerShell Direct session by running the Exit command.
If you would prefer to scale this solution out with a script, then the Invoke-Command option would be better. We will create a session via PowerShell Direct and store the details in a variable called $Session, and then run the above two IPv4 configuration commands using Invoke-Command:

# You are prompted to sign-in using the following line to create a PowerShell Direct session that we can reuse.
$Session = New-PSSession -VMName Petri-VM1 -Credential Petri-VM1\administrator
# Configure the IPv4 sessions using the saved PowerShell Direct session
Invoke-Command -Session $Session -ScriptBlock { New-NetIPAddress -InterfaceAlias "Ethernet 2" -IPAddress 192.168.0.31 -PrefixLength 24 -DefaultGateway 192.168.0.1 }
Invoke-Command -Session $Session -ScriptBlock { Set-DnsClientServerAddress -InterfaceAlias "Ethernet 2" -ServerAddresses "208.67.222.222,208.67.220.220" }
# The following line cleans things up by ending the PowerShell Direct session
Remove-PSSession $Session

All that remains now is to figure out how to create NAT rules so that we can access virtual machines from the LAN; I’ll cover that in a later post.