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.
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.)
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.
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.
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
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") } }
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)
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
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" }
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 {} }
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)
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