I thought I knew a lot about Network Policy Server (NPS). The last few months have taught me differently. It started with my mad grab to enable AD authentication on any network device that supports it. Next, I got the joyful job of wading into the world of wireless. Alliteration aside, this led to a complete overhaul of our wireless infrastructure. By using NPS, our environment now uses a single SSID that dynamically VLANs objects based on how they authenticate.*
Both of these projects had their fair share of problems to overcome. Let’s talk about two tricks today; one learned from each project. The first makes NPS easier to manage by simplifying clients. The second makes NPS easier to manage by increasing redundancy.
Trick 1: RADIUS Client Subnets
Many network administrators group devices by their type and IP. For example, all network switches in at a site might be in a dedicated range or a specific portion of a subnet. When creating RADIUS clients, think about how the clients can be grouped. In the screenshot below, you can see two clients. The first IP address is actually a range. My 10.94 IP range actually a /20 at that site. All of my switches though are located in the first 254 addresses. The second IP address show how clients used to be managed – one IP at a time.
I now use the single RADIUS client IP of 10.94.0.0/24 to allow authentication to all of my switches at that site. If I add a new switch at that location, I don’t have to remember to also create a RADIUS client for it because it is automatically included.
If another type of device happens to be in that range, no big deal. For any kind of a security risk, that device would have to be:
- Attempting to authenticate against my network policy server
- have the correct shared secret for this RADIUS client
Using IP ranges instead of single IP addresses makes RADIUS client management so much easier!
Trick 2: Syncing Network Policy Server Settings Between Two Servers
Having all of this fancy authentication is of little good if your Network Policy Server is offline. To be redundant, you need a second server running NPS with your RADIUS clients configured to contact it as a backup service. For switches, this is as simple as adding a separate radius-server host command in your configuration. HP Switches, at least, contact RADIUS servers in a top – bottom order in their configuration. Other devices typically allow you to specify multiple RADIUS entries in their web interface.
The next step is to keep your servers in sync with each other.** PowerShell makes this incredibly easy. Copy the below script, written by JGrote, and save it on your secondary Network Policy Server. Be sure to configure the two variables under the ###Variables section.
###Network Policy Server Synchronization Script #This script copies the configuration from the NPS Master Server and imports it on this server. #The Account that this script runs under must have Local Administrator rights to the NPS Master. #This was designed to be run as a scheduled task on the NPS Secondary Servers on an hourly,daily, or as-needed basis. #Last Modified 01 Dec 2009 by JGrote <jgrote AT enpointe NOSPAM-DOTCOM> ###Variables #NPSMaster - Your Primary Network Policy Server you want to copy the config from. $NPSMaster = "NPS1.Test.local" #NPSConfigTempFile - A temporary location to store the XML config. Use a UNC path so that the primary can save the XML file across the network. Be sure to set secure permissions on this folder, as the configuration including pre-shared keys is temporarily stored here during the import process. $NPSConfigTempFile = "\\NPS1.Test.local\C$\NPSConfig-$NPSMaster.xml" #Create an NPS Sync Event Source if it doesn't already exist if (!(get-eventlog -logname "System" -source "NPS-Sync")) {new-eventlog -logname "System" -source "NPS-Sync"} #Write an error and exit the script if an exception is ever thrown trap {write-eventlog -logname "System" -eventID 1 -source "NPS-Sync" -EntryType "Error" -Message "An Error occured during NPS Sync: $_. Script run from $($MyInvocation.MyCommand.Definition)"; exit} #Connect to NPS Master and export configuration $configExportResult = invoke-command -ComputerName $NPSMaster -ArgumentList $NPSConfigTempFile -scriptBlock {param ($NPSConfigTempFile) netsh nps export filename = $NPSConfigTempFile exportPSK = yes} #Verify that the import XML file was created. If it is not there, it will throw an exception caught by the trap above that will exit the script. $NPSConfigTest = Get-Item $NPSConfigTempFile #Clear existing configuration and import new NPS config $configClearResult = netsh nps reset config $configImportResult = netsh nps import filename = $NPSConfigTempFile #Delete Temporary File remove-item -path $NPSConfigTempFile #Compose and Write Success Event $successText = "Network Policy Server Configuration successfully synchronized from $NPSMaster. Export Results: $configExportResult Import Results: $configImportResult Script was run from $($MyInvocation.MyCommand.Definition)" write-eventlog -logname "System" -eventID 1 -source "NPS-Sync" -EntryType "Information" -Message $successText
Create a scheduled task on your secondary server that calls powershell.exe with this script as a parameter. The screenshot below shows the syntax for this action. Set the task to run on a regular schedule. Our environment syncs once per day.
The account running this task needs Modify/Read permissions to the NPSConfigTempFile variable location as well as the ability to read the primary Network Policy Server configuration. Once setup, run the task and ensure that your primary configuration syncs to your secondary server.
Your environment now has a secondary server running NPS that will authenticate any client created on your primary server! Do you have any other tips for managing NPS?
*My goal with any article is to help the most amount of people possible. This means I don’t often write about specific technologies or products. If anyone would like more information about this, just leave a comment or shoot me an email.
**I wanted to make a boy band joke here so bad. Any suggestions?
@ Thomas: instead of adding extra snippets of script to maintain the config in the event that the master NPS server is not available just comment out the line (line 25?) that reads “netshell nps reset config”. I tested this with Srv2012 and it works, maintaining the config on the secondary even if the master is gone. You can also add entries to the secondary server and they get overwritten when the master NPS comes back online without otherwise affecting the availablity of the service.
The top part I have in production and works great. My issue is I recently started using Radius within Cisco small business switches to allow our admin team to use their familiar user name and password.
The issue is the switches for whatever reason refuse to use the blanked subet rule, I had to add each IP independantly, I am at a loss as to why, and I hate having all these individual IP’s.
Any thought would be appreciated.
What about connection request policy configuration when you use subnet range with radius clients?
Can you please the snapshot of the connection request policy which works with this?
correction!
What about connection request policy configuration when you use subnet range with radius clients?
Can you please share the snapshot of the connection request policy which works with this?
Hello,
Thank you for this very helpful article. Can you please update the script to check to see if the primary NPS server is reachable? I have found that if the primary NPS server is unreachable when the script runs all settings on the secondary NPS servers are erased.
I added this line to my Script:
“If ($NPSConfigTest.Length -lt 10000) {write-eventlog -logname “System” -eventID 1 -source “NPS-Sync” -EntryType “Error” -Message “An Error occured during NPS Sync: XML File was too Small: $_. Script run from $($MyInvocation.MyCommand.Definition)”; exit}”
It counts the number of chars in the XML file and if its less than 10k it writes an error and exits. I’m just starting out with NPS and my original .XML file was 78K in length so this should be a safe number.
This was a great article. I’m especially interested in the part “By using NPS, our environment now uses a single SSID that dynamically VLANs objects based on how they authenticate.” could you tell me how you set that up? I’m looking to do that with our wired network. right now the conference room ports are open and that drives me NUTZ. I want to make all ports guest ports by default, and if the connected device is a domain PC, RADIUS server will authenticate (maybe using 802.1x) and sort them into the internal VLAN. For external PCs they would stay on the guest VLAN. How do you set that up?
You are right on the money! You will want to use 802.1x for this. Your switch ports will have two vlans configured (internal and public). If computers/users have a cert from your CA, they will hit the internal NPS rule first. If not, they are placed in the public vlan. What type of switches do you have?
Thanks for preserving this and presenting it so clearly. I tried running it on a Windows 2016 Server and it opens PowerShell and then closes, and nothing is synched. Do you have any modifications or tips to deploy this happiness in a Server 2016 environment?
Powershelll does not run unsigned scripts by default. it’s a security thing. you have to implicitly give it permission.
http://windowsitpro.com/powershell/running-powershell-scripts-easy-1-2-3
https://stackoverflow.com/questions/10635/why-are-my-powershell-scripts-not-running
Try typing this:
set-executionpolicy remotesigned
That will tell PowerShell to allow local (that is, on a local drive) unsigned scripts to run.
And thanks for the tips! If I ever get time, I have a powershell security/signing post to finish that ties into this.
For your 1st question (filtering by OU), change the last foreach loop to the code below. You will need to change the OU specified below to your OU. If you have multiple OUs, you would need an If statement for each OU.
foreach ($NetLogonErrorsObject in $NetLogonErrorsObjects.ComputerName){
if ((Get-ADComputer -Identity $NetLogonErrorsObject -Properties CanonicalName | select -ExpandProperty CanonicalName) -match "TEST.local/Sites/Computers"){
if (((Get-ADComputer -Identity $NetLogonErrorsObject -Properties * | select -ExpandProperty PasswordLastSet) -gt $DateToStartSearch) -eq $False){
Send-MailMessage -SmtpServer $SMTPServer -From $From -to $To -Subject $Subject -Body $NetLogonErrorsObject
}
}
}
Excellent work. The only thing you may want to add to the article is to import the shared secrets from the master on the secondary server. I had to right click Templates Management and import templates from a computer and import from the master to get the shared secrets on the secondary server. After that all is well running windows 2012 R2. We also use Aerohive and HP access points.
Good tip Shawn! That little step makes a big difference. 🙂
* Yes please!
Excellent article once again, It’s always surprised me that NPS never had any “out of the box” sync.
Thank you Jeff!
In brief, our wireless setup is aerohive APs (but I am sure many other vendors can suppport this). We have a single SSID that has multiple user profiles (aerohive term) associated with it. Each profile has a VLAN ID associated with it.
The really cool thing happens in NPS though. I have multiple network policies listed in order from most restrictive to least. I configure an additional attribute on each (under advanced) named Tunnel-PVT-Group-ID. This attribute is configured with the VLAN ID mentioned above. When a device authentication matches against a policy, that attribute is passed back to the Aerohive AP which then knows what VLAN to put the device on.