If your VMware implementation contains more than a few hosts, managing port groups (or any multi-host settings) can be a real pain. In order to take advantage of cool things like vMotion, your port groups need to match across all hosts in the cluster. If one of them is misspelled, or has a bad VLAN tag, it’s a no-go.
By using a script, you can apply a add/change to all hosts in a cluster, vastly reducing the chances of that hard to find typo that will bork you. As an added bonus, you’ll get your portgroups updated in vastly reduced time.
Recently, I began on a journey to standardize names of port groups across all the VMware clusters that I manage. Mainly for standardization of processes and procedures. Also, I am trying to prepare the virtual landscape for movement to a private cloud model. This standardization of network names across the 9 or so clusters is a good start.
My largest single cluster, the labs, contains 16 hosts. Each host contains 8 VLANS, for seperation of various lab environments, some fenced, most not. I drafted up this handy little table that shows current state and where I want to be:
VLAN ID | Old PG Name | New PG Name |
---|---|---|
10 | prod-10net | 0010 Production |
12 | QALabs12 | 0012 LAB QA 1 |
29 | CVLAN29 | 0029 Client |
26 | CVLAN26 | 0026 Client |
214 | SIT214 | 0214 LAB UAT |
314 | SIT314 | 0314 LAB SIT |
414 | infra414 | 0414 LAB Infrastructure |
514 | PerfTest514 | 0514 LAB Performance Testing |
So, I know the what the current VLAN and name information is for each portgroup, and what I want it to be called when I am done. Good – step 1 complete. Now, we have a few more steps to complete:
- Create new portgroups
- Move existing guest VMs to new portgroups
- Remove old portgroups
Why not just rename the existing portgroups? Much easier, right? Glad you asked!
Each guest VM holds its configuration in a VMX file. This file describes the virtual hardware configuration of the guest VM. Things like vCPU count, Memory size, VMDK location, and what network to use. By simply changing the name of the portgroup, the guest configurations are not updated. You would have to change all the VMs to point to the new network!
You could automate that with some of the knowledge I’m going to lay on you below, but I think it is a bit less intrusive to the users if you first create a new set of portgroups, then update the VMs with the new info.
For this exercise, I am going to be using PowerCLI. VMware vSphere PowerCLI is a powerful command line tool that lets you automate all aspects of vSphere management, including network, storage, VM, guest OS and more, all in a PowerShell snapin. If you haven’t gotten your hands on it, go get it now!
Once you get PowerCLI installed, connect to your vCenter server:
Connect-VIServer -Server 10.22.36.36 -Protocol https -User admin -Password mypass
Of course, you’ll need to put your account information in the proper places. Once you get connected, you now have a PowerShell interface to all the hosts and clusters that your account has access to, with a ton of great cmdlets at your disposal.
The cmdlet we are interested for adding new portgroups is new-VirtualPortGroup. A single host example of adding a portgroup to a vswitch looks something like this:
get-vmhost -name vmwarehost01.mydomain.com | Get-VirtualSwitch -name vSwitch0 | new-VirtualPortGroup -name "4010 LAB MyLabSpace" -vlanid 4010
Typing this command at your PowerCLI prompt will add a new portgroup called 4010 LAB MyLabSpace to vSwitch0, with a VLAN tag of 4010. Ok, that’s pretty neat. This definitely cuts the amount of time needed to add a portgroups to hosts. You could type this up into notepad, with all the necessary host information, ending with 16 lines of code you could then paste into the PowerCLI window.
But there is a better way. How about poking the information into all the hosts in a particular cluster, with one line of PowerShell goodness? This bit of code will add a portgroup with VLAN id, to a named vSwitch on all hosts in a named cluster:
foreach ($esx in get-VMhost -Location "TargetClusterName" | sort Name) { $esx | Get-VirtualSwitch -Name "vSwitchName" | New-VirtualPortGroup -Name "New PortGroup Name" -VlanId 123 }
If you’ve worked with PowerShell, you should recognize what is going on here. But for those who may not be familar, I’ll explain a bit. First, if you are copy/pasting this code, you’ll need to modify a few values before you run it.
- TargetClusterName: This is the name of the cluster that you want to target.
- vSwitchName: The vSwitch you want to place the portgroup on. All your hosts should be configured to use the same vSwitch name already, right?
- New PortGroup Name: This is what you want to call the new portgroup. If you have spaces in the name, be sure to put quotes around it.
- 123: If you use VLANs, this is where you specify the VLAN id. If you don’t use VLANs (shame on you!), remove the -vlanid switch.
Once you have all the information in there, run it. The code retrieves all the host names in the cluster, sorted by name, then proceeds to add the portgroup to each host. Repeat this for each new portgroup you want to add. You could encapsulate this further by having PowerShell read a list of portgroups to add from a file, and fully automate the process. Pretty slick, and step two complete.
Before we move on to moving the clients, you might want to know how to break this command out. This would be handy if you want to include this workflow in a larger script. Basically, we are going to use variables to define our switch values, thus:
$Cluster = "Target Cluster Name"
$vSwitch = "Target vSwitch Name"
$NPG = "Name of new Portgroup"
$VLAN = "VLAN ID"
Get-Cluster -Name $Cluster | Get-VMHost | foreach { New-VirtualPortGroup -VirtualSwitch ( Get-VirtualSwitch -Name $vSwitch -VMHost $_ ) -Name $NPG -VLanId $vlan }
Using this, you could potentially have the script ask for the needed values from the user running the script, or this would be first step in reading the values from a CSV file. Go forth and do good!
Provided you didn’t make any typos, you now have at least one new, empty portgroup on all the hosts in your cluster. Now, on to step 3, moving the guest VMs to the new portgroup.
Once again, you can change individual machines, but that would take a bit long, I think. But, if you want to test with one machine (which you should), you’d use the Set-NetworkAdapter cmdlet, like this:
Get-VM VMName | Get-NetworkAdapter | Set-NetworkAdapter -NetworkName "PortGroup Name"
Easy enough. Set focus to the VM, then the network adapter, then set the name. Pretty easy to do, for one or two guest virtual machines.
As mentioned previously, the cluster I am working with contains sixteen hosts, and currently carries around 500 guest virtual machines. I am not going to use the above method to change 500 VMs. PowerShell to the rescue! Here is the code to change all guests using a named network to the new network:
$Cluster = "My Cluster Name"
$OldNetwork = "Old Network Name"
$NewNetwork = "New Network Name"
Get-Cluster $Cluster |Get-VM |Get-NetworkAdapter |Where {$_.NetworkName -eq $OldNetwork } |Set-NetworkAdapter -NetworkName $NewNetwork -Confirm:$false
As you can see, the above code is ready for inclusion into a larger script. For the “one-line” method, simply place your values directly in the last line of the code. Be sure and change the values where applicable, though. Otherwise, you’ll see a bunch of red errors because PowerShell is not happy with your input! If all is well, your new portgroups will be full of guest VMs, and your old portgroups will be emptied in a matter of minutes rather than days.
By now, you should see pattern to these scripts. They are pretty basic, but very powerful. With these bits of code, you have the potential to easily administer your entire environment, or shoot yourself in the foot.
This next piece of code is especially dangerous, especially if you stick it in a loop. You could accidentally blow away the wrong thing, so be careful!
Get-VirtualPortGroup -VMHost "Host" -name "PortGroupName" | Remove-VirtualPortGroup -confirm:$false
This chunk of code will remove the named portgroup from the specified host, without confirmation. BE CAREFUL! I can’t reiterate that enough. Test in a safe area before you start working in a production environment. If you mistype something and delete the wrong thing, it’s your own fault.
So, that’s it. I hope this little bit of knowledge will help you in automating your VMware environment. At the very least, the points and method brought up in this article should get you started down that path.
Happy coding, and may your packets keep flowing!