Hyper-V: How to remove disabled virtual network adapters from the parent partition
In May, I mentioned that we introduced a checkbox in the Hyper-V UI for Windows 7 and Windows Server 2008 R2 which determines whether a virtual NIC is created in the parent partition for External Virtual Networks. (To get a better understanding of Hyper-V networking and what this means, take a look at this article.)
Many customers follow our best practice of having at least two physical NICs, one for use by the parent partition (aka Management Operating System), and one or more for use by virtual machines. But using the “v1” UI, there’s no option to not have the parent virtual NIC created. Two common ways to resolve this are to disable the virtual NIC it in “Network Connections” on the control panel, or unbinding all protocols from the virtual NIC. The disabling option tends (in my experience) to be the more common choice of the two.
There are, of course, several scripts out there to create what I termed a “dedicated” network (ie one which is dedicated for use only by virtual machines) last year. Ben has a couple of samples here in both VBScript and PowerShell, and Robert has a sample here. These are better approaches to disabling NICs or removing protocol bindings.
To date, I haven’t come across a script which removes disabled virtual NICs in the parent partition. So here is one such example. This will hopefully assist you in being more “compliant” with our best practice recommendations in an existing Hyper-V deployment.
Obviously with any script which does destructive things, I urge caution and that you make careful note of your configuration before running it, and remember the standard disclaimer on my blog.
//
// VirtualSwitchManagementService object. Logical wrapper class for Switch Management Service
//
function
VirtualSwitchManagementService(
Server,
User,
Password
)
{
//
// Define instance fields.
//
this.m_VirtualizationNamespace = null;
this.m_VirtualSwitchManagementService = null;
//
// Instance methods
//
VirtualSwitchManagementService.prototype.DeleteInternalEthernetPort =
function(
InternalEthernetPort
)
/*++
Description:
Deletes an internal ethernet port
Arguments:
InternalEthernetPort - Msvm_InternalEthernetPort to delete
Return Value:
SWbemMethod.OutParameters object.
--*/
{
var methodName = "DeleteInternalEthernetPort";
var inParams = this.m_VirtualSwitchManagementService.Methods_(methodName).inParameters.SpawnInstance_();
inParams.InternalEthernetPort = InternalEthernetPort.Path_.Path;
return this.m_VirtualSwitchManagementService.ExecMethod_(methodName, inParams);
}
//
// Utility functions
//
VirtualSwitchManagementService.prototype.WaitForNetworkJob =
function(
OutParams
)
/*++
Description:
WMI calls will exit with some type of return result. Some will require
a little more processing before they are complete. This handles those
states after a wmi call.
Arguments:
OutParams - the parameters returned by the wmi call.
Return Value:
Status code
--*/
{
if (OutParams.ReturnValue == 4096)
{
var jobStateStarting = 3;
var jobStateRunning = 4;
var jobStateCompleted = 7;
var networkJob;
do
{
WScript.Sleep(1000);
networkJob = this.m_VirtualizationNamespace.Get(OutParams.Job);
} while ((networkJob.JobState == jobStateStarting) ||
(networkJob.JobState == jobStateRunning));
if (networkJob.JobState != jobStateCompleted)
{
throw(new Error(networkJob.ErrorCode,
networkJob.Description + " failed: " + networkJob.ErrorDescription));
}
return networkJob.ErrorCode;
}
return OutParams.ReturnValue;
}
//
// Aggregate functions
//
VirtualSwitchManagementService.prototype.DeleteInternalEthernetPortAndWait =
function(
InternalEthernetPort
)
/*++
Description:
Deletes an internal ethernet port
Arguments:
InternalEthernetPort - Msvm_InternalEthernetPort to delete
Return Value:
SWbemMethod.OutParameters object.
--*/
{
var outParams = this.DeleteInternalEthernetPort(InternalEthernetPort);
var wmiRetValue = this.WaitForNetworkJob(outParams);
if (wmiRetValue != 0)
{
throw(new Error(wmiRetValue, "DeleteInternalEthernetPortAndWait failed"));
}
}
//
// Constructor code
//
if (Server == null)
{
Server = WScript.CreateObject("WScript.Network").ComputerName;
}
//
// Set Namespace fields
//
var locator = new ActiveXObject("WbemScripting.SWbemLocator");
this.m_VirtualizationNamespace = locator.ConnectServer(Server, "root\\virtualization", User, Password);
//
// Set Msvm_VirtualSwitchManagementService field
//
var physicalComputerSystem =
this.m_VirtualizationNamespace.Get(
"Msvm_ComputerSystem.CreationClassName='Msvm_ComputerSystem',Name='" + Server + "'");
var list = physicalComputerSystem.Associators_(
"Msvm_HostedService",
"Msvm_VirtualSwitchManagementService",
"Dependent");
this.m_VirtualSwitchManagementService = list.ItemIndex(0)
}
//
// main
//
var wshShell = WScript.CreateObject("WScript.Shell");
var g_NvspWmi = null;
var g_CimV2 = null;
Main();
function Main()
{
g_NvspWmi = new VirtualSwitchManagementService();
WScript.Echo("Looking for root\\cimv2...");
var locator = new ActiveXObject("WbemScripting.SWbemLocator");
g_CimV2 = locator.ConnectServer("", "root\\cimv2", "", "");
WScript.Echo("");
WScript.Echo("Looking for internal (parent) virtual nics...");
var list = g_NvspWmi.m_VirtualizationNamespace.ExecQuery("SELECT * FROM Msvm_InternalEthernetPort");
for (i = 0; i < list.Count; i++)
{
var next = list.ItemIndex(i);
// find correpsonding Win32_NetworkAdapter
var adapters = g_CimV2.ExecQuery("SELECT * FROM Win32_NetworkAdapter WHERE GUID='" + next.DeviceID + "'");
for (j = 0; j < adapters.Count; j++)
{
var adapter = adapters.ItemIndex(j);
if (adapter.NetEnabled == false)
{
WScript.echo("Deleting '" + next.ElementName + "' because it is disabled.");
g_NvspWmi.DeleteInternalEthernetPortAndWait(next);
}
else
{
WScript.echo("Not deleting '" + next.ElementName + "' because it is enabled.");
}
}
}
WScript.Echo("");
WScript.Echo("Finished!");
}
The script should be saved with a .js extension to run it from the command line. Or you can get it as a text file from here.
One thing I would note is that after running the script, you’ll notice in the “v1” UI when you select an External Virtual Network, the message “This virtual network switch cannot be configured. You might not have permission to perform this task, or it might have been reconfigured in the parent partition” is displayed. This limits your ability to change the network type to an Internal or Private network. However, you can still remove the network if necessary.
Another point to note is that if you are running Hyper-V v1 RTM on Windows Server 2008 SP1, have disabled virtual NICs in the parent partition, then apply Service Pack 2, disabled NICs are re-enabled after applying the service pack. Hence, I would recommend you remove disabled virtual NICs from the parent partition if you have no need for them prior to applying SP2.
And for completeness, if you ever need to completely remove all virtual networks from your system (it crops up as a question every now and then), there’s a useful script you can find here. Obviously though, I recommend extreme caution before running that script.
Cheers,
John.
And again, thanks to Keith for his assistance :)
Comments
Anonymous
January 01, 2003
Greg - a paper is in the process of being published, but for now, you need to refer to documentation supplied by the OEMs themselves. Thanks, John.Anonymous
January 01, 2003
The comment has been removedAnonymous
January 01, 2003
The comment has been removedAnonymous
July 07, 2009
The comment has been removedAnonymous
August 19, 2009
It worked great! I had a disabled virtual network adapter for another reason: I was fiddling with the virtual network stuff, because my VM's would get access to the internet like all other pc's. I tried bridging, one NIC, two NICs, etc. It turned out that the simplest of all setups works. One NIC, one virtual network and no bridge of any kind. So the "best practise" seems bogus to me, because it doesn't allow my VM's to get anywhere on the network. Besides, it would occupy an extra port on the switch, which is nonsense. Anyway, after fiddling, I ended up with a virtual network that doesn't show in the Hyper-V manager, but it does show in the network connections in the control panel. Disabled or enabled doesn't make any difference; Hyper-V thinks it doesn't exist. So, I disabled it. Because logically, I cannot delete it from the network connections, not from the device manager. But this script deleted that useless good for nothing device, so now I have one working virtual network again. Thanks!Anonymous
August 27, 2009
What about NIC teaming in Server Core with Hyper V? I'm finding what Ron mentions above aobut documentation hard to find, scattered, and incomplete. Thanks, GregAnonymous
August 26, 2010
Finally I am rid of that Virtual Switch and can reset my network config! THANK YOU!Anonymous
July 02, 2013
Hi John This script was very useful.. Tried for 3 days manually. But this script done within a second.. ThanksAnonymous
August 20, 2013
Excellent! There were a couple of virtual network switches and connections installed which was annoying. This script helped a lott! Thanks!