Jaa


Script: Creating an internal virtual network with Hyper-V

Moving on from yesterdays script (which showed you how to create a private virtual network) let’s look at creating an internal virtual network via a script.  An internal virtual network is one that is not connected to a physical network adapter – but allows virtual machines to communicate with each other and the parent partition.  This is a fair bit more complicated than creating a private virtual network:

VBScript:

 option explicit 
  
 Dim HyperVServer
 Dim SwitchFriendlyName
 Dim TypeLib
 Dim SwitchName
 Dim InternalEthernetPortFriendlyName
 Dim InternalSwitchPortFriendlyName
 Dim InternalSwitchPortName
 Dim InternalEthernetPortName
 Dim ScopeofResidence
 Dim WMIService 
 Dim VirtualSwitchManagementService
 Dim Switch
 Dim InternalSwitchPort
 Dim InternalEthernetPort
 Dim InternalLanEndPoint
 Dim InParam
 Dim OutParams
  
 'Prompt for the Hyper-V Server to use
 HyperVServer = InputBox("Specify the Hyper-V Server to create the internal virtual network switch:")
  
 'Get friendly name for the internal virtual network switch (and the internal ethernet port)
 SwitchFriendlyName = InputBox("Specify the name of the new internal virtual network switch:")
 InternalEthernetPortFriendlyName = SwitchFriendlyName 
  
 'Set the friendly name for the internal switch port
 InternalSwitchPortFriendlyName = "InternalSwitchPort"
  
 'Generate GUIDs for the unique switch name, internal switch port name and internal ethernet port name
 Set TypeLib = CreateObject("Scriptlet.TypeLib")
 SwitchName = TypeLib.Guid
  
 Set TypeLib = CreateObject("Scriptlet.TypeLib")
 InternalSwitchPortName = TypeLib.Guid
  
 Set TypeLib = CreateObject("Scriptlet.TypeLib")
 InternalEthernetPortName = TypeLib.Guid
  
 'Set scope of residence
 ScopeofResidence = null
  
 '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)
         
 '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 = ScopeofResidence
  
 '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 internal switch port
  
 'Setup the input parameter list
 set InParam = VirtualSwitchManagementService.Methods_("CreateSwitchPort").InParameters.SpawnInstance_()
 InParam.VirtualSwitch = Switch.Path_.Path
 InParam.FriendlyName = InternalSwitchPortFriendlyName
 InParam.Name = InternalSwitchPortName 
 InParam.ScopeofResidence = ScopeofResidence
  
 'Execute the method and store the results in OutParam
 set OutParams = VirtualSwitchManagementService.ExecMethod_("CreateSwitchPort", InParam)
  
 'Get the new internal switch port out of the results    
 Set InternalSwitchPort = WMIService.Get(OutParams.CreatedSwitchPort)
  
 'Create a new internal ethernet port
  
 'Setup the input parameter list
 set InParam = VirtualSwitchManagementService.Methods_("CreateInternalEthernetPortDynamicMac").InParameters.SpawnInstance_()
 InParam.FriendlyName = InternalEthernetPortFriendlyName
 InParam.Name = InternalEthernetPortName
  
 'Execute the method and store the results in OutParam
 set OutParams = VirtualSwitchManagementService.ExecMethod_("CreateInternalEthernetPortDynamicMac", InParam)
     
 'Get the new internal ethernet port out of the results
 Set InternalEthernetPort = WMIService.Get(OutParams.CreatedInternalEthernetPort)
  
 'Get the CIM_LanEndpoint Object associated with the internal ethernet port
 Set InternalLanEndPoint = (InternalEthernetPort.Associators_("CIM_DeviceSAPImplementation", "Cim_LanEndpoint")).ItemIndex(0)  
  
 'Connect the switch to the internal ethernet port via the CIM_LanEndpoint
  
 'Setup the input parameter list
 set InParam = VirtualSwitchManagementService.Methods_("ConnectSwitchPort").InParameters.SpawnInstance_()
 InParam.LANEndPoint = InternalLanEndPoint.Path_.Path
 InParam.SwitchPort = InternalSwitchPort.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)"
  
 # Get friendly name for the internal virtual network switch (and internal ethernet port)
 $SwitchFriendlyName = Read-Host "Specify the name of the new internal virtual network switch"
 $InternalEthernetPortFriendlyName = $SwitchFriendlyName
  
 # Set the friendly name for the internal switch port
 $InternalSwitchPortFriendlyName = "InternalSwitchPort"
  
 # Generate GUIDs for the unique switch name, internal switch port name and internal ethernet port name
 $SwitchName = [guid]::NewGuid().ToString()
 $InternalSwitchPortName = [guid]::NewGuid().ToString()
 $InternalEthernetPortName = [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 Internal Switch Port 
 $Result = $VirtualSwitchManagementService.CreateSwitchPort($Switch, $InternalSwitchPortName, $InternalSwitchPortFriendlyName, $ScopeOfResidence)
  
 # Get the WMI object for the new switch port out of the results
 $InternalSwitchPort = [WMI]$Result.CreatedSwitchPort 
  
 # Create Internal Ethernet Port 
 $Result = $VirtualSwitchManagementService.CreateInternalEthernetPortDynamicMac($InternalEthernetPortName, $InternalEthernetPortFriendlyName)
  
 # Get the WMI object for the new ethernet port out of the results
 $InternalEthernetPort = [WMI]$Result.CreatedInternalEthernetPort
  
 # Get the CIM_LanEndpoint Object associated with the internal ethernet port
 $query = "Associators of {$InternalEthernetPort} Where ResultClass=CIM_LanEndpoint"
 $InternalLanEndPoint = gwmi -namespace root\virtualization -query $query -computername $HyperVServer
  
 # Connect the internal ethernet port to the virtual network switch
 $Result = $VirtualSwitchManagementService.ConnectSwitchPort($InternalSwitchPort, $InternalLanEndPoint)

Yikes!  That is a bunch of code.  Let’s step through the logic involved here.  The logic flow is as follows:

When it is all done you have an internal virtual network as Hyper-V creates in its own UI.  Some extra things to highlight here:

  • 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.
  • The friendly name for the internal ethernet port is what appears as the device name for the virtual network adapter in the parent partition (when you open up the network connection management UI under Windows).  In these scripts I make it the same as the virtual network name – which is what the Hyper-V UI does – but you can make it anything you want.
  • 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 internal switch port.  I am doing this because it is never displayed in the UI and does not need to be unique.
  • In these scripts I use “CreateInternalEthernetPortDynamicMac”.  There is a plain “CreateInternalEthernetPort” where you specify your own MAC address – but most of the time it is just easiest to use dynamic MAC addresses.
  • You need to provide a CIM_LanEndpoint object when calling ConnectSwitchPort.  The best way to get this is to take the Msvm_InternalEthernetPort object and walk the association through CIM_DeviceSAPImplementation to Cim_LanEndpoint.

Cheers,

Ben

UPDATE: I have made a minor update to the VBScript as I discovered that I needed to reinitialize TypeLib each time, otherwise you just get the same GUID multiple times over.