Script: Determining Virtual Switch Type Under Hyper-V

When you are scripting against virtual switches – it is good to know what type of switch you are talking to.  In order to figure this out you need to find out whether the virtual switch has an internal network connection, external network connection, neither or both.  Here are some scripts that will do just that:

VBScript:

 option explicit 
  
 Dim HyperVServer
 Dim WMIService 
 Dim VirtualSwitches
 Dim VirtualSwitch
 Dim InternalPortCount
 Dim ExternalPortCount
 Dim SwitchPorts
 Dim SwitchPort
 Dim SwitchLANEndPoints
 Dim SwitchLANEndPoint
 Dim EthernetPort
 Dim Output
 Dim FullMessage
  
 FullMessage = "The following virtual networks were discovered:" & chr(10)
  
 'Prompt for the Hyper-V Server to use
 HyperVServer = InputBox("Specify the Hyper-V Server to create the internal virtual network switch:")
  
 'Get an instance of the WMI Service in the virtualization namespace.
 set WMIService = GetObject("winmgmts:\\" & HyperVServer & "\root\virtualization")
  
 'Get the list of all available network switches
 Set VirtualSwitches = WMIService.ExecQuery("Select * From Msvm_VirtualSwitch")
  
 for each VirtualSwitch in VirtualSwitches
  
    'Initialize variables for counting number of internal and external ports per switch
    InternalPortCount = 0
    ExternalPortCount = 0
  
    'Get the switch ports associated with the switch
    Set SwitchPorts = VirtualSwitch.Associators_("CIM_HostedAccessPoint", "CIM_SwitchPort")
  
    for each SwitchPort in SwitchPorts
       
       'Get the Msvm_SwitchLANEndpoint associated with the switch port
       Set SwitchLANEndpoints = SwitchPort.Associators_("Msvm_ActiveConnection", "Msvm_SwitchLANEndpoint")
       
       for each SwitchLANEndPoint in SwitchLANEndPoints
  
          'Get the CIM_EthernetPort associated with the SwitchLanEndPoint
          Set EthernetPort = (SwitchLANEndPoint.Associators_("CIM_DeviceSAPImplementation", "CIM_EthernetPort")).ItemIndex(0)
          if EthernetPort.Path_.Class = "Msvm_InternalEthernetPort" then InternalPortCount = InternalPortCount + 1
          if EthernetPort.Path_.Class = "Msvm_ExternalEthernetPort" then ExternalPortCount = ExternalPortCount + 1
  
       next
  
    next
  
    Select Case InternalPortCount
    Case 0
       Select Case ExternalPortCount
       Case 0
          Output = "The virtual switch '" & VirtualSwitch.ElementName & "' is a virtual machine only virtual network."
       Case 1
          Output = "The virtual switch '" & VirtualSwitch.ElementName & "' is an external-only virtual network."
       Case Else
          Output = "The virtual switch '" & VirtualSwitch.ElementName & "' is not a standard virtual network."
       End Select
    Case 1
       Select Case ExternalPortCount
       Case 0
          Output = "The virtual switch '" & VirtualSwitch.ElementName & "' is an internal virtual network."
       Case 1
          Output = "The virtual switch '" & VirtualSwitch.ElementName & "' is an external virtual network."
       Case Else
          Output = "The virtual switch '" & VirtualSwitch.ElementName & "' is not a standard virtual network."
       End Select
    Case Else
       Output = "The virtual switch '" & VirtualSwitch.ElementName & "' is not a standard virtual network."
    End Select
  
    FullMessage = FullMessage & chr(10) & Output
  
 next        
  
 'Display the complete information about the virtual switches
 Wscript.echo FullMessage

 

PowerShell:

 # Prompt for the Hyper-V Server to use
 $HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
 write-host
  
 # Get the list of all available network switches
 $query = "Select * From Msvm_VirtualSwitch"
 $VirtualSwitches = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer
  
 # Iterate over each virtual switch
 foreach ($VirtualSwitch in $VirtualSwitches)       
    {  
  
    # Initialize variables for counting number of internal and external ports per switch
    $InternalPortCount = 0
    $ExternalPortCount = 0 
  
    # Get the Switch ports on the virtual switch  
    $query = "Associators of {$VirtualSwitch} where ResultClass=CIM_SwitchPort"
    $switchPorts = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer
  
  
    # A VM only switch with no VMs connected will return null
    if ($switchPorts -ne $null)
       {
  
       # Iterate over each switch port
       foreach ($switchPort in @($switchPorts))       
          {
          # Get the Msvm_SwitchLANEndpoint associated with the switch port
          $query = "Associators of {$switchPort} where ResultClass=Msvm_SwitchLANEndpoint"
          $SwitchLANEndpoint = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer
  
          # If there is no active connection on the switch port the results will be null
          if ($SwitchLANEndpoint -ne $null)
             {
             # Get the CIM_EthernetPort for the Msvm_SwitchLANEndpoint
             $query = "Associators of {$SwitchLANEndpoint} where ResultClass=CIM_EthernetPort"
             $EthernetPort = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer
  
             # Check to see if the associated Ethernet port is an internal port
             if ($EthernetPort.__CLASS -eq "Msvm_InternalEthernetPort")
                {
                $InternalPortCount = $InternalPortCount + 1
                }
  
             # Check to see if the associated Ethernet port is an external port
             if ($EthernetPort.__CLASS -eq "Msvm_ExternalEthernetPort")
                {
                $ExternalPortCount = $ExternalPortCount + 1
                }
             }
          }
       }
  
    switch ($InternalPortCount) 
       {
       0 
          {
          switch ($ExternalPortCount)
             {
             0 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is a virtual machine only virtual network."}
             1 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an external-only virtual network."}
             default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."}
             }
          }
       1
          {
          switch ($ExternalPortCount)
             {
             0 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an internal virtual network."}
             1 {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is an external virtual network."}
             default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."}
             }
          }
       default {$output = "The virtual switch '" + $VirtualSwitch.ElementName + "' is not a standard virtual network."}
       }
    write-host $output
    } 
 write-host

The logic flow for these scripts is as follows:

  • Get all virtual switches (Msvm_VirtualSwitch) and then iterate over each switch.
  • Follow the CIM_HostedAccessPoint association on the switch to get every CIM_SwitchPort associated with the virtual switch.
  • Follow the Msvm_ActiveConnection association on the switch port to get every Msvm_SwitchLANEndpoint associated with each switch port.
  • Follow the CIM_DeviceSAPImplementation association on the switch LAN endpoint to get every CIM_EthernetPort associated with each switch LAN endpoint.
  • Look at the Ethernet port class (external or internal) and tally the number of internal and external Ethernet ports associated with the switch in question.
  • Look at the final tally to figure out the type of the switch.

Some notes to make

  • Many of these queries return 0, 1 or many results – which VBScript tends to do a better job of handling than PowerShell.  Hence why the VBScript is shorter.
    • UPDATE: An MVP pointed out how to make my PowerShell Script shorter – so it has been corrected.
  • Switch ports that are connected to virtual machines do not return a Msvm_SwitchLANEndpoint (they return a Msvm_VMSwitchLANEndpoint) so these switch ports are not considered during this code.
  • The “Msvm_ActiveConnection” object only exists on switch ports that are connected to internal Ethernet ports, external Ethernet ports or running virtual machines.
  • It is possible to have a virtual switch with more than 1 external Ethernet port or more than 1 internal Ethernet port – but the Hyper-V UI will never make one (and such configurations are not tested or recommended).

Cheers,

Ben