Why is there a redundant Restart-NetAdapter cmdlet?

Sometimes you can’t just Enable your way out of a Disable mess

Windows 8 and Windows Server 2012 include a whole set of new PowerShell cmdlets to manage the network stack.  These cmdlets include Enable-NetAdapter and Disable-NetAdapter.  Believe it or not, those two cmdlets let you enable and disable your network adapters, respectively.  Want to shut off networking in a hurry?

PS C:> Disable-NetAdapter *

If that were all you needed to know, these cmdlets would be so obvious, they wouldn’t even be worth writing about.  As you might have guessed from the length of this page, there are actually a few surprises lurking in the void between Enable and Disable.

Surprise 1: You can’t call Enable immediately after Disable

Suppose you want to set a few advanced properties on the NIC named “Ethernet”.  You might write this script:

Set-NetAdapterAdvancedProperty Ethernet -DisplayName 'Flow Control' -DisplayValue Disabled
Set-NetAdapterAdvancedProperty Ethernet –DisplayName 'Jumbo Packet' -DisplayValue Disabled

That’ll work just fine, but it’s a little klunky.  By default, the Set-NetAdapterAdvancedProperty cmdlet restarts the NIC, so the new value takes effect immediately.  But when you set 2 or more properties in a row, the NIC goes through unnecessary restarts.  Recognizing this inefficiency, you might try a new version of the script that coalesces all the restarts to the end:

Set-NetAdapterAdvancedProperty Ethernet -NoRestart -DisplayName 'Flow Control' -DisplayValue Disabled
Set-NetAdapterAdvancedProperty Ethernet -NoRestart –DisplayName 'Jumbo Packet' -DisplayValue Disabled
Disable-NetAdapter Ethernet
Enable-NetAdapter Ethernet

But now you find that that script fails while trying to re-enable the adapter.  What gives?

It turns out that the Disable-NetAdapter cmdlet is asynchronous.  It initiates the disable operation, then returns immediately back to the script, before the adapter is fully disabled.  When the script then tries to call Enable-NetAdapter on the NIC, the Enable cmdlet fails, because the adapter isn’t fully disabled yet.

While you could work around the race by inserting Start-Sleep, there’s a better way: Restart-NetAdapter.  The Restart-NetAdapter cmdlet combines a Disable and an Enable into a single operation.  Restart-NetAdapter ensures that the Enable operation happens as soon as possible, but no sooner.

So Restart-NetAdapter is better than just a script that calls Disable-NetAdapter + Enable-NetAdapter.  Really, the whole is greater than the sum of its parts.

Surprise 2: Wildcard matching doesn’t always work

Update in 2017: MSDN blogs was migrated to Wordpress, which apparently ate all the inline SVG that was here.  Unfortunately, the pictures that accompanied this page are gone for now.  I've left the text.

We saw earlier how a grumpy administrator might try to disable all the NICs on the system with Disable-NetAdapter *.  It seems logical that the proper way to re-enable your NICs is to run Enable-NetAdapter *.  But there’s a subtlety here: the * wildcard doesn't always match the same set of NICs in both commands.  Let’s see what happens if you use NIC Teaming to create a team, then try to disable and re-enable all the NICs.

Initially, both the physical NIC and the Team Interface are enabled:

(Picture: team interface & NIC are both enabled)

Then we run Disable-NetAdapter *, and Windows evaluates the wildcard to both adapters.  Both get disabled:

(Picture: team interface & NIC are both disabled)

But when Microsoft NIC Teaming detects that all member NICs have been disabled, NIC Teaming will remove the entire team:

(Picture: team interface is missing & NIC is disabled)

Now when you run Enable-NetAdapter *, the wildcard matches all adapters: but only one adapter exists!  The cmdlet only enables the physical NIC:

(Picture: team interface is missing & NIC is enabled)

Finally, NIC Teaming notices that one of its member NICs has returned, so NIC Teaming restores the Team Interface(s).  But remember, the last thing we did to the team interface was disable it, so the team interface comes up in a disabled state:

(Picture: team interface is disabled & NIC is enabled)

So as you can see, Enable-NetAdapter * does not completely undo the effects of Disable-NetAdapter *.  What, then, is a good way to do this?  Restart-NetAdapter to the rescue, again.  When you run Restart-NetAdapter *, the wildcard is only evaluated once, so it includes the Team Interface, before the Team Interface is removed.

Bonus surprise: Remote desktop facepalm

Disable-NetAdapter is dangerous when you’re logged in remotely, because if you disable the NIC you were using to connect, you won’t be able to log back in again to re-enable the NIC.  You know that, I know that, everybody knows that.  But we still all make this mistake sooner or later.  (My favorite variant of this story involves a remote kernel debugger and wayward flow control PAUSE frames taking the local network offline, killing the connection to the kernel debugger….)

Anyway, if you have to bounce the NICs, the safest solution is once again to use Restart-NetAdapter.  That’ll still kill your remote connection, but hopefully the NIC will come back up and the connection will be restored automatically.