Migrating distributed vSwitch to new vCenter

Customer called me to ask how they could easily migrate their existing vCenter to a new vCenter including all distributed vSwitches. They were moving from vCenter 4.0 to vCenter 4.1 and at the same time creating an AD intergrated vCenter and moving from physical to a virtual vCenter. The upgrade path would be a difficult road and they decided to just perform a fresh vCenter install. Since a dvSwitch is linked to vCenter and not the ESX host, you cannot move the dvSwitch to a new vCenter by connecting the ESX host to the new vCenter. We had to use a different path.

Biggest issue in this was the recreating of all the distributed virtual portgroups in the new vCenter, since they have over 400 different VLANs it would be a lot of manual work and of course error prone. Another issue was that the whole migration should take place without downtime for the VMs.

The migration path I suggested is found below. I searched for some PowerShell scripts to help automate this migration and found some great scripts from (of course) Luc Dekens (click for scripts)  and Glenn Sizemore ( click for blog) that served as the basics for my migration scripts.  The migration will be performed in a few steps. I haven’t automated all the steps and I created a number of small scripts instead of one big script to keep more control on the whole process.


Migration preparation

For this migration to work, you will need a ESX host with multiple vmnics. Since we’re going to move VMs from dvSwitch to vSwitch on the same host and can’t afford to lose network connectivity during these steps, it is important that you have a vmnic available for your existing dvSwitch and the new vSwitch. If your host has only a few vmnics, you might consider running on just one vmnic per (d)vSwitch during this migration. If your using Ethernet Channels, be sure to check with your network admins what the consequences are!!!

In this first version of my scripts, I only migrate the VLAN ID of the dvPortGroups. I’m working on a newer version that will migrate more dvPortGroups attributes like loadbalancing and security settings.


A global overview of the migration

  • Create a standard vSwitch and portgroups with VLAN-IDs on the ESX host
  • Change the portgroup of the VMs from dvPortGroup to the new temporary PortGroups
  • Create the new dvSwitch plus dvPortGroups on the new vCenter
  • Remove the dvSwitch from the ESX host
  • Move the ESX host to the new vCenter
  • Add the ESX host to the new dvSwitch
  • Change the portgroup of the VMs from temporary PortGroup to the new dvPortGroups


Perform Migration

  • Step01-Get-distributedswitch: This script reads the dvSwitches and dvPortGroups. Then the standard vSwitch will be created with the normal PortGroups and a CSV will be created holding a list of the PortGroups and their VLAN ID.
  • Manual intervention: add one or more vmnics to the vswitch
  • Step02-Move-VM-to-vSwitch: VMs will be migrated from the dvPortGroups to the temporary standard PortGroups
  • Step03-create-dvswitch-dvportgroup: On the new vCenter the new dvSwitch and dvPortGroups will be created.
  • Manual intervention: Remove the old dvSwitch from the ESX host
  • Manual intervention: Move the ESX host to the new vCenter
  • Manual intervention: Add the ESX host to the new dvSwitch
  • Step04-Move-VM-to-dvSwitch : VMs will be migrated from the temporary PortGroups to the dvPortGroups

In the near future I will post some updates to these scripts and try to automate even more steps to make this a complete migration wizard. Feel free to comment with new ideas or issues you are running into. The powershell scripts below can be downloaded as ZIP:  Migrate-dvSwitch-001

 

Step01-Get-DistributedSwitch:

# Migrating distributed vSwitch configurations from one vCenter to a new vCenter
# Written by: Gabrie van Zanten
# http://www.GabesVirtualWorld.com

function Get-dvSwitch{

	# This function was written by Luc Dekens
	# See: http://www.lucd.info/2009/10/12/dvswitch-scripting-part-2-dvportgroup/

	param([parameter(Position = 0, Mandatory = $true)][string]$DatacenterName,
	[parameter(Position = 1, Mandatory = $true)][string]$dvSwitchName)

	$dcNetFolder = Get-View (Get-Datacenter $DatacenterName | Get-View).NetworkFolder
	$found = $null
	foreach($net in $dcNetFolder.ChildEntity){
		if($net.Type -eq "VmwareDistributedVirtualSwitch"){
			$temp = Get-View $net
			if($temp.Name -eq $dvSwitchName){
				$found = $temp
			}
		}
	}
	$found
}

function Set-dvSwPgVLAN{

	# This function was written by Luc Dekens
	# See: http://www.lucd.info/2009/10/12/dvswitch-scripting-part-2-dvportgroup/

	param($dvSw, $dvPg, $vlanNr)

	$spec = New-Object VMware.Vim.DVPortgroupConfigSpec
	$spec.defaultPortConfig = New-Object VMware.Vim.VMwareDVSPortSetting
	$spec.DefaultPortConfig.vlan = New-Object VMware.Vim.VmwareDistributedVirtualSwitchVlanIdSpec
	$spec.defaultPortConfig.vlan.vlanId = $vlanNr

	$dvPg.UpdateViewData()
	$spec.ConfigVersion = $dvPg.Config.ConfigVersion

	$taskMoRef = $dvPg.ReconfigureDVPortgroup_Task($spec)

	$task = Get-View $taskMoRef
	while("running","queued" -contains $task.Info.State){
		$task.UpdateViewData("Info")
	}
}

function Get-dvSwPg{
	param($dvSw )

# Search for Portgroups
	$dvSw.Portgroup | %{Get-View -Id $_} 

}

# Report will be used to store the changes
$report=@()

# Ask what vCenter, datacenter and dvSwitch we're talking about
Disconnect-VIServer "*" -Force:$true
$vCenterOld = Read-Host "What is the name of the OLD vCenter: "
$DatacenterName = Read-Host "What is the name of the datacenter on the OLD vCenter: "
$OlddvSwitch = Read-Host "What is the name of the distributed vSwitch (dvSwitch) you want to move: "
$MovingHost = Read-Host "What is the name of the host you want to move: "

# Make the connection to vCenter
Connect-VIServer -Server $vCenterOld

# Read the dvSwitch and dvPortGroups
$dvSwitch = Get-dvSwitch $DatacenterName $OlddvSwitch
$dvPG = Get-dvSwPg $dvSwitch 

# Now create a (temporary) standard vSwitch with 128 ports. Remember, each VM needs one port and 128 might not be enough for you.
# The name of this temporary standard vSwitch will be 'vSwitch-Migrate'
New-VirtualSwitch -Name 'vSwitch-Migrate' -NumPorts 128 -VMHost $MovingHost
$vSwitch = Get-VirtualSwitch -VMHost $MovingHost -Name 'vSwitch-Migrate'

foreach( $dvPGroup in $dvPG )
	{

	$VLANID = $dvPGroup.Config.DefaultPortConfig.Vlan.VlanId
	# Somehow the first line in $dvPGroup is some kind of header with 'VMware.Vim.NumericRange' in it. So I skip it
	if( $VLANID -notmatch 'VMware.Vim.NumericRange')
		{

		# I want the new standard Portgroup to be named 'Mig-VLAN100' instead of 'VLAN100'
		$NewPG = 'Mig-' + $dvPGroup.Name

		# Create a New standard portgroup
		Get-VirtualSwitch -VMHost $MovingHost -Name 'vSwitch-Migrate' | New-VirtualPortGroup -Name $NewPG -VLanId $VLANID 

		# Just to always know what was what, I keep track of old and new names
		# This is where you could add more settings from the olddvPG, like load balancing, number of ports, etc.
		$Conversion = "" | Select olddvSwitch, olddvPG, tmpvSwitch, tmpvPG, VLANID
		$Conversion.olddvswitch = $dvSwitch.Name
		$Conversion.olddvPG = $dvPGroup.Name
		$Conversion.tmpvSwitch = Get-VirtualSwitch -VMHost $MovingHost -Name 'vSwitch-Migrate'
		$Conversion.tmpvPG = $NewPG
		$Conversion.VLANID = $VLANID
		$report += $Conversion

		}
	}

# Writing the info to CSV file
$report | Export-Csv "d:csvswitch-list.csv" -NoTypeInformation

Write-Host "The dvSwitch and dvPortGroups have been exported to CSV file and a standard vSwitch with portgroups has been created."
Write-Host "Next Step is to run script 'Step02-Move-VM-to-vSwitch' which will move all VMs to standard vSwitches and portgroups"

Step02-Move-VM-to-vSwitch:

# Migrating distributed vSwitch configurations from one vCenter to a new vCenter
# Written by: Gabrie van Zanten
# http://www.GabesVirtualWorld.com

<# 	This function has been written by Glenn Sizemore http://get-admin.com/blog/ 	Code at: http://poshcode.org/1895     .SYNOPSIS         Retrieves the virtual network adapters  available on a vSphere server.     .DESCRIPTION         A replacement for the default cmdlet will work with either a standard vSwitch or a dvSwitch.          Retrieves the virtual network adapters  available on a vSphere server.     .PARAMETER VM         Specify the virtual machines from which you want to retrieve virtual network adapters.     .EXAMPLE         Get-VM | Get-dvSwitchNetworkAdapter     .OUTPUTS         PSObject     .LINK         Set-dvSwitchNetworkAdapter #>
Function Get-dvSwitchNetworkAdapter
{
	[cmdletbinding()]
    param(
        [parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [VMware.VimAutomation.Client20.VirtualMachineImpl[]]
        $VM
    )
    process
    {
        Foreach ($VirtualMachine in (get-view -VIObject $VM -Property "Config.Hardware.Device","Network"))
        {
            $VirtualVmxnets = $VirtualMachine.Config.Hardware.Device |
                Where-Object {"VirtualEthernetCard","VirtualVmxnet" -contains $_.GetType().BaseType.Name}
            Foreach ($VirtualVmxnet in $VirtualVmxnets)
            {
                New-Object PSObject -Property @{
                    MacAddress = $VirtualVmxnet.MacAddress
                    WakeOnLanEnabled = $VirtualVmxnet.WakeOnLanEnabled
                    NetworkName = switch ($VirtualVmxnet.Backing.GetType().Name)
                        {
                            "VirtualEthernetCardNetworkBackingInfo"
                            {
                                Get-View $VirtualVmxnet.Backing.network -Property 'Name'|
                                    Select-Object -ExpandProperty 'Name'
                            }
                            Default
                            {
                              Get-view -ID $VirtualMachine.Network -Property 'Name','Key' |
                                Where-Object {$_.Key -eq $VirtualVmxnet.Backing.Port.PortgroupKey} |
                                Select-Object -ExpandProperty 'Name'
                            }
                        }
                    Type = $VirtualVmxnet.GetType().Name
                    ParentId = $VirtualMachine.MoRef.Type + "-" + $VirtualMachine.MoRef.Value
                    ConnectionState = New-Object PSObject -Property @{
                        Connected = $VirtualVmxnet.Connectable.Connected
                        StartConnected = $VirtualVmxnet.Connectable.StartConnected
                    }
                    Id = "{0}-{1}/{2}" -f $VirtualMachine.MoRef.Type,$VirtualMachine.MoRef.Value, $VirtualVmxnet.Key
                    Name = $VirtualVmxnet.DeviceInfo.Label
                }
            }
        }
    }
}

<# 	This function has been written by Glenn Sizemore http://get-admin.com/blog/ 	Code at: http://poshcode.org/1895     .SYNOPSIS          Changes the configuration of the virtual network adapter.     .DESCRIPTION         A replacement for the default cmdlet will work with either a standard vSwitch or a dvSwitch.          Changes the configuration of the virtual network adapter.     .PARAMETER NetworkAdapter         Specify the name of the network to which you want to connect the virtual network adapter.         NetworkName must be globally unique within vSphere.     .PARAMETER NetworkName         Specify the virtual network adapter you want to configure.     .PARAMETER StartConnected         If the value is $true, the virtual network adapter starts connected when its associated          virtual machine powers on. If the value is $false, it starts disconnected.  If Nothing is         Supplied than nothing will be changed.     .PARAMETER Connected         If the value is $true, the virtual network adapter is connected after its creation. If the          value is $false, it is disconnected.  If Nothing is Supplied than nothing will be changed.     .RunAsync         If supplied then the cmdlet will not wait for the completion of the network reconfiguration.           Instead a Task object will be returned and the cmdlet will process the next object in the         pipeline.     .EXAMPLE         Get-VM | Get-dvSwitchNetworkAdapter | Where-object{$_.NetworkName -eq "192.168.1.0"}| Set-dvSwitchNetworkAdapter -NetworkName "dvSwitch0_192.168.1.0"     .EXAMPLE         Get-VM | Get-dvSwitchNetworkAdapter | Set-dvSwitchNetworkAdapter -StartConnected $True     .OUTPUTS         PSObject     .LINK         Get-dvSwitchNetworkAdapter #>
Function Set-dvSwitchNetworkAdapter
{
    [cmdletbinding(SupportsShouldProcess=$true)]
    param(
        [parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSCustomObject[]]
        $NetworkAdapter
    ,
        [parameter(Mandatory = $false)]
        [string]
        $NetworkName
    ,
        [parameter()]
        [bool]
        $StartConnected
    ,
        [parameter()]
        [bool]
        $Connected
    ,
        [parameter()]
        [switch]
        $RunAsync
    )
    process
    {
        Foreach ($netAdapter in $NetworkAdapter)
        {
            $VirtualMachine = Get-View $netAdapter.ParentId -Property 'Runtime.Host','Config.Hardware.Device','Name'
            $HostSystem = Get-View -ID $VirtualMachine.Runtime.Host -Property 'Network','Name'

            $VirtualDeviceConfigSpec = New-Object VMware.Vim.VirtualDeviceConfigSpec
            $VirtualDeviceConfigSpec.operation = "edit"
            Try
            {
                $VirtualDeviceConfigSpec.device = $VirtualMachine.Config.Hardware.Device |
                    Where-Object {$_.GetType().Name -eq $netAdapter.Type -and $_.MacAddress -eq $netAdapter.MacAddress}
            }
            Catch
            {
                write-warning "$($netAdapter.Name) not found on $($VirtualMachine.name)"
                break;
            }

            $Msg = ""
            if ($NetworkName)
            {
                $Network = Get-View -Id $HostSystem.Network -Property 'Name','Config' |
                    Where-Object { $_.Name -eq $NetworkName }
                if ($Network)
                {
                    $Msg += "Connecting $($netAdapter.Name) to $($NetworkName) "
                    # Determine backing type
                    switch($Network.GetType().Name)
                    {
                        "Network"
                        {
                            $VirtualDeviceConfigSpec.device.backing = New-Object VMware.Vim.VirtualEthernetCardNetworkBackingInfo
                            $VirtualDeviceConfigSpec.device.backing.deviceName = $NetworkName
                        }
                        "DistributedVirtualPortgroup"
                        {
                            $VirtualDeviceConfigSpec.device.Backing = New-Object VMware.Vim.VirtualEthernetCardDistributedVirtualPortBackingInfo
                            $VirtualDeviceConfigSpec.device.backing.port = New-Object VMware.Vim.DistributedVirtualSwitchPortConnection
                            $VirtualDeviceConfigSpec.device.backing.port.switchUuid = (Get-View $Network.Config.DistributedVirtualSwitch).Uuid
                            $VirtualDeviceConfigSpec.device.backing.port.portgroupKey = $Network.Config.Key
                        }
                    }
                }
                Else
                {
                    Write-Warning "$($NetworkName) was not found on $($HostSystem.Name)"
                }
            }

            if ($PSCmdlet.MyInvocation.BoundParameters.Connected -ne $null)
            {
                $Msg += "Connected:$($Connected) "
                $VirtualDeviceConfigSpec.Device.Connectable.Connected = $Connected
            }
            Else {
                $VirtualDeviceConfigSpec.Device.Connectable.Connected = $netAdapter.ConnectionState.Connected
            }

            if ($PSCmdlet.MyInvocation.BoundParameters.StartConnected -ne $null)
            {
                $Msg += "StartConnected:$($StartConnected) "
                $VirtualDeviceConfigSpec.Device.Connectable.StartConnected = $StartConnected
            }
            Else
            {
                $VirtualDeviceConfigSpec.Device.Connectable.StartConnected = $netAdapter.ConnectionState.StartConnected
            }

            $VirtualMachineConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
            $VirtualMachineConfigSpec.deviceChange += $VirtualDeviceConfigSpec

            IF ($PSCmdlet.ShouldProcess($VirtualMachine.Name,$Msg))
            {
                $Task = Get-VIObjectByVIView -MORef $VirtualMachine.ReconfigVM_Task($VirtualMachineConfigSpec)

                if (-Not $RunAsync)
                {
                    Wait-Task -Task $Task | Out-Null
                    $returnNetworkAdapter = $netAdapter
                    $returnNetworkAdapter.NetworkName = $NetworkName
                    $returnNetworkAdapter.ConnectionState.StartConnected = $VirtualDeviceConfigSpec.Device.Connectable.StartConnected
                    $returnNetworkAdapter.ConnectionState.Connected = $VirtualDeviceConfigSpec.Device.Connectable.Connected
                    $returnNetworkAdapter
                }
                else
                {
                    $task
                }
            }
        }
    }
}

# Now impport the csv file with the switch info
$report = Import-Csv "d:csvswitch-list.csv"

Foreach( $row in $report)
	{
	#     Set all VMs where dvPortGroup is equal to olddvPG to new standard (temporary) tmpvPG
	Write-Host "Switching VMs from dvPortGroups to standard PortGroup: " $row.olddvPG $row.tmpvPG

	Get-VM | Get-dvSwitchNetworkAdapter | Where-object{$_.NetworkName -eq $row.olddvPG }| Set-dvSwitchNetworkAdapter -NetworkName $row.tmpvPG
	}

Write-Host "All VMs have now been moved from the dvSwitches to the standard vSwitches."
Write-Host "You can now remove this host from the old vCenter and add it to the new vCenter"
Write-Host "If the dvSwitch and dvPortGroups have not yet been created on the new vCenter,"
Write-Host "you should first run 03-Create-New-dvPG.ps1"
Write-Host "If the dvSwitch and dvPortGroups have been created on the new vCenter,"
Write-Host "run 04-Move-VMs-to-dvPG.ps1"

Step03-create-dvswitch-dvportgroup:

# Migrating distributed vSwitch configurations from one vCenter to a new vCenter
# Written by: Gabrie van Zanten
# http://www.GabesVirtualWorld.com

function New-dvSwitch{
	param($dcName, $dvSwName, $baseUplink, $nrUplink)

	$dc = Get-View -ViewType Datacenter -Filter @{"Name"=$dcName}
	$net = Get-View -Id $dc.NetworkFolder
	$spec = New-Object VMware.Vim.DVSCreateSpec
	$spec.configSpec = New-Object VMware.Vim.DVSConfigSpec
	$spec.configspec.name = $dvSwName
	$spec.configspec.uplinkPortPolicy = New-Object VMware.Vim.DVSNameArrayUplinkPortPolicy
	$spec.configspec.uplinkPortPolicy.UplinkPortName = (1..$nrUplink | % {$baseUplink + $_})

	$taskMoRef = $net.CreateDVS_Task($spec)

	$task = Get-View $taskMoRef
	while("running","queued" -contains $task.Info.State)
		{
		$task.UpdateViewData("Info")
		}
	$task.Info.Result
}

function Get-dvSwitch{
	param([parameter(Position = 0, Mandatory = $true)][string]$DatacenterName,
	[parameter(Position = 1, Mandatory = $true)][string]$dvSwitchName)

	$dcNetFolder = Get-View (Get-Datacenter $DatacenterName | Get-View).NetworkFolder
	$found = $null
	foreach($net in $dcNetFolder.ChildEntity){
		if($net.Type -eq "VmwareDistributedVirtualSwitch"){
			$temp = Get-View $net
			if($temp.Name -eq $dvSwitchName){
				$found = $temp
			}
		}
	}
	$found
}
function New-dvSwPortgroup{

	# This function was written by Luc Dekens
	# See: http://www.lucd.info/2009/10/12/dvswitch-scripting-part-2-dvportgroup/
	# As you can see, many parameters have been included in the function, but are not being used when creating the dvPortGroup
	# You can change the script to your likings, make sure the extra items you want to import are exported in Step01-Get-DistributedSwitch.ps1

	param([parameter(Position = 0, Mandatory = $true, ValueFromPipeline = $true)][VMware.Vim.VmwareDistributedVirtualSwitch]$dvSw,
	[parameter(Position = 1, Mandatory = $true)][string]$PgName,
	[int]$PgNumberPorts = 64,
	[string]$PgBinding = "earlyBinding",
	[string]$PgVLANType = "none",
	[int[]]$PgVLANId,
	[switch]$SecPolPromiciousMode = $false,
	[switch]$SecPolMacChanges = $true,
	[switch]$SecPolForgedTransmits = $true,
	[switch]$TeamingCheckDuplex = $false,
	[switch]$TeamingCheckErrorPercent = $false,
	[string]$TeamingCheckSpeed = $false,
	[switch]$TeamingFullDuplex = $true,
	[int]$TeamingPercentage,
	[int]$TeamingSpeed,
	[string]$TeamingPolicy = "loadbalance_srcid",
	[switch]$TeamingNotifySwitches = $true,
	[switch]$TeamingRollingOrder = $false,
	[switch]$TeamingReversePolicy = $true,
	[string[]]$TeamingActiveUplink,
	[string[]]$TeamingStandbyUplink
	)
	process{
		$teamingPolicies = "loadbalance_ip",
						"loadbalance_srcmac",
						"loadbalance_srcid",
						"failover_explicit",
						"loadbalance_loadbased"

		$spec = New-Object VMware.Vim.DVPortgroupConfigSpec
		$spec.Name = $PgName
		$spec.Type = $PgBinding
		$spec.numPorts = $PgNumberPorts
		$spec.defaultPortConfig = New-Object VMware.Vim.VMwareDVSPortSetting
		switch($PgVLANType.ToLower()){
			"vlan" {
				$spec.defaultPortConfig.VLAN = New-Object VMware.Vim.VmwareDistributedVirtualSwitchVlanIdSpec
				$spec.defaultPortConfig.VLAN.vlanId = $PgVLANId[0]
			}
			"vlan trunking" {
				$spec.defaultPortConfig.VLAN = New-Object VMware.Vim.VmwareDistributedVirtualSwitchTrunkVlanSpec
				$spec.defaultPortConfig.VLAN.vlanId = Get-VLANRanges $PgVLANId
			}
			"private vlan" {
				$spec.defaultPortConfig.VLAN = New-Object VMware.Vim.VmwareDistributedVirtualSwitchPvlanSpec
				$spec.defaultPortConfig.VLAN.pvlanId = $PgVLANId[0]
			}
			Default{}
		}

		$spec.defaultPortConfig.securityPolicy = New-Object VMware.Vim.DVSSecurityPolicy
		$spec.defaultPortConfig.securityPolicy.allowPromiscuous = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.securityPolicy.allowPromiscuous.Value = $SecPolPromiciousMode
		$spec.defaultPortConfig.securityPolicy.forgedTransmits = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.securityPolicy.forgedTransmits.Value = $SecPolForgedTransmits
		$spec.defaultPortConfig.securityPolicy.macChanges = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.securityPolicy.macChanges.Value = $SecPolMacChanges

		$spec.defaultPortConfig.uplinkTeamingPolicy = New-Object VMware.Vim.VmwareUplinkPortTeamingPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria = New-Object VMware.Vim.DVSFailureCriteria
		if($TeamingCheckDuplex){
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.checkDuplex = $TeamingCheckDuplex
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.fullDuplex = $TeamingFullDuplex
		}
		if($TeamingCheckErrorPercent){
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.checkErrorPercent = $TeamingCheckErrorPercent
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.percentage = $TeamingPercentage
		}
		if("exact","minimum" -contains $TeamingCheckSpeed){
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.checkSpeed = $TeamingCheckSpeed
			$spec.defaultPortConfig.uplinkTeamingPolicy.failureCriteria.speed = $TeamingSpeed
		}
		$spec.defaultPortConfig.uplinkTeamingPolicy.notifySwitches = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.notifySwitches.Value = $TeamingNotifySwitches
		if($teamingPolicies -contains $TeamingPolicy){
			$spec.defaultPortConfig.uplinkTeamingPolicy.policy = New-Object VMware.Vim.StringPolicy
			$spec.defaultPortConfig.uplinkTeamingPolicy.policy.Value = $TeamingPolicy
		}
		$spec.defaultPortConfig.uplinkTeamingPolicy.reversePolicy = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.reversePolicy.Value = $TeamingReversePolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.rollingOrder = New-Object VMware.Vim.BoolPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.rollingOrder.Value = $TeamingRollingOrder
		$spec.defaultPortConfig.uplinkTeamingPolicy.uplinkPortOrder = New-Object VMware.Vim.VMwareUplinkPortOrderPolicy
		$spec.defaultPortConfig.uplinkTeamingPolicy.uplinkPortOrder.activeUplinkPort = $TeamingActiveUplink
		$spec.defaultPortConfig.uplinkTeamingPolicy.uplinkPortOrder.standbyUplinkPort = $TeamingStandbyUplink

		$taskMoRef = $dvSw.AddDVPortgroup_Task($spec)
		$task = Get-View $taskMoRef
		while("running","queued" -contains $task.Info.State){
			$task.UpdateViewData("Info")
		}
		$task.Info.Result
	}
}

# In this step the new dvSwitches will be created on the new vCenter
$vCenterNew = Read-Host "What is the name of the new vCenter: "
$DatacenterName = Read-Host "What is the name of the datacenter: "

Disconnect-VIServer "*" -Force:$true
Connect-VIServer -Server $vCenterNew

# Reading CSV file
$report = Import-Csv "d:csvswitch-list.csv" | Select olddvSwitch -Unique

foreach( $row in $report)
	{
	Write-Host "Creating dvSwitch: " $row.olddvSwitch
	# Creating the new dvSwitch. You may want to change the baseUplink and nrUplink values to your needs
	New-dvSwitch -dcName $DatacenterName -dvSwName $row.olddvSwitch -baseUplink 1 -nrUplink 1

	}

# dvPortGroups will be created on the new vCenter
# Reading CSV file
$report = Import-Csv "d:csvswitch-list.csv"

foreach( $row in $report)
	{
	$dvSwitchFromCSV = Get-dvSwitch dc02 $row.olddvSwitch
	Write-Host "Creating dvPortGroup " $row.olddvPG " with VLANID " $row.VLANID " on dvSwitch " $row.olddvSwitch
	New-dvSwPortgroup -dvSw $dvSwitchFromCSV -PgName $row.olddvPG -PgVLANType "vlan" -PgVLANId $row.VLANID

	}

Write-Host "The new dvSwitch and dvPortGroups have been created"
Write-Host "You can now move your ESX host with running VMs from the old to the new vCenter"
Write-Host "Don't forget to add your ESX host to the newly created dvSwitch on the new vCenter !!!"
Write-Host "Next step is to switch the VMs over to the dvPortGroups. Use 'Step04-Move-VM-to-dvSwitch' for this."

Step04-Move-VM-to-dvSwitch:

# Migrating distributed vSwitch configurations from one vCenter to a new vCenter
# Written by: Gabrie van Zanten
# http://www.GabesVirtualWorld.com

<# 	This function has been written by Glenn Sizemore http://get-admin.com/blog/ 	Code at: http://poshcode.org/1895     .SYNOPSIS         Retrieves the virtual network adapters  available on a vSphere server.     .DESCRIPTION         A replacement for the default cmdlet will work with either a standard vSwitch or a dvSwitch.          Retrieves the virtual network adapters  available on a vSphere server.     .PARAMETER VM         Specify the virtual machines from which you want to retrieve virtual network adapters.     .EXAMPLE         Get-VM | Get-dvSwitchNetworkAdapter     .OUTPUTS         PSObject     .LINK         Set-dvSwitchNetworkAdapter #>
Function Get-dvSwitchNetworkAdapter
{
	[cmdletbinding()]
    param(
        [parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [VMware.VimAutomation.Client20.VirtualMachineImpl[]]
        $VM
    )
    process
    {
        Foreach ($VirtualMachine in (get-view -VIObject $VM -Property "Config.Hardware.Device","Network"))
        {
            $VirtualVmxnets = $VirtualMachine.Config.Hardware.Device |
                Where-Object {"VirtualEthernetCard","VirtualVmxnet" -contains $_.GetType().BaseType.Name}
            Foreach ($VirtualVmxnet in $VirtualVmxnets)
            {
                New-Object PSObject -Property @{
                    MacAddress = $VirtualVmxnet.MacAddress
                    WakeOnLanEnabled = $VirtualVmxnet.WakeOnLanEnabled
                    NetworkName = switch ($VirtualVmxnet.Backing.GetType().Name)
                        {
                            "VirtualEthernetCardNetworkBackingInfo"
                            {
                                Get-View $VirtualVmxnet.Backing.network -Property 'Name'|
                                    Select-Object -ExpandProperty 'Name'
                            }
                            Default
                            {
                              Get-view -ID $VirtualMachine.Network -Property 'Name','Key' |
                                Where-Object {$_.Key -eq $VirtualVmxnet.Backing.Port.PortgroupKey} |
                                Select-Object -ExpandProperty 'Name'
                            }
                        }
                    Type = $VirtualVmxnet.GetType().Name
                    ParentId = $VirtualMachine.MoRef.Type + "-" + $VirtualMachine.MoRef.Value
                    ConnectionState = New-Object PSObject -Property @{
                        Connected = $VirtualVmxnet.Connectable.Connected
                        StartConnected = $VirtualVmxnet.Connectable.StartConnected
                    }
                    Id = "{0}-{1}/{2}" -f $VirtualMachine.MoRef.Type,$VirtualMachine.MoRef.Value, $VirtualVmxnet.Key
                    Name = $VirtualVmxnet.DeviceInfo.Label
                }
            }
        }
    }
}

<# 	This function has been written by Glenn Sizemore http://get-admin.com/blog/ 	Code at: http://poshcode.org/1895     .SYNOPSIS          Changes the configuration of the virtual network adapter.     .DESCRIPTION         A replacement for the default cmdlet will work with either a standard vSwitch or a dvSwitch.          Changes the configuration of the virtual network adapter.     .PARAMETER NetworkAdapter         Specify the name of the network to which you want to connect the virtual network adapter.         NetworkName must be globally unique within vSphere.     .PARAMETER NetworkName         Specify the virtual network adapter you want to configure.     .PARAMETER StartConnected         If the value is $true, the virtual network adapter starts connected when its associated          virtual machine powers on. If the value is $false, it starts disconnected.  If Nothing is         Supplied than nothing will be changed.     .PARAMETER Connected         If the value is $true, the virtual network adapter is connected after its creation. If the          value is $false, it is disconnected.  If Nothing is Supplied than nothing will be changed.     .RunAsync         If supplied then the cmdlet will not wait for the completion of the network reconfiguration.           Instead a Task object will be returned and the cmdlet will process the next object in the         pipeline.     .EXAMPLE         Get-VM | Get-dvSwitchNetworkAdapter | Where-object{$_.NetworkName -eq "192.168.1.0"}| Set-dvSwitchNetworkAdapter -NetworkName "dvSwitch0_192.168.1.0"     .EXAMPLE         Get-VM | Get-dvSwitchNetworkAdapter | Set-dvSwitchNetworkAdapter -StartConnected $True     .OUTPUTS         PSObject     .LINK         Get-dvSwitchNetworkAdapter #>
Function Set-dvSwitchNetworkAdapter
{
    [cmdletbinding(SupportsShouldProcess=$true)]
    param(
        [parameter(Mandatory = $true, ValueFromPipeline = $true)]
        [PSCustomObject[]]
        $NetworkAdapter
    ,
        [parameter(Mandatory = $false)]
        [string]
        $NetworkName
    ,
        [parameter()]
        [bool]
        $StartConnected
    ,
        [parameter()]
        [bool]
        $Connected
    ,
        [parameter()]
        [switch]
        $RunAsync
    )
    process
    {
        Foreach ($netAdapter in $NetworkAdapter)
        {
            $VirtualMachine = Get-View $netAdapter.ParentId -Property 'Runtime.Host','Config.Hardware.Device','Name'
            $HostSystem = Get-View -ID $VirtualMachine.Runtime.Host -Property 'Network','Name'

            $VirtualDeviceConfigSpec = New-Object VMware.Vim.VirtualDeviceConfigSpec
            $VirtualDeviceConfigSpec.operation = "edit"
            Try
            {
                $VirtualDeviceConfigSpec.device = $VirtualMachine.Config.Hardware.Device |
                    Where-Object {$_.GetType().Name -eq $netAdapter.Type -and $_.MacAddress -eq $netAdapter.MacAddress}
            }
            Catch
            {
                write-warning "$($netAdapter.Name) not found on $($VirtualMachine.name)"
                break;
            }

            $Msg = ""
            if ($NetworkName)
            {
                $Network = Get-View -Id $HostSystem.Network -Property 'Name','Config' |
                    Where-Object { $_.Name -eq $NetworkName }
                if ($Network)
                {
                    $Msg += "Connecting $($netAdapter.Name) to $($NetworkName) "
                    # Determine backing type
                    switch($Network.GetType().Name)
                    {
                        "Network"
                        {
                            $VirtualDeviceConfigSpec.device.backing = New-Object VMware.Vim.VirtualEthernetCardNetworkBackingInfo
                            $VirtualDeviceConfigSpec.device.backing.deviceName = $NetworkName
                        }
                        "DistributedVirtualPortgroup"
                        {
                            $VirtualDeviceConfigSpec.device.Backing = New-Object VMware.Vim.VirtualEthernetCardDistributedVirtualPortBackingInfo
                            $VirtualDeviceConfigSpec.device.backing.port = New-Object VMware.Vim.DistributedVirtualSwitchPortConnection
                            $VirtualDeviceConfigSpec.device.backing.port.switchUuid = (Get-View $Network.Config.DistributedVirtualSwitch).Uuid
                            $VirtualDeviceConfigSpec.device.backing.port.portgroupKey = $Network.Config.Key
                        }
                    }
                }
                Else
                {
                    Write-Warning "$($NetworkName) was not found on $($HostSystem.Name)"
                }
            }

            if ($PSCmdlet.MyInvocation.BoundParameters.Connected -ne $null)
            {
                $Msg += "Connected:$($Connected) "
                $VirtualDeviceConfigSpec.Device.Connectable.Connected = $Connected
            }
            Else {
                $VirtualDeviceConfigSpec.Device.Connectable.Connected = $netAdapter.ConnectionState.Connected
            }

            if ($PSCmdlet.MyInvocation.BoundParameters.StartConnected -ne $null)
            {
                $Msg += "StartConnected:$($StartConnected) "
                $VirtualDeviceConfigSpec.Device.Connectable.StartConnected = $StartConnected
            }
            Else
            {
                $VirtualDeviceConfigSpec.Device.Connectable.StartConnected = $netAdapter.ConnectionState.StartConnected
            }

            $VirtualMachineConfigSpec = New-Object VMware.Vim.VirtualMachineConfigSpec
            $VirtualMachineConfigSpec.deviceChange += $VirtualDeviceConfigSpec

            IF ($PSCmdlet.ShouldProcess($VirtualMachine.Name,$Msg))
            {
                $Task = Get-VIObjectByVIView -MORef $VirtualMachine.ReconfigVM_Task($VirtualMachineConfigSpec)

                if (-Not $RunAsync)
                {
                    Wait-Task -Task $Task | Out-Null
                    $returnNetworkAdapter = $netAdapter
                    $returnNetworkAdapter.NetworkName = $NetworkName
                    $returnNetworkAdapter.ConnectionState.StartConnected = $VirtualDeviceConfigSpec.Device.Connectable.StartConnected
                    $returnNetworkAdapter.ConnectionState.Connected = $VirtualDeviceConfigSpec.Device.Connectable.Connected
                    $returnNetworkAdapter
                }
                else
                {
                    $task
                }
            }
        }
    }
}

# Now impport the csv file with the switch info
$report = Import-Csv "d:csvswitch-list.csv"

Foreach( $row in $report)
	{
	#     Set all VMs where dvPortGroup is equal to tmpvPG to it's original portgroup olddvPG
	Write-Host "Switching VMs from temporary PortGroup " $row.tmpvPG " to dvPortGroup " $row.olddvPG 

	Get-VM | Get-dvSwitchNetworkAdapter | Where-object{$_.NetworkName -eq $row.tmpvPG }| Set-dvSwitchNetworkAdapter -NetworkName $row.olddvPG
	}

Write-Host "All VMs have now been moved from the dvSwitches to the standard vSwitches."

See full post at: Migrating distributed vSwitch to new vCenter