Script: Creating an external-only virtual network with Hyper-V

Script: Creating an external-only virtual network with Hyper-V

  • Comments 2

Okay, last script for the week.  Creating an external-only virtual network (one without a connection in the parent partition).

VBScript:

option explicit 
 
Dim HyperVServer
Dim SwitchFriendlyName
Dim TypeLib
Dim SwitchName
Dim ExternalSwitchPortFriendlyName
Dim ExternalSwitchPortName
Dim ExternalEthernetPort
Dim ExternalEthernetPorts
Dim ExternalEthernetPortName
Dim ExternalEthernetPortString
Dim ExternalLanEndPoint 
Dim ScopeofResidence
Dim WMIService 
Dim VirtualSwitchManagementService
Dim Switch
Dim ExternalSwitchPort
Dim InParam
Dim OutParams
Dim Job
Dim Test
 
'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 Msvm_VirtualSwitchManagementService object
set VirtualSwitchManagementService = WMIService.ExecQuery("select * from Msvm_VirtualSwitchManagementService").ItemIndex(0)
 
'Get all possible physical network adapters that can be used for a switch
Set ExternalEthernetPorts = WMIService.ExecQuery("Select * From Msvm_ExternalEthernetPort WHERE IsBound=False AND EnabledState=2")
 
'Build the string to ask what physical network adapter to use
ExternalEthernetPortString = "The following network adapters are available:" & chr(10) & chr(10)
 
for each ExternalEthernetPort in ExternalEthernetPorts
   ExternalEthernetPortString = ExternalEthernetPortString & ExternalEthernetPort.Name & chr(10)
next       
 
ExternalEthernetPortString = ExternalEthernetPortString & chr(10) & "Please type in the (exact) name of the network adapter you want to use for the external connection:"
 
'Setup a loop to keep on asking for a network adapter until we get a valid response
Test = true
 
while test
   ExternalEthernetPortName = InputBox(ExternalEthernetPortString)
   on error resume next
   Set ExternalEthernetPort = WMIService.ExecQuery("Select * From Msvm_ExternalEthernetPort WHERE Name='" & ExternalEthernetPortName & "' AND IsBound=False AND EnabledState=2").ItemIndex(0)       
   If Err.Number = 0 Then
      Test = false
   End If
   on error goto 0
wend
 
'Get friendly name for the external virtual network switch 
SwitchFriendlyName = InputBox("Specify the name of the new external virtual network switch:")
 
'Set the friendly name for the external switch port
ExternalSwitchPortFriendlyName = "ExternalSwitchPort"
 
'Generate GUIDs for the unique switch name and external ethernet port name
Set TypeLib = CreateObject("Scriptlet.TypeLib")
SwitchName = TypeLib.Guid
 
Set TypeLib = CreateObject("Scriptlet.TypeLib")
ExternalSwitchPortName = TypeLib.Guid
 
'Create a new virtual network switch
 
'Setup the input parameter list
set InParam = VirtualSwitchManagementService.Methods_("CreateSwitch").InParameters.SpawnInstance_()
InParam.FriendlyName = SwitchFriendlyName
InParam.Name = SwitchName 
InParam.NumLearnableAddresses = 1024
InParam.ScopeofResidence = null
 
'Execute the method and store the results in OutParam
set OutParams = VirtualSwitchManagementService.ExecMethod_("CreateSwitch", InParam)
 
'Get the new switch object out of the results    
Set Switch = WMIService.Get(OutParams.CreatedVirtualSwitch)
 
'Create a new external switch port
 
'Setup the input parameter list
set InParam = VirtualSwitchManagementService.Methods_("CreateSwitchPort").InParameters.SpawnInstance_()
InParam.VirtualSwitch = Switch.Path_.Path
InParam.FriendlyName = ExternalSwitchPortFriendlyName
InParam.Name = ExternalSwitchPortName 
InParam.ScopeofResidence = null
 
'Execute the method and store the results in OutParam
set OutParams = VirtualSwitchManagementService.ExecMethod_("CreateSwitchPort", InParam)
 
'Get the new external switch port out of the results    
Set ExternalSwitchPort = WMIService.Get(OutParams.CreatedSwitchPort)
 
'Bind the external ethernet port to prepare it to be connected to a switch
 
'Setup the input parameter list
set InParam = VirtualSwitchManagementService.Methods_("BindExternalEthernetPort").InParameters.SpawnInstance_()
InParam.ExternalEthernetPort = ExternalEthernetPort.Path_.Path
 
'Execute the method and store the results in OutParam
set OutParams = VirtualSwitchManagementService.ExecMethod_("BindExternalEthernetPort", InParam)
 
'Get the CIM_LanEndpoint Object associated with the external ethernet port
Set ExternalLanEndPoint = (ExternalEthernetPort.Associators_("CIM_DeviceSAPImplementation", "Cim_LanEndpoint")).ItemIndex(0)  
 
'Connect the switch to the external ethernet port via the CIM_LanEndpoint
 
'Setup the input parameter list
set InParam = VirtualSwitchManagementService.Methods_("ConnectSwitchPort").InParameters.SpawnInstance_()
InParam.LANEndPoint = ExternalLanEndPoint.Path_.Path
InParam.SwitchPort = ExternalSwitchPort.Path_.Path
 
'Execute the method and store the results in OutParam
set OutParams = VirtualSwitchManagementService.ExecMethod_("ConnectSwitchPort", InParam)

PowerShell:

# Prompt for the Hyper-V Server to use
$HyperVServer = Read-Host "Specify the Hyper-V Server to use (enter '.' for the local computer)"
 
# List the available physical network adapters
Write-Host "The following physical network adapters are avaiable for an external-only virtual network:"
 
# Get the collection of external network adapters that are not associated with switches
$query = "Select * From Msvm_ExternalEthernetPort WHERE IsBound=False AND EnabledState=2"
$ExternalEthernetPorts = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer
 
#Output the elementname for each external nic
foreach ($Nic in $ExternalEthernetPorts)       
   {          
      Write-Host $Nic.Name       
   } 
 
# Keep on asking for a physical network adapter until we get a valid answer
$ExternalEthernetPort = $null
 
While ($ExternalEthernetPort -eq $null)
   {
   # Ask for the NIC name to use for the switch
   $ExternalEthernetPortName = Read-Host "Please type in the (exact) name of the network adapter you want to use for the external connection"
 
   # Get the WMI object for the external nic
   $query = "Select * From Msvm_ExternalEthernetPort WHERE Name='" + $ExternalEthernetPortName + "' AND IsBound=False AND EnabledState=2"
   $ExternalEthernetPort = gwmi -namespace "root\virtualization" -Query $query -computername $HyperVServer
   }
 
# Get friendly name for the external-only virtual network switch
$SwitchFriendlyName = Read-Host "Specify the name of the new external-only virtual network switch"
 
# Set the friendly name for the external switch port
$ExternalSwitchPortFriendlyName = "ExternalSwitchPort"
 
# Generate GUIDs for the unique switch name and external switch port name
$SwitchName = [guid]::NewGuid().ToString()
$ExternalSwitchPortName = [guid]::NewGuid().ToString()
 
# Setup some other values that will be used
$NumLearnableAddresses = 1024
$ScopeOfResidence = ""
 
# Get the Msvm_VirtualSwitchManagementService WMI Object on the system we are going to be working with
$VirtualSwitchManagementService = gwmi Msvm_VirtualSwitchManagementService -namespace "root\virtualization" -computername $HyperVServer
 
# Create a new switch with 1024 learnable addresses
$Result = $VirtualSwitchManagementService.CreateSwitch($SwitchName, $SwitchFriendlyName, $NumLearnableAddresses, $ScopeOfResidence) 
 
# Get the WMI object for the new switch out of the results
$Switch = [WMI]$Result.CreatedVirtualSwitch 
 
# Create External Switch Port 
$Result = $VirtualSwitchManagementService.CreateSwitchPort($Switch, $ExternalSwitchPortName, $ExternalSwitchPortFriendlyName, $ScopeOfResidence)
 
# Get the WMI object for the new switch port out of the results
$ExternalSwitchPort = [WMI]$Result.CreatedSwitchPort 
 
# Bind ExternalEthernetPort to prepare it for connection to a virtual network switch
$Result = $VirtualSwitchManagementService.BindExternalEthernetPort($ExternalEthernetPort) 
 
# Get the CIM_LanEndpoint Object associated with the external ethernet port
$query = "Associators of {$ExternalEthernetPort} Where ResultClass=CIM_LanEndpoint"
$ExternalLanEndPoint = gwmi -namespace root\virtualization -query $query -computername $HyperVServer
 
# Connect the external ethernet port to the virtual network switch
$Result = $VirtualSwitchManagementService.ConnectSwitchPort($ExternalSwitchPort, $ExternalLanEndPoint)

Going through the flow again:

Some interesting points to make:

  • When looking at physical network adapters (MSVM_ExternalEthernetPort):
    • Network adapters that are already connected to a virtual network will return “true” for “IsBound”
    • If you do not check the EnabledState you will see entries for old network adapters that are no longer present in the physical computer
    • You really should be using the “DeviceID” to uniquely identify network adapters, as the name is not guaranteed to be unique – but as no one knows the device ID, and the chances of a duplicate name are incredibly low – I prefer to use the name
  • Since I am asking the user to type in a long string for the network name – I have put in a loop so that if they make a mistake they have a chance to enter it again.
  • All of the above methods return a result object that contains a reference to the WMI object that has been created.  You will see in the code that after each method call we then need to go and grab this object out of the results.
  • The results also contain a return code that indicates success or failure.  For brevity of code I am not checking this value and am assuming success on each of these calls – however for correctness you should be checking this value.
  • For all the non-friendly names I am generating GUIDs.  This is not required but is strongly recommended.  These values are never displayed in the UI and are used for internal purposes and *must* be unique.
  • I have hardcoded the value for the friendly name of the external switch port.  I am doing this because it is never displayed in the UI and does not need to be unique.
  • You need to provide a CIM_LanEndpoint object when calling ConnectSwitchPort.  The best way to get this is to take the Msvm_ExternalEthernetPort object and walk the association through CIM_DeviceSAPImplementation to Cim_LanEndpoint.
    • This only works after calling BindExternalEthernetPort
  • You should be careful with this script as it will render the parent partition unable to use the physical network adapter that you select.

Cheers,
Ben

Leave a Comment
  • Please add 5 and 1 and type the answer here:
  • Post
  • Exactly what I needed! Thanks much for the script.

  • Hi,

    thanks for this great script! The only issue I still have is that I need to " allow management operating system to share this network". Do you have also a solution for this?

    Regards

    Michael

Page 1 of 1 (2 items)