- If a Windows service hangs, restart the service with PowerShell - Mon, Dec 12 2022
- Install, remove, list, and set default printer with PowerShell - Mon, Nov 7 2022
- Format time and date output of PowerShell New-TimeSpan - Wed, Nov 2 2022
Prerequisites
- Basic knowledge of Hyper-V and Windows Networking
- The Hyper-V module for Windows PowerShell
- Any supported version of the Windows Operating System
Current scenario (example)
If you have a VM with multiple virtual network interface cards (NIC), it can be challenging to know which NIC is connected to which virtual switch. If you created the VM using the default naming convention, they are all named "Network Adapter" in Hyper-V.
In the examples I provide below, I worked with a VM, named "Proxy2," that has two NICs: one connected to the virtual switch ExternalLan and one connected to the virtual switch Private.
The PowerShell equivalent to see the NIC-related summary is:
Get-VMNetworkAdapter -VMName "Proxy2" | Select-Object VMName,SwitchName,Name
Both NICs have the same name (Network Adapter), as shown in the screenshot below.
If we look at the NICs from inside the VMs in the Network Connections applet (ncpa.cpl), there's not too much information there either. The first NIC is named "Ethernet," and all other NICs are named "Ethernet," followed by a number ("Ethernet 2," in this case).
Using PowerShell inside the VM shows the same (little) information:
Get-NetAdapter
With only this information, it is difficult to know whether, for example, the interface "Ethernet 2" is connected to the Private virtual switch or to the ExternalLan. Fortunately, there is a simple solution.
Desired scenario: VMs with NIC names that are easily identifiable
There are three simple steps to follow to make your VM's NICs easy to identify. Here is an overview, before we discuss each step in more detail.
Turn on Device Naming for the NIC, which enables seeing the name of the NIC inside the VM. This only works for supported operating systems. I hope that in the future all the operating systems supported by Hyper-V will support this, and the setting will be turned on by default. But for now, at least, this feature works on all the supported editions of Windows (both Client and Server).
On the Hyper-V host, change the name each of the VM's NICs to a more relevant name.
In the VM, I will rename the NICs from "Ethernet x" to the name I assigned in the previous step. It is easier than it sounds, and it will be clearer once we work with an actual example.
Below, we explain each step in more detail.
Step 1: Enable Device Naming
Using the GUI
Before renaming a VM's NICs, there is one thing you need to do, which allows you to "see" the (new) name of the NIC inside the VM as well. This task is accomplished by turning on the "DeviceNaming" attribute of the NIC, using the Hyper-V GUI (or the Cluster Manager console if your VMs are clustered). To turn on Device Naming in the GUI:
- Select the Network Adapter and click the "+" sign to expand its properties.
- Select Advanced Features.
- Scroll to the Enable device naming property and enable it (here you also see the explanation of this setting).
- Click Apply to apply the setting and repeat this for all the other NICs of the VM.
Using PowerShell
Of course, you can achieve this in PowerShell, using the DeviceNaming switch with the commands Add-VMNetworkAdapter (for a new NIC) or Set-VMNetworkAdapter (for an existing NIC). Here is how to turn on Device Naming for all the NICs of the VM "Proxy2":
Get-VMNetworkAdapter -VMName "Proxy2" |Set-VMNetworkAdapter -DeviceNaming On
That is all. Just one single line for all the NICs. Of course, you could do this for all the VMs in a single line, which can save you a lot of clicks.
Step 2: Change the name of the NICs in the Hyper-V host
In this step, you will change the name of the NICs to something more relevant than "Network Adapter."
I prefer to name each NIC according to the virtual switch the NIC is connected to. In our case, the NIC connected to the ExternalLan virtual switch will be called "ExternalLan," and the NIC connected to the Private virtual switch will be called "Private." I admit it is not the most creative solution, but it is simple to automate and better than "Network Adapter" for every NIC attached to the VM.
Of course, you may use different names that make more sense to you. For instance, you might rename the NIC connected to an "external" to "Internet" and the NIC connected to an isolated network could be called "Corporate" or "Internal." I will provide examples for both scenarios.
You can assign a different name to a NIC either when you create it and add it to a VM (Add-VMNetworkAdapter) or when you reconfigure an existing one (Set-VMNetworkAdapter).
This means you can easily perform this on your existing VMs without having to remove and then add new NICs.
Note: You need to use PowerShell to change the name of a NIC; there is no way to rename it via the GUI.
Note: If you just turned on Device Naming, you will need to reboot the VM.
Scenario 1: Rename each NIC to the name of the virtual switch it is connected to
In this case, every NIC attached to the VM will be renamed to the name of the virtual switch it is connected to. Each command has a comment to explain what the command does.
# Name of the VM for which the NICs will be renamed $VM = "Proxy2" # Get a list of all the switches the $VM has NICs connected to $VmSwitches = (Get-VMNetworkAdapter -VMName $VM).SwitchName # Rename each NIC of the VM to the name of the virtual switch it is connected to foreach ($C in $VmSwitches) { Get-VMNetworkAdapter -VMName $VM ` | Where-Object SwitchName -EQ $C ` | Rename-VMNetworkAdapter -NewName $C -Verbose }
The renamed VNICs (in the GUI):
The renamed VNICs (in PowerShell):
Get-VMNetworkAdapter -VMName "Proxy2" | Select-Object VMName,SwitchName,Name
Scenario 2: Rename each NIC to custom names
In this case, every NIC attached to the VM will be renamed to the name of the virtual switch it is connected to. As in Scenario 1 above, each command has a comment to explain what the command does.
# Name of the VM for which the NICs will be renamed $VM = "Proxy2" # Rename the NIC connected to the ExternalLan virtual switch to a custom name Get-VMNetworkAdapter -VMName $VM ` | Where-Object SwitchName -EQ "ExternalLan" ` | Rename-VMNetworkAdapter -NewName "Internet" -Verbose # Rename the NIC connected to the Private virtual switch to a custom name Get-VMNetworkAdapter -VMName $VM ` | Where-Object SwitchName -EQ "Private" ` | Rename-VMNetworkAdapter -NewName "Corporate" -Verbose
The renamed VNICs:
Get-VMNetworkAdapter -VMName "Proxy2" | Select-Object VMName,SwitchName,Name
At the end of Step 2, the NICs attached to the VM have been renamed to more relevant names. In the next step, the NICs from inside the VM will be renamed to match the names we just defined.
Step 3: Change the name of the NICs inside the VM using PowerShell
So far, the NICs of our VM have been renamed with more relevant names. At this moment, the name of the NICs inside the VM are still something like (the boring) "Ethernet #xx."
You still need to change the NICs' names yourself inside the VM; they did not change automatically when you renamed them in the Hyper-V host.
You could accomplish this manually, but you would have to dig through one NIC at a time in Hyper-V, disconnect it or disable it inside the VM, and see what breaks.
With PowerShell, you do it all in one step. All the NICs inside the VMs are changed to have the same names as defined in Hyper-V. It's quick and easy, without "shooting in the dark" and hoping you selected the right NIC.
To accomplish this, use the command Get-NetAdapterAdvancedProperty, which exposes a lot of advanced information about each NIC. To sift through all the relevant information, you only need to look at the property "Hyper-V Network Adapter Name", as in the example below:
Get-NetAdapterAdvancedProperty -DisplayName "Hyper-V Network Adapter Name"
You already see where we are going. The last step is to rename each NIC with the value from "DisplayValue." (Note: If you do not see any value, it means the NIC has not been renamed after you turned on Device Naming.)
The command below will rename the NICs.
# Virtual NICs added without the switch "DeviceNaming" set to On have no value set in DisplayValue, and will be ignored foreach ($N in (Get-NetAdapterAdvancedProperty -DisplayName "Hyper-V Network Adapter Name" | Where-Object DisplayValue -NotLike "")) { $N | Rename-NetAdapter -NewName $n.DisplayValue -Verbose }
And that's it. Next time you check your network settings, you can easily identify which NIC is which.
Conclusion
It is good hygiene to use relevant, consistent names for your NICs inside the VMs, just like those for inside your physical machines. This is particularly helpful in the case of VMs with multiple NICs.
You may modify your deployment scripts to automatically turn on Device Naming for new VMs, and you may also apply them to existing VMs.
Hi there,
Great post !
I didn't know about this Device Naming Feature … I did some kind of equivalent HV NIC / VM NIC matching by using Powershell Direct, but this gave me some new ideas, thanks !
Unfortunately, I work on 2012R2 HV too, and no Device Naminf feature and no Powershell Direct … 🙁
Do you know another way of doing this in 2012R2 HV ?
Regards
Hi, Gino.
According to this Microsoft article, the feature was introduced in WS2016. It's a feature for Gen2 Hyper-V VMs. I couldn't find any workaround for earlier versions (like WS2012R2).
Regards. Emanuel
Hi Emmanuel and thank you for your reply.
I'm an IT Trainer and wanted to write some Powershell scripts that deploy a VMs Infrastructure automatically depending on the training I have to deliver. This script is driven by 3 csv files (switches, vms, nics).
My true problem with 2012R2 was not naming but matching VM Network cards with right HV switches for 'routers like' VMs.
When you start a VM with several nics for the 1st time, order is random, there is no logic … ?
So the VM nics are mixed the wrong way relatively to switch creating order.
I found a way to get my job done by modifying my script to :
– create a 'Dummy' internal switch
– connect one VM Network card at a time on the 'Dummy' switch allowing the HV Host to communicate with the VM with WinRM
– Grab the VM internal nics names and MacAddress with winrm
– Connect each VM Nic to the right switch
But I'm still trying to know if there is another way to know which VM Nic is connected to which HV switch (winrm is slow …)…
Hi, Gino.
One thing I could think of is to retrieve the MAC address from the host, and then use that information to identify the NIC.
Get-VMNetworkAdapter -VMName VM1 | Select-Object SwitchName, MacAddress
I haven't tested in WS2012 (I don't have hosts with WS2012), but if it works, I think that should help you.
Regards. Emanuel
Hi Emanuel
Thank you and Yes I use this command to get SwitchName and MacAddress but it's not sufficient to be sure nics are connected to the right switch.
the problem is with routers ; for example, with powershell, I create a 3 NIC router VM from my 2012R2 master vhdx. Before starting the VM. I inject a powershell script that creates, configure and rename the needed nics inside my VM according to switch names..
From Hyper-V point of view, same thing, one HVNIC is connected to a Paris switch, another one to a London switch and the last one to a WAN switch.
When I start the VM, the nics inside the VM don't match, everything is random, there is no logic.
The nics inside the VM are not detected and named in the same order as they are created or connected to a switch. I spent some hours trying to find some logic but there is not …
Sometimes the first created VMNetadapter is named "…..Microsoft Hyper-V #3" or "…..Microsoft Hyper-V #2". Sometimes it is on the right switch but it's only luck. this is a non sense.
So I Had another idea. I used a command like yours to get switch names and MacAddress and wanted to inject these parameters in the VM boot script.
Unfortunately, you can't get any MACAddress from Hyper-V unless you already started the VM !
That's why I use WinRM. It's impossible for me to get the right matchines Nics/Switch whithout communicating with the VMs from the HV host.
Thanks for your help anyway
Hi, Gino.
I had no idea the MACs are not "seen" until the VM is powered on.
I guess a workaround would be to assign the MACs manually from a pool.
You would need to figure a way to avoid duplicate MACs, but probably a shared CSV file would be enough. You may populate it when you're planning your infrastructure or as you add VMs in the environment).
If I could pick, I'd just use more recent OS'es, but is it safe to guess the restriction is not technical? (I don't know if a happy or sad emoticon is more suitable here…)
Its correct that MAC is assigned on first Power on.
However, I dont really understand what Gino is trying to do. The thing you mention, that NICs are not detected by Windows in the same order as you see them in Hyper-V – that totally normal tho. There is no "order" property or something that would allow Windows to map the devices as you see them. If you want to do this, then you need to start the VM first and add the NIC adapters one by one. Then Windows should create the same way as you see it in the VM.
If I deploy a VM with 3 NICs, I am assigning the switch in the VM properties. So you already know which NIC is connected to which switch. Then I can simply power on the VM, grab the MAC addresses, and push a script to the VM that does proper configuration.
L
Leos, that sounds like a better idea. I was trying to stick to Gino's restrictions, but your workaround sounds easier than static MACs (which would accumulate to a messy problem in time).
Thanks, I posted one more comment few seconds later, think its even better 😀
PS – You dont need a VM NIC to be connected to any switch to utilize Invoke-Command -VMname from Hyper-V host. This does not work over network from Hyper-V to the VM.
So, you can simply create a VM with 3 NICs, leave them Not Connected, start your VM, grab your mac addresses, invoke your command to the VM and then connect the NICs to switches.
Hope that helps.