Weekend Scripter: Use PowerShell to Manage Windows Network Locations

Weekend Scripter: Use PowerShell to Manage Windows Network Locations

  • Comments 5
  • Likes

Summary: Guest blogger, Microsoft PFE, Chris Wu, shows how to use Windows PowerShell to manage Windows network locations.

Microsoft Scripting Guy, Ed Wilson, is here. Today we have another guest blog by my good friend Microsoft premier field engineer (PFE), Chris Wu.

Chris started his career at Microsoft in 2002, first as a support engineer in the Microsoft Global Technical Support Center in China to support the various components of the base operating system. Now he works as a premier field engineer (PFE) in Canada, and he specializes in platform and development support. During the course of troubleshooting, performance tuning, and debugging, he has created many utilities to ease and facilitate the process by leveraging various programming languages, such as C, C++, and C#. Windows PowerShell has become his new favorite.

Photo of Chris Wu

OK Chris, the keyboard is all yours…

Understanding Windows network locations

One feature that Windows 7 inherits from Windows Vista is network location awareness, which enables applications to sense changes to the network that the computer is connected to and then behave accordingly. Two applications in this feature are the network location-aware host firewall, and location-aware printing.

Two services play a key role in implementing the feature: the Network Location Awareness service and the Network List Service (which depends on the former). Collaboratively they keep a record of all the network locations that the computer has ever connected to, remember the associated location category (domain, or public vs. private per a user’s selection), apply Windows Firewall and default printer settings, and send network location awareness notifications.

In my opinion, network location awareness is a neat feature that is currently underutilized. Maybe partially it is because the managing interface is a little hard to reach.

It’s not difficult to open the Network and Sharing Center console in Control Panel to figure out the current network location name and location category (highlighted in yellow in the following image). Users can also click the category text (Public network in this case) to switch between public and private. (The domain location category is automatically applied.)

Image of menu

However, some users may fail to realize that the network icon (highlighted in red in the previous image) is also clickable, which leads to a Set Network Properties console. This console is shown in the image that follows.

Image of menu

This console gives users an option to change the network location’s name. In addition, it allows users to manage location history through a console, which is accessible through the Merge or delete network locations link. The Manage Location History console is shown in the following image.

Image of console 

Unfortunately, the Set Network Properties and Manage Location History consoles are not visible in Control Panel, which may leave some users out in the cold.

Using Windows PowerShell to manage network locations

Now, with the background knowledge about Windows network locations covered, it’s time to explore how to manage network locations by using Windows PowerShell.

The Network List Manager (NLM) infrastructure is exposed through the Network List Manager API, which is not easy to use directly from within Windows PowerShell scripts. Fortunately, a managed module is available on MSDN as part of Microsoft Windows Network List Manager Samples. Simply download the zip file and extract the Interop.NETWORKLIST.dll file from the obj\Debug folder, and we will be ready to roll.

Now that the prep work is complete, we see how we can do some common tasks quite easily. A few of the more common tasks are illustrated here.

Use the following script to get a list of network locations that the computer has ever connected to:

  Add-Type –Path .\Interop.NETWORKLIST.dll

  $nlm = new-object NETWORKLIST.NetworkListManagerClass

  $nlm.GetNetworks("NLM_ENUM_NETWORK_ALL") | select @{n="Name";e={$_.GetName()}},@{n="Category";e={$_.GetCategory()}},IsConnected,IsConnectedToInternet

Image of command output

The category property indicates if the network location is a Public, Private, or Domain network. Its value can be one of the NLM_NETWORK_CATEGORY enumerations (0 = Public, 1 = Private).

Use the following script to change the name of a disconnected network:

 $nlm.GetNetworks(2) | % { if ($_.GetName() –eq "EIA_FREE_WIFI") { $_.SetName("EIA") } }

Image of command output

In this example, we use an integer value instead of a string representation of NLM_ENUM_NETWORK enumeration as expected by the GetNetworks() method.

Use the following script to change a currently connected location’s category from public to private:

  $net = $nlm.GetNetworks("NLM_ENUM_NETWORK_CONNECTED") | select -first 1

  $net.SetCategory(1)

Image of command output

A computer may connect to multiple networks, so in the previous example, we use the Select-Object cmdlet to choose the first connected network location, and then change its category to 1 = Private.

Use the following script to list active connections:

  $nlm.GetNetworkConnections() | select @{n="Connectivity";e={$_.GetConnectivity()}}, @{n="DomainType";e={$_.GetDomainType()}}, @{n="Network";e={$_.GetNetwork().GetName()}}, IsConnectedToInternet,IsConnected

Image of command output

The previous command can list all active connections, which may be useful for applications to find out through which network the computer gets Internet connectivity.

Use the following script to register a ConnectivityChanged event:

  $nlm | gm –MemberType Event

  Register-ObjectEvent –InputObject $nlm –EventName ConnectivityChanged –Action { write-host "Connectivity Changed: $args" }

Image of command output

NLM allows applications to register for events. One example is the ConnectivityChanged event. Notice that the event passes NLM_CONNECTIVITY enumerations as the argument. In the previous image, 576 is a bitwise of two flags: NLM_CONNECTIVITY_IPV6_LOCALNETWORK and NLM_CONNECTIVITY_IPV4_INTERNET.

Use the following script to monitor a connectivity change per network:

  Register-ObjectEvent -InputObject $nlm -EventName NetworkConnectivityChanged -Action { try { if($nlm.GetNetwork($args[0]).GetName() -match "YOW") { write-host ("YOW is now:" + $args[1]) } } catch {} }

Image of command output

The NetworkConnectivityChanged event might be more useful than the ConnectivityChanged event, because it takes two arguments—one of which can tell us the network location of interest. Through this event, a Windows PowerShell script (preferably, it runs in the background) can possibly achieve real network location awareness. Imagine how exciting (or scary) it is to have a script that closes all productivity applications and launches Diablo 3 whenever your laptop is taken home.

Before concluding this blog, I would like to point out that the Interop.NETWORKLIST.dll library used in this blog serves as a .NET wrapper of NLM API, which are exposed as COM objects. They are accessible directly from Windows PowerShell, so it is not always necessary to use the DLL (although it does provide easier access to such features as events). For instance, this code snippet can also change the category of the current connected network location:

  $nlm2 = [Activator]::CreateInstance([Type]::GetTypeFromCLSID('DCB00C01-570F-4A9B-8D69-199FDBA5723B'))

  $net = $nlm2.GetNetworks(1) | select -first 1

  $net.SetCategory(1)

Image of command output

As useful as it is, the NLM API seems to have limitations too. After reading through its API reference, I still fail to find a way to delete a cached network location like we can do in the Merge or Delete Network Locations console. If anyone can point out a way, I would really appreciate it.

~Chris

Thank you, Chris!  This was a really interesting and instructive guest blog.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment
  • <p>Hey, </p> <p>Thanks for the excellent intro to NLM.</p> <p>I was looking for something apparently related to NLM, the Media Streaming options per network location.</p> <p>Do you happen to know how to change it programmatically, either via powershell or .Net?</p> <p>Thank you</p>

  • <p>@Joaopbnogueria I hope Chris will jump in here, because he wrote the article. But if I had to guess, I would say it could be done via the Window Firewall API. If, so, then you would have two options in Windows 7 the COM api, or Netsh. In Windows 8 with PowerShell 3 you would also have firewall cmdlets. But this is just a guess. You may also want to ask your question over on the Scripting Guys Forum.</p>

  • <p>Good article. This comes up frequently. &nbsp;Users are trying to figure out how to manage all of the networks now that Wi-FI is everywhere.. &nbsp;I have done a lot of wireless but I am not a big Wi-Fi user. &nbsp;Every bit of new info is very helpful.</p>

  • <p>There is now clearly a complete divergence between The Scripting Guy&#39;s Blog and The WeekEnd Scripter. &nbsp;There is also a new lack of ability to comment on TSGB. &nbsp;There is no comment box or &lt;comments&gt; field. &nbsp;What?</p> <p>The new blog looks better. &nbsp;The edit box is less of an issue. Why are things now mysteriously dissappearing?</p> <p>My comment should you choose to accept it is; WQL Comparison operators &quot;like&quot;....</p>

  • A nicer way to grab a handle to NLM rather than downloading a random DLL: $networkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}")) Found via a comment here: http://blogs.msdn.com/b/powershell/archive/2009/04/03/setting-network-location-to-private.aspx