Managing Virtual Switches and Networks Across Hyper-V Hosts

I was asked a question this morning about the following customer requirement:

“Managing virtual switches should be done from a central point and the configuration should be automatically distributed to the host operating system in such a way as to eliminate the need for a separate configuration switches for each of the hosts.”

The requirement to “manage” is pretty generic, that could mean anything. Minimally I’d assume it means create/update/delete virtual switches. The System Center Virtual Machine Manager 2008 R2 GUI supports these operations but only on a host by host basis. Here’s what you can do per host:

clip_image001

So per host you can create, update, and delete virtual switches. Since this is VMM, anything you can do in the GUI you can do via PowerShell and extend. Scripts can be stored in the VMM library and executed from there:

clip_image0015

Now when these run, you get presented with a PowerShell shell that you can interact with if needed or just have the script run without input. You can prompt for user input or get fancy with a menu system. There are multiple cmdlets that let you do things with virtual networks and switches like New-VirtualNetwork, Set-VirtualNetwork, Get-VirtualNetwork, Remove-VirtualNetwork. From the VMM PowerShell console, you can do a get-help on these or see the reference document linked below. 

So for anything you need to do in a distributed fashion across multiple hosts, like “add new vNetwork to all hosts, set it as External, and connect to the Broadcom NIC” you can create a script to do so then any list of hosts you pipe to that script would have the script run against it. If you feed it all hosts, then it would run on all hosts. Here’s an example:

Get-VMMServer -ComputerName "VMMServer1.Contoso.com"
$VMHost = Get-VMHost -ComputerName "VMHost01.Contoso.com"
$HostAdapter = Get-VMHostNetworkAdapter –VMMServer “VMMServer1.Contoso.com” | where { $_.Name -match "Broadcom" }
New-VirtualNetwork -Name "External" -VMHost $VMHost -VMHostNetworkAdapter $HostAdapter

This is the code for a single host, so would execute against VMHost01. The selection criteria for which physical NIC to bind the virtual network to can be any attribute of the network adapter object such as Name(the physical adapter name), MAC, IP, etc. There are several methods that could be used to run this against multiple servers. This code fragment could be turned into a function with parameters, it could be executed inside of a loop or pipeline etc. To execute against all hosts in a particular host group, you could do something like this:

$VMHostGroup = Get-VMHostGroup -Name "MyHostGroup" -VMMServer "VMMServer1.Contoso.com"
$VMHosts = Get-VMHost -VMHostGroup $VMHostGroup
ForEach ($VMHost in $VMHosts) {

    #Anything you want to run on all hosts in the $VMHostGroup

}

The above would work for a host group of stand-alone hosts. Where this gets a bit complicated is that hosts groups, host clusters, and hosts are arranged hierarchically and can be nested. So if you have a larger structure with multiple host groups, each containing multiple clusters, and so on, you would need to use a few additional techniques.

To get all stand-alone hosts in a host group with child host groups, you can use:

$VMHosts = $VMHostGroup.AllChildGroups | Get-VMHost 

To get the host clusters in a host group, you can use:

$VMHostClusters = $VMHostGroup.AllChildGroups | Get-VMHostCluster

To get the hosts in a host cluster, you can use:

$VMHosts = Get-VMHost -VMHostCluster $VMHostCluster

So to be sure that you get all hosts from a given level of the hierarchy down, you need something like this (since this starts at All Hosts, it should run against every host in the hierarchy):

$VMHostGroup = Get-VMHostGroup -Name "All Hosts" -VMMServer "VMMServer1.Contoso.com"
if ($VMHostGroup.AllChildGroups -ne $null)
{
$VMHosts = $VMHostGroup.AllChildGroups | Get-VMHost
$VMHostClusters = $VMHostGroup.AllChildGroups | Get-VMHostCluster
ForEach ($VMHost in $VMHosts)
{
#Anything you want to run on all hosts in the $VMHostGroup and all its child host groups
}
}
else
{
$VMHosts = Get-VMHost -VMHostGroup $VMHostGroup
$VMHostClusters = $VMHostGroup | Get-VMHostCluster
ForEach ($VMHost in $VMHosts)
{
#Anything you want to run on all hosts in the $VMHostGroup
}
}
if ($VMHostClusters -ne $null)
{
foreach ($VMHostCluster in $VMHostClusters)
{
$VMHosts = Get-VMHost -VMHostCluster $VMHostCluster
ForEach ($VMHost in $VMHosts)
{
#Anything you want to run on all hosts in the $VMHostCluster
}
}
}

For details on what you can do with the VMM and Failover Cluster cmdlets, here’s some links:

VMM 2008 R2 Cmdlet Reference

https://www.microsoft.com/downloads/en/details.aspx?displaylang=en&FamilyID=08a9eeb9-86ff-4a4f-8dfa-165bd701aba9

Failover Cluster Cmdlet Reference

https://technet.microsoft.com/en-us/library/ee461009.aspx

If there’s something that can’t be done from VMM, then check out the Hyper-V PowerShell Library on CodePlex:

https://pshyperv.codeplex.com/releases/view/38769