PowerCLI: Easy vSwitch & PortGroup Setup

To get VMotion working the networking setup plays a big part, any of the following could cause you big issues:

  • A spelling mistake in a PortGroup name
  • A missing PortGroup
  • A PortGroup configured incorrectly
  • A non-existing PortGroup on one of your hosts
  • etc

This is why automation and PowerCLI is key to the setup of your vSwitches and PortGroup’s, you could add each vSwitch manually and then create a PortGroup for each VLAN you have trunked to your hosts manually but what are the chances you will miss one, what are the chances you will get the VLAN ID incorrect ?  And you sure do get bored of the wizard when you have 4 vSwitches and around 20 PortGroups !

The following code will take you through copying all vSwitches and PortGroups from an existing ESX server over to a new server, ensuring they are exactly the same.  It sure does save me time !

$VISRV = Connect-VIServer (Read-Host "Please enter the name of your VI SERVER")
$BASEHost = Get-VMHost -Name (Read-Host "Please enter the name of your existing server as seen in the VI Client:")
$NEWHost = Get-VMHost -Name (Read-Host "Please enter the name of the server to configure as seen in the VI Client:")

$BASEHost |Get-VirtualSwitch |Foreach {
   If (($NEWHost |Get-VirtualSwitch -Name $_.Name-ErrorAction SilentlyContinue)-eq $null){
       Write-Host "Creating Virtual Switch $($_.Name)"
       $NewSwitch = $NEWHost |New-VirtualSwitch -Name $_.Name-NumPorts $_.NumPorts-Mtu $_.Mtu
       $vSwitch = $_
    }
   $_ |Get-VirtualPortGroup |Foreach {
       If (($NEWHost |Get-VirtualPortGroup -Name $_.Name-ErrorAction SilentlyContinue)-eq $null){
           Write-Host "Creating Portgroup $($_.Name)"
           $NewPortGroup = $NEWHost |Get-VirtualSwitch -Name $vSwitch |New-VirtualPortGroup -Name $_.Name-VLanId $_.VLanID
        }
    }
}

32 thoughts on “PowerCLI: Easy vSwitch & PortGroup Setup”

    1. Wow, long time since I have looked at this. We use almost exclusively distributed switches now, so this is not much used.

      Sunny, will you post the version of the script you are using and then clarify what your question is? Do you mean hostname of the vCenter or when looking at ESX hosts?

  1. Hi,
    We made a few changes to the script to replicate the configuration on several esx…

    clear

    #Servers array for [2] choice
    $servers = “esx11”, “esx12”, “esx13”, “esx14”, “esx15”, “esx16”, “esx21”, “esx22”, “esx23”, “esx24”, “esx25”, “esx26”

    write-host “”
    write-host “vSwitch Configuration Duplicator”
    write-host “”
    write-host “Menu :”
    write-host “[1] : From one server to another one”
    write-host “[2] : From one server to all others”
    write-host “[q] : Quit”

    $choix = Read-Host “Choice ?”
    if (“$choix” -eq “1”)
    {
    $srvconnection = Connect-VIServer (Read-Host “Please enter the name of your VI SERVER”)
    $sourceHost = Get-VMHost -Name (Read-Host “Please enter the name of your existing server as seen in the VI Client:”)
    $targetHost = Get-VMHost -Name (Read-Host “Please enter the name of the server to configure as seen in the VI Client:”)

    #Collecting source information
    $sourceHostObj = Get-VMHost -Name $sourceHost -Server $srvconnection
    write-host “Exporting vSwithes configurations from $sourceHost”
    $sourcevSwitches = $sourceHostObj | Get-VirtualSwitch
    write-host “Exporting Port Group configurations from $targetHost”
    $sourcevPGs = $sourceHostObj | Get-VirtualPortGroup

    #Collecting target host information
    $targethostObj = Get-VMHost -Name $targetHost -Server $srvconnection
    write-host “Exporting vSwithes configurations of target $targetHost”
    $targetvSwitches = $targetHostObj | Get-VirtualSwitch
    write-host “Exporting Port Group configurations of target $targetHost”
    $targetvPGs = $targetHostObj | Get-VirtualPortGroup

    # determine the difference
    $differencevSwitches = Compare-Object $sourcevSwitches $targetvSwitches
    $differencevPGs = Compare-Object $sourcevPGs $targetvPGs

    # Only process the difference in vSwitches
    if (“$differencevSwitches” -ne “”)
    {
    $differencevSwitches | %{
    $newvSwitch = $_.InputObject
    Write-Host “Creating Virtual Switch $($newvSwitch.Name) on $targetHost”
    if($newvSwitch.Nic) {
    $outputvSwitch = $targethostObj | New-VirtualSwitch -Name $newvSwitch.Name -NumPorts $newvSwitch.NumPorts -Mtu $newvSwitch.Mtu -Nic $newvSwitch.Nic
    } else {
    $outputvSwitch = $targethostObj | New-VirtualSwitch -Name $newvSwitch.Name -NumPorts $newvSwitch.NumPorts -Mtu $newvSwitch.Mtu
    }
    }
    }
    else
    {
    write-host “No Change”
    }
    # Only Process difference in Port Groups
    if (“$differencevPGs” -ne “”)
    {
    $differencevPGs | %{
    $newvPG = $_.InputObject
    Write-Host “Creating Port group “”$($newvPG.Name)”” on vSwitch “”$($newvPG.VirtualSwitchName)”” on target host $targetHost”
    $outputvPG = $targethostObj | Get-VirtualSwitch -Name $newvPG.VirtualSwitchName | New-VirtualPortGroup -Name $newvPG.Name-VLanId $newvPG.VLanID
    }
    }
    else
    {
    write-host “No Change”
    }
    }
    elseif (“$choix” -eq “2”)
    {
    $srvconnection = Connect-VIServer (Read-Host “Please enter the name of your VI SERVER”)
    $sourceHost = Get-VMHost -Name (Read-Host “Please enter the name of your existing server as seen in the VI Client:”)
    # $targetHost = Get-VMHost -Name (Read-Host “Please enter the name of the server to configure as seen in the VI Client:”)
    foreach ($tree in $servers)
    {
    if (“$tree” -ne “$sourceHost”)
    {
    write-host “”
    write-host “WORKING ON : $tree”
    write-host “”
    #Collecting source information
    $sourceHostObj = Get-VMHost -Name $sourceHost -Server $srvconnection
    write-host “Exporting vSwithes configurations from $sourceHost”
    $sourcevSwitches = $sourceHostObj | Get-VirtualSwitch
    write-host “Exporting Port Group configurations from $targetHost”
    $sourcevPGs = $sourceHostObj | Get-VirtualPortGroup

    #Collecting target host information
    $targethostObj = Get-VMHost -Name $tree -Server $srvconnection
    write-host “Exporting vSwithes configurations of target $targetHost”
    $targetvSwitches = $targetHostObj | Get-VirtualSwitch
    write-host “Exporting Port Group configurations of target $targetHost”
    $targetvPGs = $targetHostObj | Get-VirtualPortGroup

    # determine the difference
    $differencevSwitches = Compare-Object $sourcevSwitches $targetvSwitches
    $differencevPGs = Compare-Object $sourcevPGs $targetvPGs

    # Only process the difference in vSwitches
    if (“$differencevSwitches” -ne “”)
    {
    $differencevSwitches | %{
    $newvSwitch = $_.InputObject
    Write-Host “Creating Virtual Switch $($newvSwitch.Name) on $targetHost”
    if($newvSwitch.Nic) {
    $outputvSwitch = $targethostObj | New-VirtualSwitch -Name $newvSwitch.Name -NumPorts $newvSwitch.NumPorts -Mtu $newvSwitch.Mtu -Nic $newvSwitch.Nic
    } else {
    $outputvSwitch = $targethostObj | New-VirtualSwitch -Name $newvSwitch.Name -NumPorts $newvSwitch.NumPorts -Mtu $newvSwitch.Mtu
    }
    }
    }
    else
    {
    write-host “No Change”
    }
    # Only Process difference in Port Groups
    if (“$differencevPGs” -ne “”)
    {
    $differencevPGs | %{
    $newvPG = $_.InputObject
    Write-Host “Creating Port group “”$($newvPG.Name)”” on vSwitch “”$($newvPG.VirtualSwitchName)”” on target host $targetHost”
    $outputvPG = $targethostObj | Get-VirtualSwitch -Name $newvPG.VirtualSwitchName | New-VirtualPortGroup -Name $newvPG.Name-VLanId $newvPG.VLanID
    }
    }
    else
    {
    write-host “No Change”
    }

    }
    }
    }
    elseif (“$choix” -eq “q”)
    {
    exit
    }
    else
    {
    write-host “Wrong Choice !”
    }

  2. Hi, i am completely new to powercli so forgive my newbee questions. I run the originally posted script and i get an error at line 13 on every one of the port groups it tries to create. Here is the error message:

    Creating Portgroup 10.110.12
    14
    Get-VirtualSwitch : Cannot validate argument on parameter ‘Name’. The argument is null or empty. Provide an argument that is not null or empty, and then try the command
    again.
    At C:\Users\tmhiaf.TMH\AppData\Local\Temp\c3b7ef92-0377-479b-b61a-8dfa48f65078.ps1:28 char:62
    + $NewPortGroup = $NEWHost |Get-VirtualSwitch -Name $vSwitch |New-Virtu …
    + ~~~~~~~~
    + CategoryInfo : InvalidData: (:) [Get-VirtualSwitch], ParameterBindingValidationException
    + FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutomation.ViCore.Cmdlets.Commands.Host.GetVirtualSwitch

    I thnk that it is attempting to pull the name of the portgroup from the reference host but i just dont understand why the error. It seems to start to create the PG but then right at line 14 it craps out….

    Please advise….
    Thanks

  3. Moved:
          $vSwitch= $_

    Between line 5 and 6. Otherwise it would fail if the vSwitch already existed.

  4. # Thank you for the script, I have modified it slighlty to make use of the Comparative
    # function of powershell. I hope it helps

    $srvconnection = get-vc “vcenterserver”
    $sourceHost = “hostname.fqdn”
    $targetHost = “hostname.fqdn”

    #Collecting source information
    $sourceHostObj = Get-VMHost -Name $sourceHost -Server $srvconnection
    write-host “Exporting vSwithes configurations from $sourceHost”
    $sourcevSwitches = $sourceHostObj | Get-VirtualSwitch
    write-host “Exporting Port Group configurations from $targetHost”
    $sourcevPGs = $sourceHostObj | Get-VirtualPortGroup

    #Collecting target host information
    $targethostObj = Get-VMHost -Name $targetHost -Server $srvconnection
    write-host “Exporting vSwithes configurations of target $targetHost”
    $targetvSwitches = $targetHostObj | Get-VirtualSwitch
    write-host “Exporting Port Group configurations of target $targetHost”
    $targetvPGs = $targetHostObj | Get-VirtualPortGroup

    # determine the difference
    $differencevSwitches = Compare-Object $sourcevSwitches $targetvSwitches
    $differencevPGs = Compare-Object $sourcevPGs $targetvPGs

    # Only process the difference in vSwitches
    $differencevSwitches | %{
    $newvSwitch = $_.InputObject
    Write-Host “Creating Virtual Switch $($newvSwitch.Name) on $targetHost”
    if($newvSwitch.Nic) {
    $outputvSwitch = $targethostObj | New-VirtualSwitch -Name $newvSwitch.Name -NumPorts $newvSwitch.NumPorts -Mtu $newvSwitch.Mtu -Nic $newvSwitch.Nic
    } else {
    $outputvSwitch = $targethostObj | New-VirtualSwitch -Name $newvSwitch.Name -NumPorts $newvSwitch.NumPorts -Mtu $newvSwitch.Mtu
    }
    }

    # Only Process difference in Port Groups
    $differencevPGs | %{
    $newvPG = $_.InputObject
    Write-Host “Creating Port group “”$($newvPG.Name)”” on vSwitch “”$($newvPG.VirtualSwitchName)”” on target host $targetHost”
    $outputvPG = $targethostObj | Get-VirtualSwitch -Name $newvPG.VirtualSwitchName | New-VirtualPortGroup -Name $newvPG.Name-VLanId $newvPG.VLanID
    }

  5. Hi all,
    I have to modified Mike’s script.

    $VISRV = Read-Host “Please enter the name of your VI SERVER”

    #connect to vcenter before continue asking for esx host.
    Connect-VIServer -server $VISRV -Protocol http

    $BASEHost = Get-VMHost -Name (Read-Host “Please enter the name of your existing server as seen in the VI Client:”)
    $NEWHost = Get-VMHost -Name (Read-Host “Please enter the name of the server to configure as seen in the VI Client:”)

    In other case I always have got:

    Get-VMHost : 21/02/2013 14:14:20 Get-VMHost You are not currently con
    nected to any servers. Please connect first using a Connect cmdlet.
    At C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\netscript.ps1:
    17 char:23
    + $BASEHost = Get-VMHost <<<< -Name (Read-Host "Please enter the name of your
    existing server as seen in the VI Client:")
    + CategoryInfo : ResourceUnavailable: (:) [Get-VMHost], ViServerC
    onnectionException
    + FullyQualifiedErrorId : Core_BaseCmdlet_NotConnectedError,VMware.VimAuto
    mation.ViCore.Cmdlets.Commands.GetVMHost

  6. Guys,

    I’ve used this script to add porgroups to vSwitchs 1 Cluster at a time.

    Connect-VIServer -username Domain\UserID -password
    Foreach ($esxhost in (Get-Cluster -name “Actual Cluster Name Here” | Get-VMHost))
    {
    $vswitch = Get-VirtualSwitch -VMHost $esxhost -Name “vSwitch1”
    $portgroup = New-VirtualPortGroup -VirtualSwitch $vswitch -Name “PortGroupName” -VLanId 4095 #4095 allows all vLANs.
    }

  7. Hi Mike,

    I’m using your version of the script. It’s working really well for me and I’ve made my own additions for our environment. The only piece I can’t get to work is the vmkernel creation (I had to remove this piece to test the rest).

    If I don’t modify the script, I get this error:
    [vSphere PowerCLI] > .\copyportgroups_tmp.ps1
    Unexpected token ‘What’ in expression or statement.
    At D:\copyportgroups_tmp.ps1:39 char:28
    + $MotionIP = Read-Host “What <<< .\copyportgroups_tmp.ps1 Unexpected token 'Creating' in expression or statement. At D:\copyportgroups_tmp.ps1:43 char:21 + Write-Host "Creating <<<< $($vmk) on $($NewHost)." + CategoryInfo : ParserError: (Creating:String) [], ParseException + FullyQualifiedErrorId : UnexpectedToken Thanks for the help.

  8. Thanks Mike

    script did prompt me for VI server and source/destination and it generate this error after accepting the infomation. I will try again as you mentioned. thanks heaps
    Ajay

  9. Hi Ajay.

    That has nothing to do with ESXi or ESX. That command is trying to connect to your vCenter server.

    In the command:

    $VISRV = Connect-VIServer # or ask (Read-Host “Please enter the name of your VI SERVER”)

    the “#” is a commentor, meaning everything after that is ignored. So, put the FQDN of your vCenter server just before the “#” or remove the “# or ask” part and it will ask when you run the script.

    Hope that helps…

    Mike

  10. Hi Guys

    I am trying this script from 1 esxi to another esxi and both are 4.0 U2 and geting this error!! help if you guys can
    Connect-VIServer : A positional parameter cannot be found that accepts argument
    ‘$null’.
    At line:1 char:26

  11. I have worked more on “my” version of the script. It now looks at one host and configures another host to have the same vSwitches with portgroups and VLANs. It does ESXi and vmk interfaces and will ask you which of the vSwitches on the existing host you want to “copy” to the new host. This was helpful for me where I was occasionally changing a host from one cluster to another and I wanted to leave one vSwitch alone (this might be specific to my environment). My vMotion vmk interfaces are always on vSwitch0, thus the part where I ask what the vMotion IP is if the current vSwitch is vSwithc0. Sorry about that, but that’s the way it works for me.

    Use this in a testing area first, or use it for ideas. Full credit to Al as this is still mainly his work that I merely tweaked. I am NOT a programmer and someone will likely hate the way I do things. No worries.

    function AskEm {
    $caption = “Select:”;
    $message = “Add item $element to the new list?”;
    $yes = new-Object System.Management.Automation.Host.ChoiceDescription “&Yes”,”help”;
    $no = new-Object System.Management.Automation.Host.ChoiceDescription “&No”,”help”;
    $choices = [System.Management.Automation.Host.ChoiceDescription[]]($yes,$no);
    $answer = $host.ui.PromptForChoice($caption,$message,$choices,0)
    switch ($answer){
    0 {$Global:NewList += @($element)}
    1 {continue}
    }
    }
    # initialize a variable
    $Global:NewList = $null

    $VISRV = Connect-VIServer # or ask (Read-Host “Please enter the name of your VI SERVER”)
    $BASEHost = Get-VMHost -Name (Read-Host “Please enter the name of your existing server as seen in the VI Client:”)
    $NEWHost = Get-VMHost -Name (Read-Host “Please enter the name of the server to configure as seen in the VI Client:”)

    # get the switches for the base host
    $MySwitches = $BASEHost |Get-VirtualSwitch

    # ask the user to select what switches to look at and copy
    foreach ($element in $MySwitches) {
    Askem
    }

    #go thru each switch selected above
    foreach ($switch in $NewList) {
    # check to see if the switch already exists on the new host – if so don’t create it.
    If (($NEWHost |Get-VirtualSwitch -Name $switch.Name -ErrorAction SilentlyContinue)-eq $null){
    # if not, create it…
    Write-Host “Creating Virtual Switch $($switch.Name) on $($NEWHost).”
    $NewSwitch = $NEWHost |New-VirtualSwitch -Name $switch.Name -NumPorts $switch.NumPorts -Mtu $switch.Mtu
    }
    Else {Write-Host “Vswitch $($switch.name) already exists on $($NEWHost). Checking port groups on this switch.”}

    If ($switch.Name -eq “vSwitch0”) {
    $MotionIP = Read-Host “What is the IP for the VMotion Network?”
    $MyVMKs = $BASEHost | Get-VMHostNetworkAdapter -VMKernel
    foreach ($vmk in $MyVMKs) {
    if (($NEWHost | Get-VMHostNetworkAdapter -VMKernel).devicename -ne $vmk.DeviceName) {
    Write-Host “Creating $($vmk) on $($NewHost).”
    $vmkpg = Get-VirtualPortGroup -Name $vmk.portgroupname -VMHost $BASEhost
    if ($vmk.PortGroupName -eq “VMkernel-VMotion”) {
    $NewVMK = $NEWHost | New-VMHostNetworkAdapter -PortGroup $vmk.portgroupname -SubnetMask $vmk.subnetmask -VMotionEnabled $vmk.vmotionenabled -VirtualSwitch $vmkpg.virtualswitchname -IP $MotionIP}
    else {$NewVMK = $NEWHost | New-VMHostNetworkAdapter -PortGroup $vmk.portgroupname -SubnetMask $vmk.subnetmask -VMotionEnabled $vmk.vmotionenabled -VirtualSwitch $vmkpg.virtualswitchname}
    get-virtualportgroup -VMHost $NEWHost -Name $vmk.portgroupname | Set-VirtualPortGroup -VLanId $vmkpg.vlanid
    }
    }
    }
    Else {
    $MyPGs = $switch | Get-VirtualPortGroup
    foreach ($Pg in $MyPGs) {
    If (($NEWHost |Get-VirtualPortGroup -Name $PG.Name-ErrorAction SilentlyContinue)-eq $null){
    Write-Host “Creating Portgroup $($PG.Name) on $($switch)”
    $NewPortGroup = $NEWHost |Get-VirtualSwitch -Name $switch |New-VirtualPortGroup -Name $PG.Name -VLanId $PG.VLanID
    }
    }
    }

    }

    Hope this helps…

  12. I used it just the other day against an ESXi 4 host, but not without some issues. I was using a version I am sorta working on that tries to create the vswitches, add portgroups and VMkernel ports and adds vnics to the vswitches. It does this by looking at an existing host and making the new host just like the old one. Still not much of my work – mainly Al’s.

    The part ESXi didn’t seem to like was the fact that the VMkernel ports are vmk0, vmk1, etc. instead of looking a bit like ESX portgroups. Still things to look at in “my” version before it is ready to use in Production.

  13. My only real change was to use a variable in place of $_ in the foreach loops. For some reason, it didn’t seem to get the scope of $_ without assigning it to a variable first and then using the variable ($switch or &myPG in my version).

    I learned a lot from looking at your script and tweaking it, Al (even if the tweaks turn out to have been unnecessary). Thanks!

  14. Hmm.. not sure M@rcel. Double-check the way this gets pasted in to PowerCLI perhaps. Watch that line breaks don’t get put in where they shouldn’t be.

    Perhaps copy “my” version of the script and paste into notepad or some other text editor and watch for the line breaks. Have you tried to use PowerGUI and its Script Editor at all?

    Mike

  15. Hi Al/Mike,

    I’m not very experienced with the PowerCLI, but am very interested in automating the creation of vSwitches and PortGroups. We are using ESX4.
    I tried pasting Mike’s script in the PowerCLI, but keep getting this error:

    Get-VirtualPortGroup : 28-1-2010 17:02:38 Get-VirtualPortGroup
    Could not find VirtualSwitch with name ‘vSwitch0’.
    At line:8 char:33
    + $BASEHost | Get-VirtualPortGroup <<<< -VirtualSwitch $switch | Foreach {
    + CategoryInfo : ObjectNotFound: (vSwitch0:String) [Get-VirtualPortGroup], VimException
    + FullyQualifiedErrorId : Core_ObnSelector_SelectObjectByNameCore_ObjectNotFound,VMware.VimAutomation.Commands.GetVirtualPortGroup

    I even do not get the questions for vCenter server, source and destination server. I'm running the PowerCLI with my vmWare admin account (not root)

    Any suggestions?

  16. I had to modify the script a tiny bit (sounds like the above comment #1) to get it to work against ESX 4, but below is my version (with all thanks to Al!). I did get this to work for my vSphere hosts.

    $VISRV = Connect-VIServer (Read-Host “Please enter the name of your VI SERVER”)
    $BASEHost = Get-VMHost -Name (Read-Host “Please enter the name of your existing server as seen in the VI Client:”)
    $NEWHost = Get-VMHost -Name (Read-Host “Please enter the name of the server to configure as seen in the VI Client:”)

    $BASEHost |Get-VirtualSwitch |Foreach {
    $switch = $_.Name
    If (($NEWHost |Get-VirtualSwitch -Name $switch -ErrorAction SilentlyContinue)-eq $null){
    Write-Host “Creating Virtual Switch $($_.Name)”
    $NewSwitch = $NEWHost |New-VirtualSwitch -Name $_.Name-NumPorts $_.NumPorts-Mtu $_.Mtu
    #$vSwitch = $_
    }
    $BASEHost | Get-VirtualPortGroup -VirtualSwitch $switch | Foreach {
    $myPG = $_.name
    If (($NEWHost |Get-VirtualPortGroup -Name $myPG -ErrorAction SilentlyContinue)-eq $null){
    Write-Host “Creating Portgroup $($_.Name)”
    $NewPortGroup = $NEWHost |Get-VirtualSwitch -Name $vSwitch |New-VirtualPortGroup -Name $_.Name-VLanId $_.VLanID
    }
    }
    }

  17. Has anyone (else) tried this on ESX4? I keep getting this error
    “The argument cannot be null or empty.
    At :line:30 char:60
    + $NewPortGroup = $NEWHost |Get-VirtualSwitch -Name <<<< $vSwitch |New-VirtualPortGroup -Name $_.Name-VLanId $_.VLanID"

    Line 30 equates to "$NewPortGroup = $NEWHost……." on my script.

Leave a Reply