Where I work, we use VMware to virtualize the majority of our servers. Last year, we bought four new servers in order to provide more resources to our virtual evironment, and also to aid in the upgrade to vSphere 4 from VI3. The plan was to power off all virtual machines and perform an offline migration of all the VMs from the old cluster to the new cluster. However, we were also migrating from the vSwitch to the distributed virtual switch (dvSwitch).

The Setup:

To start out, I upgraded VMware vCenter Server to version 4.x. After that was done, I created a new cluster and added all four new hosts to it. I then mapped all of the same LUNs to the new cluster that were already mapped to the old cluster. This allowed me to do a migration from the old cluster to the new without having to worry about storage migrations. Next, I created the new dvSwitch with all the same port groups as the old vSwitch. It was important to make sure all VLAN IDs were present. Finally, I powered off all virtual machines.

The Code

Now for the interesting part. I wrote a PowerShell script to automate the migration of the VMs from the old cluster to the new. At the same time, it looks at the vSwitches and maps them to their equivalent dvSwitch port group by looking for matching VLALN IDs. For example, if there is a vSwitch port group called “Monkey” with VLAN ID of 123, it will check the dvSwitch port groups and map that to whichever one also has VLAN ID 123.

# Generate a hash of dvSwitch port group VLAN IDs and names, using ID as key.
function CreateDVMap() {
        $vlanmap = @{}
        $pgs = Get-VIew -ViewType DistributedVirtualPortgroup
        foreach ($pg in $pgs) {
                $vlan = $pg.Config.DefaultPortConfig.vlan.vlanid

                if ($vlan -and !$vlanmap.ContainsKey($vlan)) {
                        $vlanmap.Add($vlan, $pg.name)
        return $vlanmap

function MigrateVM($vm, $target, $dvMap) {
        # Is the virtual machine in the "Test Dev" resource pool?
        $resPool = Get-ResourcePool -VM $vm
        if ($resPool -and $resPool.Name.CompareTo("Test Dev") -eq 0) {
                $TestDev = $true
        } else {
                $TestDev = $false

        $newnetnames = @()
        Write-Host "Migrating VM", $vm.Name

        # Translate the vSwitch PG of each NIC to the equivalent dvSwitch PG
        foreach ($nic in $vm.NetworkAdapters) {
                Write-Host $nic.name -ForegroundColor Blue
                Write-Host $nic.NetworkName -ForegroundColor Green
                $vlanid = (Get-VirtualPortGroup -Name $nic.NetworkName -VMHost $vm.Host).VlanId
                Write-Host "VLAN ID is" $vlanid
                $newnetnames += $dvMap.get_item($vlanid)

        $newvm = Move-VM -VM $vm -Destination $target

        if ($TestDev) {
                # If it is a Test/Dev VM, move it to the new resource pool
                $rp = Get-ResourcePool -Location $newvm.host.parent -Name "Test Dev"
                $newvm = Move-VM -vm $newvm -Destination $rp

        # Now, set all the NICs to their new dvSwitch port group
        $i = 0
        foreach ($nic in $newvm.NetworkAdapters) {
                Set-NetworkAdapter -NetworkAdapter $nic -NetworkName $newnetnames[$i++] -Confirm:$false

# Connect to the vCenter Server
$vihost = Connect-VIServer "vCenter-Server-Hostname"

# Target host in the new cluster to deposit all VMs on
$targetHost = Get-VMHost "Some-Hostname-Here"

# Generate a hash of all dvSwitch PGs
$vlanmap = CreateDVMap

# Get a list of all VMs in "Production cluster"
$vmlist = Get-VM -Location (Get-Cluster "Production") | Where { $_.PowerState -eq "PoweredOff" } | Select "Name"

# Iterate through the VMs and migrate them
foreach ($vmname in $vmlist) {
        $vm = Get-VM $vmname.name
        MigrateVM $vm $targetHost $vlanmap

Disconnect-VIServer $vihost -Confirm:$false

© Copyright 2011-2018 Sean Kelly