vCenter Network Automation with PowerCLI


Ever needed to migrate VMs between vCenter servers but been tied down due to VM networking? Hopefully the solutions provided here will help alleviate the problem.

If you've got a large vCenter environment using VMware Distributed Switches (VDS) it's an absolute nightmare to move to a new vCenter server. A typical reason for this would be to merge multiple environments together in order to have a single point of management.

The problem actually lies with the mapping of NICs on VMs to their respective networks. When you move an ESXi host into a new vCenter server and it becomes disconnected from it's original vCenter the network it is mapped to is lost. This causes the virtual machine to report Invalid Network Backing under it's NIC(s). The VM itself will continue to function on it's previous network, but you will not be able to change the adapter, or view it's current network settings.


First Try - Import / Export VDS

One starting point which was introduced by the vSphere Web Client is the capability to import / export a VDS. This is great if you've got a large switch with many different networks and VLANs across it, however this seems to cause strange behaviour in VMs.

I started by exporting the current VDS, importing it into the new vCenter server and moved an ESXi host over with a few VMs running on it. Some of these VMs then reported perfect connectivity to the VDS, however the majority still reported Invalid Network Backing. I'm unsure as to the reason why some VMs are fine, and some are not. I expect it is to do with the assignment of virtual ports on the vSwitch itself, something which I would rather not have to deal with.

Second Try - The manual approach

I'm a firm believer in the simplest solution is the best. And often just doing it manually it easier. However I had a few hundred VMs to move, and most of them had at least two NICs. That's a whole lot of soul destroying time.

The manual approach can be combined with the above importing and exporting of a VDS. Effectively you have to clean up after the migration by checking each and every VM to make sure that it is connected correctly to the VDS. If it is not, add the NIC back to it's appropriate port-group. This requires noting down all of the VMs on a host before it's added to the new vCenter server, and then clicking through menus to re-assign the NIC. Simple, but soul destroying. No way was I doing that for all my VMs.

Third Try - PowerCLI (The winner!)

I've never touched it before. I'd like to think I have some capability when it comes to scripting and programming so I expect my background helped with understanding it.

Installing PowerCLI

I'd not normally bother posting what I'd consider trivial information here, but I did have some issues when installing and using VMware PowerCLI for the first time. It's easy enough to download and install it, however I faced an error and struggled for a while to resolve it.

The issue I faced was some path error. Which can be found here: I pasted this into a PowerShell prompt (as instructed on the above link) and it seemed to clear up the issue:

$CurrentValue = [Environment]::GetEnvironmentVariable("PSModulePath", "Machine")
[Environment]::SetEnvironmentVariable("PSModulePath", $CurrentValue + ";C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\Modules", "Machine")
The Method

The method I used (there may be a better one) was to use a "ferry" ESXi host to move between the vCenter servers. In my case I've got such a beefy ESXi server I managed to put the entire cluster worth of VMs onto a single host. The steps for the process are below:

  • Create the VDS in the new vCenter (either build manually or import / export. I rebuilt mine as I wanted to change all of the network labels).
  • Create a standard vSwitch on one of the ESXi hosts
  • Move one of the redundant NICs on the ESXi host to this vSwitch
  • Create port-groups on the switch to reflect the VLANs on the DVS (I did this manually, but you could automate it fairly easily using PowerCLI).
  • Move VMs from the DVS to the standalone vSwitch (PowerCLI does this)
  • Add the host into the new vCenter server
  • Remove the old (invalid) VDS
  • Add the new VDS to the host, using the uplink which was used by the old VDS
  • Move VMs from the standard vSwitch to the new VDS (PowerCLI does this).

This might sound long winded, but I could not think of an easier approach without VMs losing connectivity. I'd love to know if there was a faster approach but this worked reasonably well.

The actual PowerCLI part looks at a particular network, and moves any adapters it finds to a new target network. This has to be repeated for each network, and it would be perfectly do-able to automate the entire lot. However I like to maintain some manual control as I do not trust myself to come up with a fully automated script on a production DC!

get-vm -location | get-networkadapter | where {$_.NetworkName -eq "OLD-DVS-VL200" } | Set-NetworkAdapter -NetworkName "Standard-Vswitch-VLAN200" -Confirm:$false

This is the single handy line of code which performs that conversion. Where OLD-DVS-VL200 is the OLD DVS port-group and Standard-Vswitch-VLAN200 is the new port-group on the standard vSwitch.

After the host has been moved to the new vCenter, this then reverses, so the source network is the standard vSwitch. E.g.:

get-vm -location | get-networkadapter | where {$_.NetworkName -eq "Standard-Vswitch-VLAN200" } | Set-NetworkAdapter -NetworkName "NEW-DVS-VL200" -Confirm:$false

That's it! For each network you can use these commands before and after migration. Personally I copy-pasted this command multiple times into notepad++ and edited the names for each command, then pasted the entire block of commands straight into PowerCLI.

Another rather useful snippet I managed to put together is the ability to audit the networks of VMs. This can help with the manual approach if you would rather not use a script, and saves going through each VM manually checking VM-network assignments.

get-vm -location | Foreach-Object {
    $vm = $_
    $adapter = Get-Networkadapter $vm
    New-Object -TypeName PSObject -Property @{
        Name = $vm.Name
        Adapter = $adapter.Name
        Network = $adapter.NetworkName

This gives a nice tabulated output of which VMs have which network adapters, and which of these network adapters is associated to a particular network.

One further one-liner I came up with was to add port-groups to a DVS. If you're rebuilding a VDS and have a good number of VLANs this is a great way of speeding up the process.

new-vdportgroup -vdswitch DVS-NEW -name DVLAN-2021-D4-U -vlanid 2021