How to Set Up DirectAccess for Always-On VPN on Windows Server 2012 R2

DirectAccess is Microsoft’s always-on connectivity technology for domain-joined Windows clients. Unlike traditional VPN that requires a user to manually connect, DirectAccess automatically establishes a secure IPv6-over-IPv4 tunnel whenever the client computer detects it is outside the corporate network — before the user even logs in. This enables IT administrators to manage laptops and desktops regardless of where they are, applying Group Policy, delivering Windows Updates, running compliance scans, and providing helpdesk access without any user action. Windows Server 2012 R2 introduces a simplified DirectAccess deployment that replaces the complex IP-HTTPS and ISATAP configuration of earlier versions with a streamlined, wizard-driven setup.

Prerequisites

– Windows Server 2012 R2 server with two network adapters (one Internet-facing, one internal)
– A public static IP address or name-based entry through a load balancer
– DNS entry for the DirectAccess server FQDN (e.g., da.corp.com)
– SSL certificate for the NLS (Network Location Server) and connectivity probe
– Active Directory domain at Windows Server 2008 or higher domain functional level
– Windows 8/8.1 or Windows 7 Enterprise/Ultimate clients (all support DirectAccess)
– PKI for machine certificate issuance (required for some DA configurations)
– Administrator rights to configure Group Policy and Remote Access

Step 1: Install the DirectAccess Role

# Install the Direct Access and VPN role service
Install-WindowsFeature -Name DirectAccess-VPN, RemoteAccess `
    -IncludeManagementTools -IncludeAllSubFeature

# Also install NPS for client health assessment (NAP integration)
Install-WindowsFeature -Name NPAS -IncludeManagementTools

Import-Module RemoteAccess

# Verify installation
Get-WindowsFeature DirectAccess-VPN, RemoteAccess | 
    Select-Object DisplayName, Installed | Format-Table -AutoSize

Step 2: Prepare Network Adapters

# Identify network adapters
Get-NetAdapter | Select-Object Name, InterfaceDescription, Status, LinkSpeed, 
    @{n='IPAddresses';e={(Get-NetIPAddress -InterfaceIndex $_.ifIndex).IPAddress -join ', '}} |
    Format-Table -AutoSize

# Example configuration:
# Adapter 1 "External" - connected to Internet with public IP 203.0.113.10
# Adapter 2 "Internal" - connected to corporate LAN 10.10.0.0/16

# Rename adapters for clarity
Rename-NetAdapter -Name "Ethernet" -NewName "External"
Rename-NetAdapter -Name "Ethernet 2" -NewName "Internal"

# Configure static IPs
New-NetIPAddress -InterfaceAlias "External" -IPAddress "203.0.113.10" -PrefixLength 24 `
    -DefaultGateway "203.0.113.1"
New-NetIPAddress -InterfaceAlias "Internal" -IPAddress "10.10.0.50" -PrefixLength 16

Set-DnsClientServerAddress -InterfaceAlias "Internal" -ServerAddresses "10.10.0.10","10.10.0.11"
Set-DnsClientServerAddress -InterfaceAlias "External" -ServerAddresses ""  # No DNS on external

Write-Host "Network adapters configured"
Get-NetIPAddress | Where-Object { $_.AddressFamily -eq "IPv4" } | 
    Select-Object InterfaceAlias, IPAddress | Format-Table -AutoSize

Step 3: Configure the Network Location Server (NLS)

The NLS is an HTTPS web server on the internal network. Clients check if they can reach the NLS — if yes, they are on the corporate network; if not, they are outside and need DirectAccess:

# The NLS should be on a highly available internal server (NOT the DirectAccess server)
# If it's unavailable, clients assume they're outside and attempt DA connection

# Install IIS for NLS (on a separate internal server, e.g., nls.corp.local)
Install-WindowsFeature -Name Web-Server -IncludeManagementTools

# Import NLS certificate (for internal clients to trust)
$certPwd = ConvertTo-SecureString "NLSCert@123" -AsPlainText -Force
$nlsCert = Import-PfxCertificate -FilePath "C:Certsnls_corp_local.pfx" `
    -CertStoreLocation "Cert:LocalMachineMy" -Password $certPwd

# Create the NLS website in IIS
New-WebSite -Name "NLS" -Port 443 -PhysicalPath "C:inetpubnls" `
    -SslFlags 0

Import-Module WebAdministration
$binding = Get-WebBinding -Name "NLS" -Protocol "https"
$binding.AddSslCertificate($nlsCert.Thumbprint, "My")

# Create a probe file
New-Item -ItemType Directory -Path "C:inetpubnls" -Force
"OK" | Out-File "C:inetpubnlsprobe.txt" -NoNewline

# The NLS URL will be: https://nls.corp.local/probe.txt
# This URL is configured in the DirectAccess setup wizard
# DNS name nls.corp.local must NOT be reachable from outside the corporate network

Write-Host "NLS configured at https://nls.corp.local"
Invoke-WebRequest "https://nls.corp.local/probe.txt" -UseBasicParsing |
    Select-Object StatusCode, Content

Step 4: Configure DirectAccess via PowerShell

Import-Module RemoteAccess

# Configure DirectAccess with the simplified deployment wizard
# This is the "Behind NAT" or "Edge" configuration depending on network topology

# Prepare prerequisite certificate information
$ipHttpsCert = Get-ChildItem Cert:LocalMachineMy | 
    Where-Object { $_.Subject -like "*da.corp.com*" } | Select-Object -First 1

# Run the DirectAccess setup using PowerShell
# For single NIC deployment (simplified — uses Teredo and IP-HTTPS)
Install-RemoteAccess `
    -DAInstallType FullInstall `
    -InternalInterface "Internal" `
    -InternetInterface "External" `
    -ConnectToAddress "da.corp.com" `
    -EntrypointName "Corp HQ" `
    -IPPrefixList "10.10.0.0/16"

# Configure client GPO
Set-DAClient `
    -GPOName "DirectAccess Client Settings" `
    -OnlyRemoteComputers Disabled

# Configure the NLS URL
Set-DANetworkLocationServer `
    -NLSUrl "https://nls.corp.local" `
    -CheckReachability $true

# Set the security group for DA clients
Set-DAClient -SecurityGroupNameList @("CORPDirectAccess-Clients")

Write-Host "DirectAccess configured"
Get-RemoteAccess | Format-List ConnectionType, DAInstallType

Step 5: Configure DirectAccess Connectivity

Import-Module RemoteAccess

# View current DirectAccess configuration
Get-DAClient | Format-List *
Get-DAServer | Format-List *

# Configure IP-HTTPS (used when Teredo fails — most reliable DA protocol)
$ipHttpsCert = Get-ChildItem Cert:LocalMachineMy | 
    Where-Object { $_.Subject -like "*da.corp.com*" } | Select-Object -First 1

Set-DAServer `
    -UserAuthentication UserPasswd `  # Or TwoFactor for smart card
    -IPHTTPSEnabled $true `
    -IPHTTPSCertificate $ipHttpsCert

# Configure DirectAccess for force tunneling (send all internet traffic through DA)
# Or keep default split tunneling (only internal traffic through DA)
Set-DAClient -ForceTunnel Disabled  # Split tunneling (default, recommended)

# Configure which machines get DirectAccess
# Create an AD security group for DA clients
New-ADGroup -Name "DirectAccess-Clients" `
    -GroupScope Global -GroupCategory Security `
    -Path "OU=Groups,DC=corp,DC=local" `
    -Description "Laptops and remote computers with DirectAccess"

# Add computers to the DA client group
Add-ADGroupMember -Identity "DirectAccess-Clients" `
    -Members "LAPTOP01$","LAPTOP02$","REMOTE-PC01$"

# Update DA client configuration to use this group
Set-DAClient -SecurityGroupNameList @("CORPDirectAccess-Clients")

Write-Host "DirectAccess client group: DirectAccess-Clients"

Step 6: Configure the DirectAccess GPO

Import-Module GroupPolicy

# DirectAccess automatically creates two GPOs:
# "DirectAccess Client Settings" - applied to computers in the DA client group
# "DirectAccess Server Settings" - applied to the DA server

# Verify the GPOs were created
Get-GPO -Name "DirectAccess Client Settings" | Format-List DisplayName, GpoStatus
Get-GPO -Name "DirectAccess Server Settings" | Format-List DisplayName, GpoStatus

# The client GPO contains:
# - IPsec policies for the DA tunnels
# - Name Resolution Policy Table (NRPT) entries that route internal DNS queries
#   through the DA tunnel and external DNS queries normally
# - Firewall rules for DirectAccess traffic
# - DA server discovery settings

# View the NRPT entries (Name Resolution Policy Table)
Get-DAClientDnsConfiguration | Format-List *

# View client settings
Get-DAClient | Format-List SecurityGroupName*, GpoName, ForceTunnel, ConnectionType

# Force GPO update on clients (for testing)
# gpupdate /force (run on a client computer)

Step 7: Test DirectAccess Connectivity

# Test from the DirectAccess SERVER perspective
Import-Module RemoteAccess

# View active DirectAccess connections
Get-RemoteAccessConnectionStatistics | 
    Where-Object { $_.TransportTunnel -in @("IP-HTTPS","Teredo","6to4") } |
    Select-Object UserName, ClientIpAddress, TransportTunnel, ConnectionDuration |
    Format-Table -AutoSize

# Count connected clients
$daClients = Get-RemoteAccessConnectionStatistics | 
    Where-Object { $_.TransportTunnel -ne $null }
Write-Host "Active DirectAccess clients: $($daClients.Count)"

# ON A CLIENT COMPUTER — Test DirectAccess connectivity
# Run: Get-DACConnectionStatus (shows current DA tunnel state)
# Run: netsh dns show state (shows NRPT table)
# Run: ping dc01.corp.local (should work when outside corporate network)
# Run: ipconfig /all (shows DA virtual adapter with IPv6 address)

# From Server — ping a DA-connected client
# Get the client's tunnel IP from connection statistics
$clientTunnelIP = ($daClients | Select-Object -First 1).ClientIPv4Address
ping $clientTunnelIP

# DirectAccess operational event log
Get-WinEvent -LogName "Microsoft-Windows-RemoteAccess-RemoteAccessServer/Operational" `
    -MaxEvents 20 | Format-Table TimeCreated, LevelDisplayName, Message -Wrap

Step 8: Configure DirectAccess Monitoring and Reporting

Import-Module RemoteAccess

# Set up monitoring on the Remote Access server
# View operational statistics
Get-RemoteAccessConnectionStatistics | Measure-Object | Select-Object Count

# Historical reporting
Get-RemoteAccessConnectionStatisticsSummary | Format-List *

# Monitor DA server health
Get-RemoteAccessHealth | Format-Table Component, Status, Summary -AutoSize

# Configure email alerts for DA server health
$alertBody = Get-RemoteAccessHealth | 
    Where-Object { $_.Status -ne "Working" } | 
    Format-Table Component, Status, Summary | Out-String

if ($alertBody) {
    Send-MailMessage -From "[email protected]" -To "[email protected]" `
        -Subject "DirectAccess Health Alert" `
        -Body $alertBody `
        -SmtpServer "smtp.corp.local"
}

# View DA server configuration summary
Write-Host "=== DirectAccess Configuration Summary ===" -ForegroundColor Cyan
$daServer = Get-DAServer
Write-Host "Connect To Address: $($daServer.ConnectToAddress)"
Write-Host "DA Installation Type: $($daServer.InstallationType)"
Write-Host "Internal Interface: $($daServer.InternalInterface)"
Write-Host "Internet Interface: $($daServer.InternetInterface)"

$daClient = Get-DAClient
Write-Host "Client Security Groups: $($daClient.SecurityGroupNameList -join ', ')"
Write-Host "Force Tunnel: $($daClient.ForceTunnel)"
Write-Host "Client GPO: $($daClient.GpoName)"

Verification

# Comprehensive DirectAccess health verification
Write-Host "=== DirectAccess Server Health ===" -ForegroundColor Cyan

# Service status
Get-Service RemoteAccess | Select-Object Status, StartType

# Component health
Get-RemoteAccessHealth | Format-Table Component, Status, Summary -AutoSize

# Active connections
$connections = Get-RemoteAccessConnectionStatistics
Write-Host "Active DA Connections: $($connections.Count)"

# Certificate validation
$ipHttpsCert = Get-ChildItem Cert:LocalMachineMy | 
    Where-Object { $_.Subject -like "*da.corp.com*" }
if ($ipHttpsCert) {
    $days = ($ipHttpsCert.NotAfter - (Get-Date)).Days
    Write-Host "IP-HTTPS Certificate: Valid ($days days remaining)" `
        -ForegroundColor $(if ($days -gt 30) {'Green'} else {'Yellow'})
}

# NLS reachability (from internal network — should succeed)
try {
    $nls = Invoke-WebRequest "https://nls.corp.local" -UseBasicParsing -TimeoutSec 5
    Write-Host "NLS: REACHABLE from internal network" -ForegroundColor Green
} catch {
    Write-Host "NLS: NOT REACHABLE — DA clients may have issues" -ForegroundColor Red
}

# GPO verification
Get-GPO "DirectAccess Client Settings" | Select-Object DisplayName, GpoStatus | Format-List

Summary

DirectAccess on Windows Server 2012 R2 delivers transparent always-on remote access that fundamentally improves the laptop management experience. Domain-joined Windows 8/8.1 clients automatically connect to the corporate network without user interaction as soon as they are outside the office, enabling seamless Group Policy application, Windows Update delivery, software deployment, and remote support. The simplified deployment wizard in WS2012 R2 dramatically reduces the complexity compared to earlier DirectAccess versions, supporting single-NIC configurations and automatic protocol selection between Teredo (UDP) and IP-HTTPS (HTTPS/443) based on what the client’s network allows. With high-availability NLS servers, active monitoring, and client GPO enforcement through the DA client security group, DirectAccess provides enterprise-grade connectivity that complements or replaces traditional VPN for corporate laptop fleets.