Tuesday, February 16, 2016

script/tool to remove vmkernel/vm portgroups on all vmware hosts






We all know(assuming that you are familiar with vmware) how to remove portgroups on esxi hosts but what if you have to do that on a lot of hosts? and if you are like me who likes quick, dirty and lazy ways of achieving things then here is something which might suit your taste buds.

first of all let us choose a cluster on which we want to perform this activity.


$cluster = "deadpool"
$pg      = "galactus"

get-cluster $cluster | get-vmhost | select name | sort


Above i have chosen the cluster deadpool (the new standalone movie version not the crappy x men origins wolverine version) and the portgroup is galactus. The above gives me



Name                                                                                                                                                         
----                                                                                                                                                          
Wolverine1.dc.universe                                                                                                                                    
wolverine2.dc.universe                                                                                                                                
wolverine3.dc.universe 

let us find out on which host we have the portgroup that we want to remove.



$cluster = "deadpool"
$pg      = "galactus"
foreach ($vmhost in (get-cluster $cluster | get-vmhost | sort))
{
 get-vmhost $vmhost | get-virtualportgroup -name $pg

}

Name                      Key                            VLanId PortBinding NumPorts
----                      ---                            ------ ----------- --------
galactus                  key-vim.host.PortGroup-gala... 0                         
galactus                  key-vim.host.PortGroup-gala... 0                         
get-virtualportgroup : 2/17/2016 11:07:43 AM    Get-VirtualPortGroup        VirtualPortGroup with name 'galactus' was not found using the specified
filter(s).   
At line:5 char:23
+  get-vmhost $vmhost | get-virtualportgroup -name $pg
+                       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (:) [Get-VirtualPortGroup], VimException
    + FullyQualifiedErrorId : Core_OutputHelper_WriteNotFoundError,VMware.VimAutomation.ViCore.Cmdlets.Commands.Host.GetVirtualPortGroup
 

As you can see one of the 2 hosts do not have the portgroup galactus in it and thus the error for that host says that there is no such portgroup found on that host.

Why don't we tweak it a bit to include only those hosts which has this portgroup?
 

get-vmhost $vmhost | get-virtualportgroup
 This will list all the portgroups in a host
Name                      Key                            VLanId PortBinding NumPorts
----                      ---                            ------ ----------- --------
galactus                  key-vim.host.PortGroup-gala... 0                         
xxxxxxxxxxxxx             key-vim.host.PortGroup-VB2_... 110                       
yyyyyyyyyyyyy             key-vim.host.PortGroup-VB2_... 2234                      
zzzzzzzzzzzzz             key-vim.host.PortGroup-VB2_... 107                       
galactus                  key-vim.host.PortGroup-VB2_... 108                     

 

(get-vmhost $vmhost | get-virtualportgroup).Name
  This will  show the  list of the portgroups of the hosts but just the names of the portgroups.

galactus
xxxxxxxxxx
yyyyyyyyyyy
zzzzzzzzzzz

Now let us use some powershell common sense to tell the script to consider the host for further scripting/automation only if this list contains the portgroup that we need. That is done by

  if ((get-vmhost $vmhost | get-virtualportgroup).Name -contains $pg) {
 get-vmhost $vmhost | get-virtualportgroup -name $pg
 }

  So the total script will now look like
$cluster = "AMP2_Mgmt"
$pg      = "galactus"
foreach ($vmhost in (get-cluster $cluster | get-vmhost | sort))
{
 if ((get-vmhost $vmhost | get-virtualportgroup).Name -contains $pg) {
 get-vmhost $vmhost | get-virtualportgroup -name $pg
 }
}

and it's output looks like

Name                      Key                            VLanId PortBinding NumPorts
----                      ---                            ------ ----------- --------
galactus                  key-vim.host.PortGroup-gala... 0                          
galactus                  key-vim.host.PortGroup-gala... 0                           
so it just skipped the 1 of 3 hosts which doesnt have this portgroup.
Now let us try to remove the portgroup on the host which has this portgroup.

foreach ($vmhost in (get-cluster $cluster | get-vmhost | sort)) {
  if ((get-vmhost $vmhost | get-virtualportgroup).Name -contains $pg) {
   get-vmhost $vmhost | get-virtualportgroup -Name $pg | Remove-VirtualPortGroup -Confirm:$false
  }
 }


so now you can see that i have replaced a line which was listing the portgroup to a line which remove the portgroup but let us see the output.

Remove-VirtualPortGroup : 2/17/2016 11:23:24 AM    Remove-VirtualPortGroup        The resource 'galactus' is in use.   
At line:5 char:58
+    get-vmhost $vmhost | get-virtualportgroup -Name $pg | Remove-VirtualPortGroup ...
+                                                          ~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Remove-VirtualPortGroup], VimException
    + FullyQualifiedErrorId : Core_BaseCmdlet_UnknownError,VMware.VimAutomation.ViCore.Cmdlets.Commands.RemoveVirtualPortGroup

  It says the portgroup is busy?
Let us list the portgroups again and see what happened.
get-cluster $cluster | get-vmhost | get-virtualportgroup -Name $pg

shows

Name                      Key                            VLanId PortBinding NumPorts
----                      ---                            ------ ----------- --------
galactus                  key-vim.host.PortGroup-gala... 0                         


  so it means only one host now has this portgroup and on the other one the script successfully remove the portgroup. Let us see why script was able to remove the portgroup on one host and couldnt on another one.



This is why. This galactus portgroup on this host is not a regular vm portgroup but a vmkernel portgroup. First we have to remove the vmkernel and then we have to remove the portgroup.
   $vmk = Get-VMHostNetworkAdapter -VMHost $vmhost | where PortgroupName -eq $pg
Remove-VMHostNetworkAdapter -Nic $vmk -confirm:$false

 The above should remove the vmkernel. The lines are self explanatory. The first line fetched the vmkernel. 2nd line removes the vmkernel but we want to do this on only that portgroup in which there is a vmkernel present.

   $vmk = Get-VMHostNetworkAdapter -VMHost $vmhost | where PortgroupName -eq $pg
   if ($vmk -ne $null) {
Remove-VMHostNetworkAdapter -Nic $vmk -confirm:$false
   }



basically the above will check whether the number of vmkernel is $null (meaning 0 or absent) then it will proceed further to remove the vmkernel, otherwise it will skip to the next scriptblock. 
foreach ($vmhost in (get-cluster $cluster | get-vmhost | sort)) {
  if ((get-vmhost $vmhost | get-virtualportgroup).Name -contains $pg) {
   $vmk = Get-VMHostNetworkAdapter -VMHost $vmhost | where PortgroupName -eq $pg
   if ($vmk -ne $null) {
   Write-Host "removing vmkernel from the $pg on $vmhost"
   Remove-VMHostNetworkAdapter -Nic $vmk -confirm:$false
   }
   Write-Host "removing $pg on $vmhost"
   get-vmhost $vmhost | get-virtualportgroup -Name $pg | Remove-VirtualPortGroup -Confirm:$false
  }
 }


The entire thing should look like this. If you want the complete script (updated) then go see here