Learning PowerCLI

Well, well, well… we meet again, Blog. I really need to get better at this whole “actually use your blog” thing. That’s for another day. Let’s get to the meat of it! Lots of words incoming.

I’ve been playing with PowerCLI (and by extension, Powershell) a lot more often as of late. I’ve struggled with identifying how to learn easier. I’m getting there! I’m not the best at crafting scripts yet, but I’m getting better at figuring out what I’m actually trying to accomplish.

I might just be mashing scripts together that I’ve collected from the Internet. That said, I feel like I’ve learned a lot over the last few days.

Here’s the use-case:
ESXi hosts to be moved from vCenter 5.5 and added to vCenter 6.5
Heavily segmented network with hundreds of VLANs
Multiple Distributed Switches
Officially supported move is to migrate to Standard Switch, remove ESXi host from one vCenter, add ESXi host to new vCenter, and create a new Distributed switch with the necessary port groups.

Perfect use-case for PowerCLI, right?! Without it, I’d be repeating the same actions again and again on several different hosts in the inventory, right? Time to do some learning. Except…

I didn’t really know where to get started. I did a quick search online and found this post by Mark Jones (toss him a follow on Twitter!). The post gave me a starting point and a way to expand to meet my own use-case. In Mark’s post, he does a lot more than I’m comfortable doing. I also blatantly stole (read: reused) the section of setting VM network adapters to the Standard Switch.

I modified his script and wrote the following to take the many different distributed port groups and turn them into standard port groups. The script assumes that there is already a physical adapter associated with both the standard switch and the distributed switch. Shout out to my coworker Marty (Twitter) for helping me pull in the VLAN ID and solve some errors as I was working on this. Honestly, it feels like Marty wrote more of this than me. I’m fine with it…

[code language=”powershell”]

# Request input items
$vDS = Read-Host "Which Distributed Switch would you like to copy Port Groups from?"

$VMHost = Read-Host "Which host would you like to copy the Distributed Port Groups to?"
$vSwitchName = Read-Host "Which Standard Switch on that host would you like the new Port Groups on? (Please ensure that the selected switch will support virtual machine connectivity!)"
# Create some variables
$dPG = Get-VDSwitch $vDS | Get-VDPortGroup
$vSwitch = Get-VMHost $VMHost | Get-VirtualSwitch -name $vSwitchName
$vmlist = Get-VMHost $VMHost | Get-VM

# Creates a new portgroup on the specified vSwitch and includes VLAN ID.
# Note: Trunk ports do not come over properly. Trunk ports that are listed include the Uplinks.
Write-Host "This script does not yet handle Trunk port groups properly."
foreach ($pg in $dpg){
Write-Host "Creating Port Group " $pg " with VLAN ID " $pg.vlanconfiguration.vlanid on $vSwitchName -ForegroundColor Green
New-VirtualPortGroup -VirtualSwitch $vSwitch -name $pg.Name -vlan $pg.vlanconfiguration.vlanid

Write-Host "Pausing for five seconds. Gather your thoughts!" -ForegroundColor Green
Start-Sleep -seconds 5

foreach ($vm in $vmlist){
Get-NetworkAdapter $vm | % {
Write-Host "Changing the network adapter of" $vm "to" $_.NetworkName "on the Virtual Standard Switch." -ForegroundColor Green
$_ | Set-NetworkAdapter -PortGroup (Get-VirtualPortGroup -VMHost $VMHost -Standard -Name $_.NetworkName) -Confirm:$false
# Removes newly created portgroups from test host
# Get-VMhost $vmhost | Get-VirtualSwitch -name $vSwitchName | Get-VirtualPortGroup | ? {$_.Name -ne "Management Network" -AND $_.Name -ne "iSCSI" -AND $_.Name -ne "vMotion"} | Remove-VirtualPortGroup -Confirm:$false
It worked! It was very exciting to me, as one of the first pieces of usable code I’ve written, to see this complete successfully. I’ll revisit the Trunk ports, but I don’t currently have any that would require my attention. On to the next piece…


I needed to figure out how to go back to a vDS once it’s in my new vCenter. I borrowed some other bits and pieces from the Internet, but I think they came together nicely. This script does much more and likely gets too complicated for what it does. Here’s what I came up with:

[code language=”powershell”]

# Create menu for the selection of the Virtual Switch
function Select-Switch
param (
[string]$title = ‘Which Virtual Standard Switch would you like to copy port groups from?’
Write-Host "$title"

Write-Host "1:" $vSwitch[0]
Write-Host "2:" $vSwitch[1]
Write-Host "3:" $vSwitch[2]
Write-Host "Q: Press to quit."

# Allow script runner to identify the host to run the script against.
$VMHost = Read-Host "Which host would you like to copy Port Groups from?"
# Populate the Select-Switch menu by getting the virtual switches on the host.
$vSwitch = Get-VMHost $VMHost | Get-VirtualSwitch

# Ask script runner for the name of the distributed switch to add port groups to. If the switch
# doesn’t exist, create the switch and create distributed port groups based on the user’s selection
# of the standard switch found on the host.
$dVS = Read-Host "What is the name of the Distributed Switch you like to copy Port Groups to?"
If ((Get-VDSwitch -name $dVS -Erroraction SilentlyContinue) -eq $null) {
New-VDSwitch -Name $dVS -Version (Get-VMHost $VMHost).Version -Location (Get-Datacenter)

$input = Read-Host "Please select one of the following:"
switch ($input)
$vSwitchName = $vSwitch[0]
} ‘2’{
$vSwitchName = $vSwitch[1]
} ‘3’{
$vSwitchName = $vSwitch[2]
} ‘Q'{
Until ($input -ne $null)
$vSSPG = Get-VMhost $VMHost | Get-VirtualSwitch -name $vSwitchName | Get-VirtualPortGroup
$vmlist = Get-VMHost $VMHost | Get-VM

Write-Host "This script does not yet handle Trunk port groups properly." -ForegroundColor Green
foreach ($pg in $vSSPG){
Write-Host "Creating Port Group" $pg "with VLAN ID" $pg.vlanId on $dVS -ForegroundColor Green
New-VDPortGroup -VDSwitch $dVS -Name $pg.Name -vlanid $pg.vlanid
Write-Host "Port Groups have been created. You must manually add an Uplink from" $VMHost to $vDS "before continuing.
Please do so now. This script will now sleep for 30 seconds before it can continue." -ForegroundColor Green
Start-Sleep -seconds 30

# If the distributed switch already exists, there should be no port groups on the host to add to the distributed switch.
elseif((Get-VDSwitch -name $dVS) -ne $null){
Write-Host "Great news! The distributed switch" $dVS "already exists! We can skip Port Group creation and move forward." -ForegroundColor Green

# Require user input before continuing with the script.
Write-Host "The next section of this script will migrate Virtual Machines from the Standard Switch to the Distributed Switch.
Press any key to continue." -ForegroundColor Green

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp")

# Require additional input to ensure that user has added an uplink to the distributed switch.
Write-Host "Press any key to continue." -ForegroundColor Cyan

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp")

# Migrate virtual machine network adapters from standard switch port group to distributed switch port group.
$vmlist = Get-VMHost $VMHost | Get-VM
foreach ($vm in $vmlist){
Get-NetworkAdapter $vm | % {
Write-Host "Changing the network adapter of" $vm "to" $_.NetworkName "on the Virtual Standard Switch." -ForegroundColor Green
$_ | Set-NetworkAdapter -PortGroup (Get-VDPortGroup -VDSwitch $dVS -Name $_.NetworkName) -Confirm:$false
Write-Host "Virtual machines have had their network’s updated to use the Distributed Switch. Pausing for another 30 seconds." -ForegroundColor Green
Start-Sleep -seconds 30

# Require user input before continuing with the script.
Write-Host "The last section of the script will remove all Standard Switch port groups EXCEPT Management Network, iSCSI, and vMotion. Press any key to continue." -ForegroundColor Green

$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyUp")

# Removes newly created portgroups from test host
Get-VMhost $vmhost | Get-VirtualSwitch -name $vSwitchName | Get-VirtualPortGroup | ? {$_.Name -ne "Management Network" -AND $_.Name -ne "iSCSI" -AND $_.Name -ne "vMotion"} | Remove-VirtualPortGroup -Confirm:$false

Write-Host "Well done! Take a break, you deserve it." -ForegroundColor Green


In this script, a menu is created (which is stolen from here) to call later in the script. The user is asked for inputs of ESXi host and name of vDS they want to move vSS port groups to. An “if” statement checks to see whether the vDS exists or not.

If the vDS DOESN’T exist, it creates a new vDS (which, for me, needs to be the same version as the ESXi host as specified by -Version). Next, it runs the menu to determine which Standard Switch to copy port groups from. If the distributed switch DOES exist, it skips port group creation altogether.

Once the vDS and port groups are created, the script pauses and prompts the user to add an uplink to the vDS before continuing. I purposely wanted this process to be manual! The script pauses for 30 seconds and requires the user to press a key to continue (check here for info). Twice!

Next, it swings VM network adapters from vSS port groups to the vDS port groups (reusing and reworking a bit of code from the last script). Once complete, the script requires user input again before removing vSS port groups.

I’m able to run both of these scripts in a test environment. I can go back and forth from vSS to vDS and from vDS to vSS with relative ease. There’s probably some cleanup to do. More likely is that there are different and better ways to accomplish these tasks, too. I’m happy to hear them. Share your thoughts with me!

Leave a Reply