Hyper-V: How to unbind a physical NIC from a Virtual Switch using WMI and PowerShell

If youre not already familiar with networking in Microsoft Hyper-V I would recommend you to have a look at this whitepaper from Microsoft, which described how networking works in Hyper-V.

The following solution will describe a problem which might occur when configuring virtual networks in Hyper-V. Consider the following scenario:

  • Youre about to configure a new external virtual network in Hyper-V using Hyper-V Manager remotely from another computer. This is a common scenario when working with the Core edition of Windows Server 2008/2008 R2.
  • When selecting the physical NIC to bind to the new virtual network, you choose the adapter which you are remotely connecting to the Hyper-V host through.

What happens in this scenario is that the Virtual Switch Management Service is binding the external Ethernet port for the selected NIC to the Microsoft Windows Virtualization network subsystem. What normally should happen next is that the converted Ethernet port should be bound to the new virtual switch you are creating. However, this never happens since the NIC you are remotely managing the Hyper-V host through is no longer available in the parent operating system. This leaves the NIC in an “orphaned” state, since you cannot use the NIC in the parent operating system, and its not in use by any virtual networks.

To resolve this issue, whether using the full GUI version or the Core version of Windows Server, you need to manually unbind the the Ethernet port. There is an UnbindExternalEthernetPort available on the Msvm_VirtualSwitchManagementService WMI class, which is fully documented in this article on MSDN.

To invoke the WMI method we can use Windows PowerShell. To ease the procedure Ive created a PowerShell function you can use if you ever come into the need for manually unbinding an external Ethernet port in Hyper-V:

Function Select-List
{
    Param   ([Parameter(Mandatory=$true  ,valueFromPipeline=$true )]$InputObject, 
             [Parameter(Mandatory=$true)]$Property)

    begin   { $i= @()  }
    process { $i += $inputobject  }
    end     { if ($i.count -eq 1) {$i[0]} elseif ($i.count -gt 1) {
                  $Global:counter=-1
                  $Property=@(@{Label=“ID”; Expression={ ($global:Counter++) }}) + $Property
                  format-table -inputObject $i -autosize -property $Property | out-host
                 $Response = Read-Host “Select NIC to unbind”
                  if ($response -gt “”) { 
                        $I[$response] 
                  }
              }
            }
}

function Remove-HVExternalEthernetPort {

$ExternalEthernetPort = Get-WMIObject -class “Msvm_ExternalEthernetPort” -namespace “rootvirtualization” | Select-List -Property name

$HVSwitchObj = Get-WMIObject -class “MSVM_VirtualSwitchManagementService” -namespace “rootvirtualization”

if ($ExternalEthernetPort) {
$HVSwitchObj.UnbindExternalEthernetPort($ExternalEthernetPort)
}
else {
throw “An error occured. Choose a valid ExternalEthernetPort from the provided list”
}

}

Note: The Select-List function is a modified version of the Select-List function available in the PowerShell Management Library for Hyper-V available on CodePlex (see link below).

You can either paste the function into a PowerShell session or save it into ps1-file and dot source it. When done you can invoke the function like this:

image

When you`ve entered the index number for the NIC you want to remove, a return value of 0 indicates the operation succeeded. Any other value indicates an error (look at the previous mentioned MSDN-article for more information).

More resources on managing Hyper-V using PowerShell

PowerShell Management Library for Hyper-V – this is an excellent PowerShell module for managing Hyper-V available on CodePlex

System Center Virtual Machine Manager 2012: Scripting

System Center Virtual Machine Manager 2008 R2: Scripting

Hyper-V WMI Using PowerShell Scripts

Script: Determining Virtual Switch Type Under Hyper-V

How to automatically convert Windows PowerShell transcripts into script-files

In Windows PowerShell we can use the Start-Transcript cmdlet to record PowerShell sessions to a text-file. This will record both the commands youve run as well as the output from the commands.

Windows PowerShell MVP Jeffery Hicks recently wrote a great tip in his Friday Fun series on his blog, which tells you how to convert a PowerShell transcript into a PowerShell script file. That is, youll get a ps1-file which contains the commands extracted from the transcript. Combined with an object event which triggers when PowerShell exits, this can be set up to happen automatically. Jeff actually blogged another Friday Fun tip a couple years ago which describes how to set up such an object event.

Lets have a look at an example on how this would work. First we launch a new PowerShell session and executes a few commands:

image

 

When we exit PowerShell well get two files in a specified log directory:

image

 

The transcript file (txt-file) contains all commands, errors and output from our session:

image

 

The PowerShell script file (ps1-file) contains a script header and the commands from our session:

image

 

This means that every PowerShell session automatically generates a PowerShell script file which can be the foundation for a new script.

To set this up you first need to copy the Export-Transcript PowerShell function from Jeffs blog-post and add it to your PowerShell profile (Microsoft.PowerShell_profile.ps1), in addition to the following:

 

001
002
003
004
005
006
007
008
009
#Define variable for the transcript path, which well use to generate the path to the ps1-file
$transcriptlog = ("C:PS-logsPS-Transcript_"+"{0:yyyy-MM-dd_HH-mm-ss}" -f (Get-Date)+".txt")
Start-Transcript -Path $transcriptlog | Out-Null

#Export transcript to ps1-file on exit
Register-EngineEvent PowerShell.Exiting –action {
Stop-Transcript
Export-Transcript
 -Transcript $transcriptlog -Script (($transcriptlog.Replace("Transcript","Script")).Replace("txt","ps1"
))
} 
| Out-Null

 

While this is very useful, there is a few gotchas to be aware of:

  • This doesnt work if your exiting PowerShell using the X button. The PowerShell.Exiting event is only triggered when using the exit command.
  • This doesnt work in the Windows PowerShell ISE, since that PowerShell host doesnt support transcripts.
  • If youve customized your PowerS
    hell prompt, you`ll need to tweak the Export-Transcript function to match the last letter in your prompt.