How to Configure Network Policy Server (NPS/RADIUS) on Windows Server 2025
Network Policy Server (NPS) is Microsoft’s implementation of the Remote Authentication Dial-In User Service (RADIUS) protocol, built into Windows Server 2025. NPS acts as the central authentication, authorization, and accounting (AAA) broker for network access requests originating from VPN gateways, wireless access points (802.1X), wired switches, and RD Gateway. Rather than embedding user authentication logic directly in each network device, those devices forward credentials to NPS, which validates them against Active Directory and applies centrally managed access policies. This tutorial covers a complete NPS/RADIUS deployment: installing the role, configuring RADIUS clients, building Connection Request Policies and Network Policies with EAP-TLS and PEAP, configuring NPS accounting logs, setting up an NPS proxy for forwarding, and validating the configuration with a VPN client and event log review.
Prerequisites
- Windows Server 2025 member server or domain controller (dedicated NPS server recommended for production)
- Active Directory domain with user accounts in appropriate security groups
- Domain Admin or local Administrator credentials on the NPS server
- Network devices (VPN gateway, WAP controller, or managed switch) that support RADIUS
- PKI infrastructure (Active Directory Certificate Services) for EAP-TLS authentication — optional for PEAP/MSCHAPv2
- PowerShell 5.1 or later
Step 1: Install the Network Policy and Access Services Role
NPS is part of the Network Policy and Access Services (NPAS) server role. Install it with management tools using PowerShell or Server Manager.
# Install NPS role with management tools and optional RRAS (for VPN on the same server)
Install-WindowsFeature -Name NPAS -IncludeManagementTools -IncludeAllSubFeature
# Verify installation
Get-WindowsFeature -Name NPAS* | Select-Object Name, InstallState, DisplayName
# Confirm NPS service is running
Get-Service -Name IAS | Select-Object Name, Status, StartType
# Start the NPS service if not already running
Start-Service -Name IAS
Set-Service -Name IAS -StartupType Automatic
# Register NPS in Active Directory (required to read dial-in properties of user accounts)
# Must be run with Domain Admin privileges
netsh nps add registeredserver domain=contoso.com server=$env:COMPUTERNAME
# Alternative PowerShell approach using NPS cmdlets
# Register server in domain so it can access AD user attributes
Register-NpsServer -Domain "contoso.com" -Server $env:COMPUTERNAME
Step 2: Configure RADIUS Clients
A RADIUS client is any network device (VPN gateway, wireless controller, managed switch) that sends RADIUS Access-Request messages to the NPS server. Each client must be registered in NPS with its IP address and a shared secret. The shared secret is used to sign RADIUS messages and must match the configuration on the network device.
# Add a RADIUS client via PowerShell
# Example: Cisco ASA VPN gateway at 192.168.1.1
New-NpsRadiusClient `
-Name "Cisco-ASA-VPN" `
-Address "192.168.1.1" `
-SharedSecret "UseALongRandomSharedSecretHere_64chars" `
-AuthAttributeRequired $false `
-VendorName "Cisco"
# Add a wireless access point controller
New-NpsRadiusClient `
-Name "Aruba-WLC-01" `
-Address "10.10.10.5" `
-SharedSecret "AnotherStrongSecret_64charsMinimum" `
-VendorName "Hewlett Packard Enterprise"
# Add a range of clients using a subnet (NPS supports /24 notation)
New-NpsRadiusClient `
-Name "Branch-Switches" `
-Address "10.20.0.0/24" `
-SharedSecret "BranchSwitchSharedSecret_AtLeast22chars"
# List all configured RADIUS clients
Get-NpsRadiusClient | Select-Object Name, Address, VendorName, Enabled
# Generate a cryptographically random shared secret (recommended practice)
$sharedSecret = -join ((65..90) + (97..122) + (48..57) |
Get-Random -Count 64 |
ForEach-Object { [char]$_ })
Write-Host "Generated shared secret: $sharedSecret"
Step 3: Configure Connection Request Policies
Connection Request Policies (CRPs) determine how NPS handles an incoming RADIUS Access-Request: process it locally against AD, or forward it to a remote RADIUS server (proxy). CRPs are evaluated in priority order; the first matching policy wins.
# Create a Connection Request Policy for VPN authentication (processed locally)
New-NpsConnectionRequestPolicy `
-Name "VPN-ConnectionRequestPolicy" `
-State "Enabled" `
-Priority 10
# Add condition: NAS-Port-Type must be Virtual (for VPN connections)
# NAS-Port-Type values: Wireless-IEEE-802.11 = 19, Virtual = 5, Ethernet = 15
Add-NpsConnectionRequestPolicyCondition `
-PolicyName "VPN-ConnectionRequestPolicy" `
-AttributeName "NAS-Port-Type" `
-AttributeValue "Virtual"
# Create a Connection Request Policy for 802.1X Wireless
New-NpsConnectionRequestPolicy `
-Name "Wireless-802.1X-ConnectionRequestPolicy" `
-State "Enabled" `
-Priority 20
Add-NpsConnectionRequestPolicyCondition `
-PolicyName "Wireless-802.1X-ConnectionRequestPolicy" `
-AttributeName "NAS-Port-Type" `
-AttributeValue "Wireless-IEEE-802.11"
# Verify policies
Get-NpsConnectionRequestPolicy | Select-Object Name, State, Priority |
Sort-Object Priority
Step 4: Configure Network Policies
Network Policies define whether an authenticated user is granted or denied access, and what connection parameters (VLAN assignment, session timeout, encryption strength) are applied. Conditions are evaluated after the CRP matches; the first matching Network Policy with a Grant Access result determines the outcome.
# Create a Network Policy granting VPN access to members of the VPN-Users AD group
New-NpsNetworkPolicy `
-Name "VPN-GrantAccess" `
-State "Enabled" `
-Priority 10 `
-AccessType "Grant"
# Add condition: Windows group membership
Add-NpsNetworkPolicyCondition `
-PolicyName "VPN-GrantAccess" `
-AttributeName "Windows-Groups" `
-AttributeValue "CONTOSOVPN-Users"
# Add constraint: Authentication method must be PEAP (MSCHAPv2) or EAP-TLS
# For PEAP with MSCHAPv2 (password-based, requires server certificate)
Set-NpsNetworkPolicy -Name "VPN-GrantAccess" `
-AuthenticationTypes @("PEAP")
# For certificate-based EAP-TLS (most secure — client + server certificates required)
# Set-NpsNetworkPolicy -Name "VPN-GrantAccess" -AuthenticationTypes @("EAP")
# Create a Network Policy for 802.1X wireless users in CorpWifi-Users group
New-NpsNetworkPolicy `
-Name "Wireless-CorpUsers-GrantAccess" `
-State "Enabled" `
-Priority 20 `
-AccessType "Grant"
Add-NpsNetworkPolicyCondition `
-PolicyName "Wireless-CorpUsers-GrantAccess" `
-AttributeName "Windows-Groups" `
-AttributeValue "CONTOSOCorpWifi-Users"
# Add a RADIUS attribute to assign VLAN 100 to wireless corporate users
Add-NpsNetworkPolicyAttribute `
-PolicyName "Wireless-CorpUsers-GrantAccess" `
-AttributeName "Tunnel-Type" `
-AttributeValue "VLAN"
Add-NpsNetworkPolicyAttribute `
-PolicyName "Wireless-CorpUsers-GrantAccess" `
-AttributeName "Tunnel-Medium-Type" `
-AttributeValue "802"
Add-NpsNetworkPolicyAttribute `
-PolicyName "Wireless-CorpUsers-GrantAccess" `
-AttributeName "Tunnel-Pvt-Group-ID" `
-AttributeValue "100"
# List all network policies
Get-NpsNetworkPolicy | Select-Object Name, State, Priority, AccessType |
Sort-Object Priority
Step 5: Configure NPS Accounting Logs
NPS accounting logs record authentication attempts, session starts/stops, and accounting data. These logs are essential for security auditing, troubleshooting, and billing. NPS supports logging to local text files, a SQL Server database, or Windows Event Log.
# Configure NPS accounting to log to local files
# Log directory must exist and NPS service account must have write access
$logDir = "C:NPS_Logs"
New-Item -Path $logDir -ItemType Directory -Force
# Configure accounting via NPS XML configuration
# Export current NPS config for reference
netsh nps export filename="C:NPS_Backupnps_backup_$(Get-Date -Format 'yyyyMMdd').xml" exportPSK=YES
# Set logging options via netsh
netsh nps set accounting logauthentication=yes logaccounting=yes logperiod=Daily `
logfile="$logDirNPS_YYYYMMDD.log" maxfilesize=20 maxlogfileage=30
# Enable Windows Event Log authentication logging
netsh nps set accounting logwinauth=yes
# View recent NPS authentication events
Get-WinEvent -LogName "Security" -FilterXPath `
"*[System[(EventID=6272 or EventID=6273 or EventID=6274 or EventID=6275 or EventID=6276 or EventID=6277)]]" |
Select-Object TimeCreated, Id,
@{N='Reason'; E={$_.Properties[8].Value}},
@{N='User'; E={$_.Properties[1].Value}},
@{N='Client'; E={$_.Properties[9].Value}} |
Sort-Object TimeCreated -Descending |
Select-Object -First 25
# Event IDs:
# 6272 = Network Policy Server granted access
# 6273 = Network Policy Server denied access
# 6274 = Network Policy Server discarded request
# 6278 = Network Policy Server granted full access (after quarantine)
Step 6: Configure NPS as a RADIUS Proxy
NPS can act as a RADIUS proxy, forwarding authentication requests to a remote RADIUS server based on the realm (username suffix). This is useful for multi-domain environments, outsourced authentication, or when forwarding requests from perimeter network devices to an internal NPS cluster.
# Configure NPS proxy: forward requests for [email protected] to a remote RADIUS server
# Step 1: Create a Remote RADIUS Server Group
New-NpsRemoteRadiusServerGroup -Name "Partner-RADIUS-Group"
# Step 2: Add the remote RADIUS server to the group
Add-NpsRemoteRadiusServer `
-AuthServerGroup "Partner-RADIUS-Group" `
-Name "partner-radius.partner.com" `
-AuthServerAddress "203.0.113.50" `
-AuthenticationPort 1812 `
-AccountingPort 1813 `
-SharedSecret "PartnerSharedSecret_AtLeast64chars_Random" `
-Priority 1 `
-Weight 50
# Step 3: Create a Connection Request Policy that matches the realm and forwards
New-NpsConnectionRequestPolicy `
-Name "Forward-PartnerRealm" `
-State "Enabled" `
-Priority 5 # Higher priority than local policies
# Add condition matching the User-Name suffix
Add-NpsConnectionRequestPolicyCondition `
-PolicyName "Forward-PartnerRealm" `
-AttributeName "User-Name" `
-AttributeValue ".*@partner.com$" # Regex match
# Configure the policy to forward to the remote group rather than authenticate locally
Set-NpsConnectionRequestPolicy `
-Name "Forward-PartnerRealm" `
-ForwardRequest $true `
-RemoteRadiusGroup "Partner-RADIUS-Group"
Write-Host "Proxy configuration complete. Requests for @partner.com will be forwarded."
Step 7: Test NPS Authentication
After configuration, validate that NPS is correctly authenticating users before connecting live network devices. Use the built-in radtest-equivalent approach on Windows or test with a VPN client connecting through the configured RADIUS gateway.
# Test NPS authentication using NTRadPing or the built-in NPS test utility
# Install Network Monitor or use PowerShell to send a test RADIUS request
# Method 1: Trigger a test authentication via netsh
netsh nps show config
# Method 2: Review NPS diagnostic logs during a test VPN connection attempt
# Enable NPS tracing for detailed diagnostic output
netsh nps set tracing state=enabled maxfilesize=20 logfile="C:NPS_LogsNPS_Trace.log"
# Reproduce the failing connection, then review the trace
Get-Content "C:NPS_LogsNPS_Trace.log" | Select-Object -Last 100
# Disable tracing after debugging (tracing generates large files)
netsh nps set tracing state=disabled
# Method 3: Monitor NPS events in real time during testing
$events = @(6272, 6273, 6274, 6276, 6278)
Get-WinEvent -LogName Security -MaxEvents 50 |
Where-Object { $_.Id -in $events } |
Select-Object TimeCreated, Id, Message |
Sort-Object TimeCreated -Descending
# Quick summary of recent access grants vs. denials
Get-WinEvent -LogName Security -MaxEvents 200 |
Where-Object { $_.Id -in @(6272, 6273) } |
Group-Object Id |
Select-Object @{N='Event'; E={ if ($_.Name -eq 6272) { "Granted" } else { "Denied" } }},
Count
Step 8: Harden the NPS Configuration
A few additional hardening steps protect the NPS infrastructure itself from abuse:
# Restrict NPS management to specific admin groups
# Ensure only authorized admins can modify NPS policies
$npsAdmins = "CONTOSONPS-Admins"
$npsSvcPath = "HKLM:SYSTEMCurrentControlSetServicesIAS"
# Audit NPS service account permissions
Get-Acl -Path $npsSvcPath | Format-List
# Export NPS configuration for backup and change management
$backupPath = "C:NPS_Backupnps_config_$(Get-Date -Format 'yyyyMMddHHmm').xml"
netsh nps export filename="$backupPath" exportPSK=YES
Write-Host "NPS configuration backed up to: $backupPath"
# Verify shared secrets meet minimum complexity (64+ chars, random)
# Audit RADIUS clients for weak shared secrets
Get-NpsRadiusClient | Select-Object Name, Address |
ForEach-Object {
Write-Host "Review shared secret for client: $($_.Name) ($($_.Address))"
}
# Ensure NPS server certificate is from a trusted enterprise CA (for PEAP/EAP-TLS)
Get-ChildItem -Path Cert:LocalMachineMy |
Where-Object { $_.EnhancedKeyUsageList -match "Server Authentication" } |
Select-Object Subject, NotBefore, NotAfter, Thumbprint |
Sort-Object NotAfter
Conclusion
Network Policy Server on Windows Server 2025 provides a centralized, AD-integrated RADIUS authentication service that eliminates the need for each network device to manage its own user database. By separating authentication logic into dedicated NPS servers, applying connection request policies to match traffic types, and enforcing network policies tied to Active Directory group membership, you gain consistent access control across VPN, 802.1X wireless, and wired network access points. For production deployments, always deploy NPS in a highly available pair behind a network load balancer, use certificate-based EAP-TLS authentication over PEAP/MSCHAPv2 wherever possible, and configure NPS accounting to feed into your SIEM for correlation and compliance reporting. The RADIUS proxy capability further extends NPS to serve as the central authentication hub for multi-domain and federated network access scenarios.