// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
// Copyright (c) Microsoft. All rights reserved.
namespace Microsoft.Samples.HyperV.Networking
{
using System;
using System.Management;
using System.Globalization;
using Microsoft.Samples.HyperV.Common;
static class CreateSwitchSample
{
///
/// Creates a switch with no ports. This is referred to as a "private" switch inside of
/// the Hyper-V UI. Any virtual machines that connect to such a switch can only communicate
/// with other virtual machines that are running on the same host and that have also connected
/// to the switch.
///
/// The name of the switch to create.
/// Some notes to associate with the switch.
static void
CreatePrivateSwitch(
string switchName,
string switchNotes)
{
ManagementScope scope = new ManagementScope(@"root\virtualization\v2");
CreateSwitch(switchName, switchNotes, null, scope);
Console.WriteLine(string.Format(CultureInfo.CurrentCulture,
"The private switch '{0}' was created successfully.", switchName));
}
///
/// Creates a switch with one port connected to the hosting computer system. This is
/// referred to as an "internal" switch inside of the Hyper-V UI. Any virtual machines
/// that connect to such a switch can communicate with the host machine and any other
/// virtual machines that are running on the same host and that have also connected to the switch.
///
/// The name of the switch to create.
/// Some notes to associate with the switch.
static void
CreateInternalSwitch(
string switchName,
string switchNotes)
{
ManagementScope scope = new ManagementScope(@"root\virtualization\v2");
string[] ports;
//
// Get the hosting computer system. When connecting an internal port, we specify the
// path to the hosting computer system as what the port should connect to.
//
using (ManagementObject hostComputerSystem = WmiUtilities.GetHostComputerSystem(scope))
//
// Get the default Msvm_EthernetPortAllocationSettingData instance that we can use to
// configure our internal port connection for the switch.
// Use the same switch name, appended with "_Internal", for the port name.
// You can use any port name that you like.
//
using (ManagementObject portToCreate =
NetworkingUtilities.GetDefaultEthernetPortAllocationSettingData(scope))
{
portToCreate["ElementName"] = switchName + "_Internal";
portToCreate["HostResource"] = new string[] { hostComputerSystem.Path.Path };
//
// Now create the switch with the internal port.
//
ports = new string[] { portToCreate.GetText(TextFormat.WmiDtd20) };
}
CreateSwitch(switchName, switchNotes, ports, scope);
Console.WriteLine(string.Format(CultureInfo.CurrentCulture,
"The internal switch '{0}' was created successfully.", switchName));
}
///
/// Creates a switch with one port connected to an external adapter. This is referred to
/// as an "external" switch inside of the Hyper-V UI. Any virtual machines that connect
/// to such a switch can communicate externally and with any other virtual machines running
/// on the same host that have also connected to the switch.
///
///
/// We recommend that a configuration have multiple NICs and not specify the external
/// adapter your host machine is using for its external connection because specifying the
/// external adapter will disrupt network traffic to your host machine.
///
/// The external adapter to connect to.
/// The name of the switch to create.
/// Some notes to associate with the switch.
static void
CreateExternalOnlySwitch(
string externalAdapterName,
string switchName,
string switchNotes)
{
ManagementScope scope = new ManagementScope(@"root\virtualization\v2");
string[] ports;
//
// Get the external adapter we are connecting to.
//
using (ManagementObject externalAdapter =
NetworkingUtilities.FindExternalAdapter(externalAdapterName, scope))
//
// Get the default Msvm_EthernetPortAllocationSettingData instance that we can use to
// configure our external port connection for the switch.
// Use the same switch name, appended with "_External", for the port name.
// You can use any port name that you like.
//
using (ManagementObject portToCreate =
NetworkingUtilities.GetDefaultEthernetPortAllocationSettingData(scope))
{
portToCreate["ElementName"] = switchName + "_External";
portToCreate["HostResource"] = new string[] { externalAdapter.Path.Path };
//
// Now create the switch with the external port.
//
ports = new string[] { portToCreate.GetText(TextFormat.WmiDtd20) };
}
CreateSwitch(switchName, switchNotes, ports, scope);
Console.WriteLine(string.Format(CultureInfo.CurrentCulture,
"The external-only switch '{0}' was created successfully.", switchName));
}
///
/// Creates a switch with two ports. One port connected to an external adapter and another
/// port is connected to the host computer system. This is referred to as an "external"
/// switch inside of the Hyper-V UI. Any virtual machines which connect to such a switch
/// can communicate externally, with the host computer system, and with any
/// other virtual machines running on the same host that have also connected to the switch.
///
///
/// We recommend that a configuration have multiple NICs and not specify the external
/// adapter your host machine is using for its external connection because specifying
/// the external adapter will disrupt network traffic to your host machine.
///
/// The external adapter to connect to.
/// The name of the switch to create.
/// Some notes to associate with the switch.
static void
CreateExternalSwitch(
string externalAdapterName,
string switchName,
string switchNotes)
{
ManagementScope scope = new ManagementScope(@"root\virtualization\v2");
string[] ports;
//
// Get the external adapter we are connecting to.
//
using (ManagementObject externalAdapter =
NetworkingUtilities.FindExternalAdapter(externalAdapterName, scope))
//
// Get the hosting computer system. The internal port we create needs to be configured
// to connect to the hosting computer system.
//
using (ManagementObject hostComputerSystem = WmiUtilities.GetHostComputerSystem(scope))
//
// Get the default Msvm_EthernetPortAllocationSettingData instance that we can use to
// configure our external port connection for the switch.
// Use the same switch name, appended with "_External", for the port name.
// You can use any port name that you like.
//
using (ManagementObject externalPortToCreate =
NetworkingUtilities.GetDefaultEthernetPortAllocationSettingData(scope))
{
externalPortToCreate["ElementName"] = switchName + "_External";
externalPortToCreate["HostResource"] = new string[] { externalAdapter.Path.Path };
//
// Clone the externalPort connection and configure it for the internal port.
// Use the same switch name, appended with "_Internal", for the port name.
// You can use any port name that you like.
//
using (ManagementObject internalPortToCreate =
(ManagementObject)externalPortToCreate.Clone())
{
internalPortToCreate["ElementName"] = switchName + "_Internal";
internalPortToCreate["HostResource"] = new string[] { hostComputerSystem.Path.Path };
//
// Copy the MAC address of the external adapter to the internal switch port.
//
internalPortToCreate["Address"] = externalAdapter["PermanentAddress"];
//
// Now create the switch with the two ports.
//
ports = new string[] {
externalPortToCreate.GetText(TextFormat.WmiDtd20),
internalPortToCreate.GetText(TextFormat.WmiDtd20) };
}
}
CreateSwitch(switchName, switchNotes, ports, scope);
Console.WriteLine(string.Format(CultureInfo.CurrentCulture,
"The external switch '{0}' was created successfully.", switchName));
}
///
/// Creates the switch with the ports as configured by the calling method.
///
/// The name of the switch to create.
/// Some notes to associate with the switch.
/// The ports to create on the new switch. This can be null if the
/// switch is supposed to be 'Private'.
/// The scope to use when connecting to WMI.
static void
CreateSwitch(
string switchName,
string switchNotes,
string[] ports,
ManagementScope scope)
{
string switchSettingText;
//
// Create the configuration object we pass into the CreateSwitch method in order to
// specify details about the switch to create, such as its name and any notes.
//
using (ManagementClass switchSettingClass =
new ManagementClass("Msvm_VirtualEthernetSwitchSettingData"))
{
switchSettingClass.Scope = scope;
using (ManagementObject switchSetting = switchSettingClass.CreateInstance())
{
switchSetting["ElementName"] = switchName;
switchSetting["Notes"] = new string[] { switchNotes };
//
// You can also configure other aspects of the switch before you create it,
// such as its IOVPreferred property.
//
// switchSetting["IOVPreferred"] = true;
switchSettingText = switchSetting.GetText(TextFormat.WmiDtd20);
}
}
//
// Now create the switch with the specified ports.
//
using (ManagementObject switchService = NetworkingUtilities.GetEthernetSwitchManagementService(scope))
using (ManagementBaseObject inParams = switchService.GetMethodParameters("DefineSystem"))
{
inParams["SystemSettings"] = switchSettingText;
inParams["ResourceSettings"] = ports;
using (ManagementBaseObject outParams =
switchService.InvokeMethod("DefineSystem", inParams, null))
{
WmiUtilities.ValidateOutput(outParams, scope);
}
}
}
///
/// Entry point for the CreateSwitch sample.
///
/// The command line arguments.
internal static void
ExecuteSample(
string[] args)
{
if (args.Length == 0 || args[0] == "/?")
{
Console.WriteLine("Usage: CreateSwitch Type [ExternalNetwork] [SwitchName] [SwitchNotes]");
Console.WriteLine("Type can be one of the follow: Private, Internal, ExternalOnly, External");
Console.WriteLine("ExternalNetwork must be supplied if the type is ExternalOnly or External");
Console.WriteLine("Example: CreateSwitch External MyNetworkConnection MySwitch \"some notes about the switch\"");
return;
}
try
{
string type = args[0];
if (string.Equals(type, "private", StringComparison.CurrentCultureIgnoreCase))
{
string switchName = (args.Length > 1) ? args[1] : "New Private Switch";
string notes = (args.Length > 2) ? args[2] : null;
CreatePrivateSwitch(switchName, notes);
}
else if (string.Equals(type, "internal", StringComparison.CurrentCultureIgnoreCase))
{
string switchName = (args.Length > 1) ? args[1] : "New Internal Switch";
string notes = (args.Length > 2) ? args[2] : null;
CreateInternalSwitch(switchName, notes);
}
else if (string.Equals(type, "externalOnly", StringComparison.CurrentCultureIgnoreCase) ||
string.Equals(type, "external", StringComparison.CurrentCultureIgnoreCase))
{
if (args.Length == 1)
{
Console.WriteLine("Must supply the external network to connect to.");
Console.WriteLine("Example: CreateSwitch ExternalOnly MyNetwork MySwitch Notes");
return;
}
string switchName = (args.Length > 2) ? args[2] : "New ExternalOnly Switch";
string notes = (args.Length > 3) ? args[3] : null;
if (string.Equals(type, "externalOnly", StringComparison.CurrentCultureIgnoreCase))
{
CreateExternalOnlySwitch(args[1], switchName, notes);
}
else
{
CreateExternalSwitch(args[1], switchName, notes);
}
}
else
{
Console.WriteLine("First parameter must be the type of switch to create: Private, Internal, ExternalOnly, or External");
return;
}
}
catch (Exception ex)
{
Console.WriteLine("Failed to create the switch. Error message details:\n");
Console.WriteLine(ex.Message);
}
}
}
}