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:
Create a new virtual network switch with nothing connected ( MSVM_VirtualSwitchManagementService.CreateSwitch )
Create a new internal switch port on the new virtual network switch ( MSVM_VirtualSwitchManagementService.CreateSwitchPort )
- You can think of this as making a new jack to connect a network cable to on the virtual switch. You need to do this for virtual machine and parent partition connections.
Create a new internal ethernet port ( MSVM_VirtualSwitchManagementService.CreateInternalEthernetPortDynamicMac )
- The internal ethernet port is the virtual network adapter that appears inside the parent partition for the internal virtual network. If you were to stop the script after creating the internal ethernet port you would see a disconnected virtual network adapter in the parent partition.
Finally connect the internal ethernet port to the internal switch port on the new switch ( MSVM_VirtualSwitchManagementService.ConnectSwitchPort )
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.