Introduction to DNS Policies on Windows Server 2019

DNS Policies, introduced in Windows Server 2016 and fully supported in Windows Server 2019, allow the DNS server to make intelligent decisions about how to respond to queries based on criteria such as the client’s IP address or subnet, the time of day, the query type, or the fully qualified domain name being queried. This enables powerful use cases including split-brain DNS (returning different answers to internal vs external clients), traffic management and load balancing, blocking specific query types or domains, and geo-based or time-based DNS responses — all without requiring additional DNS infrastructure.

DNS Policy Architecture

DNS Policies are evaluated in priority order. Each policy has a set of criteria (called conditions) and an action to take when those criteria match. Actions include: ALLOW (respond normally), DENY (drop the query or return REFUSED), IGNORE (no response), or a custom response such as redirecting to a different IP address. Policies can be applied at two levels: query resolution policies (affect how queries are answered) and zone transfer policies (affect zone replication).

Client Subnets, Recursion Scopes, and Zone Scopes are the three foundational building blocks you create before defining policies.

Prerequisites

# Verify DNS Server role and version
Get-WindowsFeature -Name DNS
Get-DnsServerSetting | Select-Object ComputerName, MajorVersion, MinorVersion

# List existing policies
Get-DnsServerQueryResolutionPolicy

Use Case 1: Split-Brain DNS with Zone Scopes

Split-brain (or split-horizon) DNS serves different resource records for the same domain name depending on whether the client is internal or external. For example, internal clients querying www.corp.example.com receive the private IP 10.1.1.50, while external clients receive the public IP 203.0.113.10. This eliminates the need for two separate zone files and two DNS servers.

# Step 1: Create client subnet definitions
Add-DnsServerClientSubnet -Name "InternalSubnet" `
    -IPv4Subnet "10.0.0.0/8","192.168.0.0/16","172.16.0.0/12"

Add-DnsServerClientSubnet -Name "ExternalSubnet" `
    -IPv4Subnet "0.0.0.0/0"   # catch-all for everything not internal

# Step 2: Create a zone scope for internal clients (in addition to the default scope)
Add-DnsServerZoneScope -ZoneName "corp.example.com" -Name "InternalScope"

# Step 3: Add records to the internal scope
Add-DnsServerResourceRecord -ZoneName "corp.example.com" `
    -ZoneScope "InternalScope" `
    -A -Name "www" -IPv4Address "10.1.1.50"

# The default zone scope already has the external record
Add-DnsServerResourceRecord -ZoneName "corp.example.com" `
    -A -Name "www" -IPv4Address "203.0.113.10"

# Step 4: Create the query resolution policies
# Internal clients get InternalScope records
Add-DnsServerQueryResolutionPolicy `
    -Name "InternalPolicy" `
    -Action Allow `
    -ClientSubnet "EQ,InternalSubnet" `
    -ZoneScope "InternalScope,1" `
    -ZoneName "corp.example.com" `
    -ProcessingOrder 1

# External clients (default scope) fall through to the default policy
Add-DnsServerQueryResolutionPolicy `
    -Name "ExternalPolicy" `
    -Action Allow `
    -ClientSubnet "EQ,ExternalSubnet" `
    -ZoneScope "corp.example.com,1" `
    -ZoneName "corp.example.com" `
    -ProcessingOrder 2

Use Case 2: Block Specific Domains

Use a query resolution policy to block resolution of specific domain names, returning REFUSED to clients that query for them. This is useful for blocking malware command-and-control domains, ad networks, or social media sites during business hours.

# Block a specific FQDN
Add-DnsServerQueryResolutionPolicy `
    -Name "BlockMalwareDomain" `
    -Action DENY `
    -FQDN "EQ,malware.badsite.com,*.evil.net" `
    -ProcessingOrder 1

# Block all queries of type MX (to prevent spam relay reconnaissance)
Add-DnsServerQueryResolutionPolicy `
    -Name "BlockMXQueries" `
    -Action DENY `
    -QType "EQ,MX" `
    -ProcessingOrder 2

# Verify
Get-DnsServerQueryResolutionPolicy | Select-Object Name, Action, ProcessingOrder | Format-Table

Use Case 3: Time-Based DNS Response Policies

Return different IP addresses based on the time of day — for example, direct traffic to a maintenance server during off-hours:

# Create a zone scope for maintenance window
Add-DnsServerZoneScope -ZoneName "corp.example.com" -Name "MaintenanceScope"

# Add maintenance server record
Add-DnsServerResourceRecord -ZoneName "corp.example.com" `
    -ZoneScope "MaintenanceScope" `
    -A -Name "app" -IPv4Address "10.1.1.99"

# Policy active only during midnight to 6am (TimeOfDay in minutes from midnight)
Add-DnsServerQueryResolutionPolicy `
    -Name "MaintenancePolicy" `
    -Action Allow `
    -TimeOfDay "EQ,00:00-06:00" `
    -FQDN "EQ,app.corp.example.com" `
    -ZoneScope "MaintenanceScope,1" `
    -ZoneName "corp.example.com" `
    -ProcessingOrder 1

Use Case 4: DNS Load Balancing with Zone Scopes

Distribute DNS responses across multiple servers using weighted zone scopes. By assigning different weights, you control what percentage of clients receive each record.

# Create two zone scopes for two application servers
Add-DnsServerZoneScope -ZoneName "corp.example.com" -Name "AppServer1Scope"
Add-DnsServerZoneScope -ZoneName "corp.example.com" -Name "AppServer2Scope"

Add-DnsServerResourceRecord -ZoneName "corp.example.com" `
    -ZoneScope "AppServer1Scope" -A -Name "app" -IPv4Address "10.1.1.10"

Add-DnsServerResourceRecord -ZoneName "corp.example.com" `
    -ZoneScope "AppServer2Scope" -A -Name "app" -IPv4Address "10.1.1.11"

# Policy with 70/30 load balance (weight = number of requests served before moving to next)
Add-DnsServerQueryResolutionPolicy `
    -Name "LoadBalance" `
    -Action Allow `
    -FQDN "EQ,app.corp.example.com" `
    -ZoneScope "AppServer1Scope,7;AppServer2Scope,3" `
    -ZoneName "corp.example.com" `
    -ProcessingOrder 1

Use Case 5: Restrict Recursion by Client Subnet

Create a recursion scope and policy to prevent external IP addresses from using your DNS server as an open resolver:

# Create a recursion scope that disables recursion
Add-DnsServerRecursionScope -Name "NoRecursion" -EnableRecursion $false

# Apply this scope to queries from external clients
Add-DnsServerQueryResolutionPolicy `
    -Name "BlockExternalRecursion" `
    -Action Allow `
    -ApplyOnRecursion `
    -RecursionScope "NoRecursion" `
    -ClientSubnet "EQ,ExternalSubnet" `
    -ProcessingOrder 5

Managing and Removing Policies

# List all query resolution policies
Get-DnsServerQueryResolutionPolicy | Format-Table Name, Action, IsEnabled, ProcessingOrder

# Disable a policy temporarily
Set-DnsServerQueryResolutionPolicy -Name "MaintenancePolicy" -Disable

# Re-enable
Set-DnsServerQueryResolutionPolicy -Name "MaintenancePolicy" -Enable

# Remove a policy
Remove-DnsServerQueryResolutionPolicy -Name "BlockMalwareDomain" -Force

# Remove a zone scope (must remove all records and policies referencing it first)
Remove-DnsServerZoneScope -ZoneName "corp.example.com" -Name "MaintenanceScope" -Force

Exporting and Importing Policy Configuration

# Export zone scopes and policies to CSV for documentation
Get-DnsServerQueryResolutionPolicy | Export-Csv -Path "C:DNSPolicies.csv" -NoTypeInformation
Get-DnsServerZoneScope -ZoneName "corp.example.com" | Export-Csv -Path "C:ZoneScopes.csv" -NoTypeInformation
Get-DnsServerClientSubnet | Export-Csv -Path "C:ClientSubnets.csv" -NoTypeInformation

Summary

DNS Policies on Windows Server 2019 provide a flexible framework for controlling DNS resolution behaviour at a granular level. Using Client Subnets, Zone Scopes, Recursion Scopes, and Query Resolution Policies together, you can implement split-brain DNS, domain blocking, time-based responses, weighted load balancing, and recursion restrictions — all within the built-in Windows DNS Server role without additional software or infrastructure.