On the PowerCLI Community there was an interesting question about dvSwitches, portgroups and connecting VMs. Turns out you will need to provide a free port to connect a VM’s NIC to a portgroup on dvSwitch.
Since the solution is a nice follow up on my previous, somewhat lengthy post, called Variations on a port, I decided to create a short post on the subject in my dvSwitch series.
Update 3th March 2016: added test to capture portgroups with no VM connected to it
To connect a VM’s NIC to a dvSwitch portgroup you can use the Set-NetworkAdapter cmdlet like this.
1 2 |
Get-vm $vmname | Get-NetworkAdapter | Set-NetworkAdapter -DistributedSwitch dvSwitch1 -PortKey 403 |
But how do we get that PortKey number ?
Since PowerCLI is all about automation, we are not going to use the vSphere client to get the number. Hence the following function.
The script
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
function Get-dvPgFreePort{ <# .SYNOPSIS Get free ports on a dvSwitch portgroup .DESCRIPTION The function will return 1 or more free ports on a dvSwitch portgroup .NOTES Author: Luc Dekens .PARAMETER PortGroup Specify the portgroup for which you want to retrieve free ports .PARAMETER Number Specify the number of free ports you want to retrieve. The default is 1 port. If Number is greater than the number of available ports, the function will return all available ports .EXAMPLE PS> Get-dvPgFreePort -PortGroup $pg .EXAMPLE PS> Get-dvPgFreePort -PortGroup $pg -Number 5 #> param( [CmdletBinding()] [string]$PortGroup, [int]$Number = 1 ) $nicTypes = "VirtualE1000","VirtualE1000e","VirtualPCNet32", "VirtualVmxnet","VirtualVmxnet2","VirtualVmxnet3" $ports = @{} $pg = Get-VirtualPortGroup -Distributed -Name $PortGroup $pg.ExtensionData.PortKeys | %{$ports.Add($_,$pg.Name)} if($pg.ExtensionData.Vm){ Get-View $pg.ExtensionData.Vm | %{ $nic = $_.Config.Hardware.Device | where {$nicTypes -contains $_.GetType().Name -and $_.Backing.GetType().Name -match "Distributed"} $nic | %{$ports.Remove($_.Backing.Port.PortKey)} } } if($Number -gt $ports.Keys.Count){ $Number = $ports.Keys.Count } ($ports.Keys | Sort-Object)[0..($Number - 1)] } |
Annotations
Line 27-28: All the possible NIC types
Line 29: To collect the ports, the script uses a hash table.
Line 32: The script adds all ports available on the portgroup to the hash table
Line 34: Skip the following code block when there are no VMs connected to this portgroup
Line 35: For all the VMs connected to the portgroup, the script will find the NICs connected to this portgroup.
Line 39: For the NICs that are connected to the portgroup, the script will remove the corresponding portkey from the hash table
Line 43-45: If the caller asked more ports than there are free on the portgroup, the function will return all the free ports.
Line 46: The script returns the free ports in ascending order
Sample usage
The use of the function is quite simple. Just pass the name of the portgroup and the number of ports you want returned.
1 |
Get-dvPgFreePort -PortGroup "dvPG12" -Number 5 |
The result is an ordered list of 5 free ports, which you can use on the PortKey parameter of the Set-NetworkAdapter cmdlet.
Enjoy !
Jrob
Luc,
Thanks so much for this awesome script. I am having some mixed results on the amount of time it takes to find a free port. For example using the function above for one VM it might take 18 secs to find a free port and then the next VM (same vCenter, different PG) it might take 41 secs. Any reason why it would take double the time? Anything I can change to make it go faster? I know I was brief but can provide more info if needed.
Thanks!
Jason
Thanks for this script. It does appear to still generate an accurate number PortKey, but I get the following error when it runs.
Get-View : Cannot validate argument on parameter ‘VIObject’. The argument is nu
ll, empty, or an element of the argument collection contains a null value. Supp
ly a collection that does not contain any null values and then try the command
again.
At C:\script\Get-dvPgFreePort.ps1:34 char:11
+ Get-View <<<< $pg.ExtensionData.Vm | %{
+ CategoryInfo : InvalidData: (:) [Get-View], ParameterBindingVal
idationException
+ FullyQualifiedErrorId : ParameterArgumentValidationError,VMware.VimAutom
ation.ViCore.Cmdlets.Commands.DotNetInterop.GetVIView
My environment utilizes the Cisco Nexus 1000V, so I wonder if that has something to do with it.