How to Set Up Multi-Site Active Directory on Windows Server 2012 R2

A multi-site Active Directory deployment distributes Domain Controllers across geographically separated locations, providing local authentication, policy application, and directory services to users at each site without relying on WAN connectivity for every AD operation. Properly designed AD sites and services configuration is essential for controlling replication topology, directing client authentication to local DCs, and managing Group Policy application in distributed environments. This guide covers designing and implementing a complete multi-site AD infrastructure on Windows Server 2012 R2.

Prerequisites

– Windows Server 2012 R2 Domain Controllers at each site
– IP subnets for each site clearly defined
– Network connectivity between sites (WAN, MPLS, VPN, or ExpressRoute)
– DNS properly configured at all sites
– Active Directory Sites and Services snap-in access
– Enterprise Admin or Domain Admin privileges
– Defined replication schedule and bandwidth constraints per site link

Step 1: Create AD Sites

Import-Module ActiveDirectory

# Create sites for each physical location
$sites = @(
    @{Name="HQ-Chicago";    Description="Headquarters - Chicago, IL"},
    @{Name="Branch-NYC";    Description="New York City Branch Office"},
    @{Name="Branch-LA";     Description="Los Angeles Branch Office"},
    @{Name="Branch-London"; Description="London UK Branch Office"},
    @{Name="DC-Dallas";     Description="Dallas Data Center - Colocation"}
)

foreach ($s in $sites) {
    try {
        New-ADReplicationSite -Name $s.Name -Description $s.Description
        Write-Host "Created site: $($s.Name)" -ForegroundColor Green
    } catch {
        Write-Warning "Site may already exist: $($s.Name)"
    }
}

# Verify sites
Get-ADReplicationSite -Filter * | Select-Object Name, Description | Format-Table -AutoSize

Step 2: Create Subnets and Associate with Sites

Active Directory uses subnet-to-site mappings to determine which site a client belongs to. This is what controls which DC a client authenticates against:

Import-Module ActiveDirectory

$subnets = @(
    @{Name="10.10.0.0/16"; Site="HQ-Chicago";    Description="Chicago corporate network"},
    @{Name="10.10.100.0/24";Site="HQ-Chicago";   Description="Chicago DMZ"},
    @{Name="10.20.0.0/24"; Site="Branch-NYC";    Description="NYC office network"},
    @{Name="10.30.0.0/24"; Site="Branch-LA";     Description="LA office network"},
    @{Name="172.16.10.0/24";Site="Branch-London";Description="London office network"},
    @{Name="192.168.50.0/24";Site="DC-Dallas";   Description="Dallas colo network"},
    @{Name="192.168.51.0/24";Site="DC-Dallas";   Description="Dallas management network"}
)

foreach ($subnet in $subnets) {
    try {
        New-ADReplicationSubnet -Name $subnet.Name `
            -Site $subnet.Site `
            -Description $subnet.Description
        Write-Host "Created subnet $($subnet.Name) -> $($subnet.Site)" -ForegroundColor Green
    } catch {
        Write-Warning "Subnet error: $($subnet.Name) - $($_.Exception.Message)"
    }
}

# Verify subnet assignments
Get-ADReplicationSubnet -Filter * | 
    Select-Object Name, Site, Description | 
    Format-Table -AutoSize

Step 3: Create Site Links

Site links define the replication paths between sites. Their cost, replication frequency, and schedule determine when and how often replication occurs across each path:

Import-Module ActiveDirectory

# Remove the default DEFAULTIPSITELINK if not needed
# Get-ADReplicationSiteLink -Filter * | Remove-ADReplicationSiteLink

# Create site links representing actual WAN connections
$siteLinks = @(
    @{
        Name="HQ-NYC-Link"
        SitesIncluded=@("HQ-Chicago","Branch-NYC")
        Cost=100
        ReplicationFrequency=15  # minutes
        Description="MPLS Chicago-NYC 100Mbps"
    },
    @{
        Name="HQ-LA-Link"
        SitesIncluded=@("HQ-Chicago","Branch-LA")
        Cost=150
        ReplicationFrequency=30
        Description="MPLS Chicago-LA 50Mbps"
    },
    @{
        Name="HQ-London-Link"
        SitesIncluded=@("HQ-Chicago","Branch-London")
        Cost=300
        ReplicationFrequency=60
        Description="MPLS Chicago-London 10Mbps transatlantic"
    },
    @{
        Name="HQ-Dallas-Link"
        SitesIncluded=@("HQ-Chicago","DC-Dallas")
        Cost=50
        ReplicationFrequency=15
        Description="Private fiber Chicago-Dallas datacenter"
    }
)

foreach ($link in $siteLinks) {
    New-ADReplicationSiteLink -Name $link.Name `
        -SitesIncluded $link.SitesIncluded `
        -Cost $link.Cost `
        -ReplicationFrequencyInMinutes $link.ReplicationFrequency `
        -Description $link.Description `
        -InterSiteTransportProtocol IP
    Write-Host "Created site link: $($link.Name)" -ForegroundColor Green
}

# Enable site link bridging if needed for indirect routes
# Set-ADReplicationSiteLinkBridge (typically not required if all sites are fully connected)

# Configure replication schedule for the London link (replicate only during off-hours)
$londonLink = Get-ADReplicationSiteLink -Identity "HQ-London-Link"
# Schedule: Mon-Fri 6PM-6AM UTC, all day Saturday and Sunday
# Schedule is configured as a 168-byte array; use ADAC GUI for complex schedules
Set-ADReplicationSiteLink -Identity "HQ-London-Link" `
    -ReplicationFrequencyInMinutes 180  # 3-hour intervals for bandwidth conservation

# Verify site links
Get-ADReplicationSiteLink -Filter * | 
    Select-Object Name, Cost, ReplicationFrequencyInMinutes | 
    Format-Table -AutoSize

Step 4: Place Domain Controllers in Sites

Import-Module ActiveDirectory

# Move DCs to their correct sites
# The DC's IP address determines its site automatically IF the subnet is configured
# But you can also manually place DCs

$dcSiteMapping = @(
    @{DC="HQ-DC01";   Site="HQ-Chicago"},
    @{DC="HQ-DC02";   Site="HQ-Chicago"},
    @{DC="NYC-DC01";  Site="Branch-NYC"},
    @{DC="LA-DC01";   Site="Branch-LA"},
    @{DC="LON-DC01";  Site="Branch-London"},
    @{DC="DAL-DC01";  Site="DC-Dallas"},
    @{DC="DAL-DC02";  Site="DC-Dallas"}
)

foreach ($mapping in $dcSiteMapping) {
    $dcObject = Get-ADDomainController -Identity $mapping.DC -ErrorAction SilentlyContinue
    if ($dcObject) {
        $ntdsPath = "CN=NTDS Settings,CN=$($mapping.DC),CN=Servers,CN=$($mapping.Site),CN=Sites,CN=Configuration,$((Get-ADDomain).DistinguishedName)"
        # Move the server object to the correct site
        $serverPath = "CN=$($mapping.DC),CN=Servers,CN=$($mapping.Site),CN=Sites,CN=Configuration,$((Get-ADDomain).DistinguishedName)"
        Write-Host "DC $($mapping.DC) -> Site: $($dcObject.Site)"
    }
}

# Verify DC placement
Get-ADDomainController -Filter * | 
    Select-Object Hostname, Site, IsGlobalCatalog, OperationMasterRoles |
    Format-Table -AutoSize

Step 5: Configure Global Catalog Servers

Import-Module ActiveDirectory

# Make DCs in large sites Global Catalog servers
# GC servers are required for Universal Group membership lookups
$gcCandidates = @("HQ-DC01","HQ-DC02","DAL-DC01","NYC-DC01")

foreach ($dc in $gcCandidates) {
    Set-ADDomainController -Identity $dc -IsGlobalCatalog $true
    Write-Host "Enabled Global Catalog on: $dc" -ForegroundColor Green
}

# For bandwidth-constrained sites (London), avoid GC unless justified
# Universal Group Membership Caching is an alternative for small branch offices
# This must be enabled in AD Sites and Services for each site
$londonSite = Get-ADReplicationSite -Identity "Branch-London"
# Configure Universal Group Membership Caching via ADAC or repadmin

# Verify GC distribution
Get-ADDomainController -Filter {IsGlobalCatalog -eq $true} | 
    Select-Object Hostname, Site | Format-Table -AutoSize

Step 6: Configure Operations Master Roles

Import-Module ActiveDirectory

# Check current FSMO role placement
$forest = Get-ADForest
$domain = Get-ADDomain

Write-Host "=== FSMO Role Placement ===" -ForegroundColor Cyan
Write-Host "Schema Master:        $($forest.SchemaMaster)"
Write-Host "Domain Naming Master: $($forest.DomainNamingMaster)"
Write-Host "PDC Emulator:         $($domain.PDCEmulator)"
Write-Host "RID Master:           $($domain.RIDMaster)"
Write-Host "Infrastructure Master:$($domain.InfrastructureMaster)"

# Best practice: PDC Emulator should be in the largest/most connected site (HQ)
# RID Master with PDC Emulator
# Infrastructure Master should NOT be on a GC server (unless all DCs are GC)

# Move PDC Emulator to HQ if not already there
if ($domain.PDCEmulator -notlike "*HQ*") {
    Move-ADDirectoryServerOperationMasterRole `
        -Identity "HQ-DC01" `
        -OperationMasterRole PDCEmulator -Force
    Write-Host "Moved PDC Emulator to HQ-DC01" -ForegroundColor Green
}

# Set site coverage for sites without DCs
# This is automatic based on site link costs, but can be forced
# Clients in sites with no DC use the DC from the closest connected site

Step 7: Monitor Replication Health Across Sites

# Comprehensive multi-site replication monitoring
function Get-MultiSiteReplicationHealth {
    $dcs = Get-ADDomainController -Filter *
    $report = [System.Collections.Generic.List[PSCustomObject]]::new()

    foreach ($dc in $dcs) {
        try {
            $partners = Get-ADReplicationPartnerMetadata -Target $dc.Hostname -ErrorAction Stop
            foreach ($partner in $partners) {
                $report.Add([PSCustomObject]@{
                    SourceDC     = $dc.Hostname
                    SourceSite   = $dc.Site
                    PartnerDC    = $partner.Partner -replace 'CN=NTDS.*?CN=',''-replace ',.*',''
                    LastSuccess  = $partner.LastReplicationSuccess
                    Errors       = $partner.ConsecutiveReplicationFailures
                    HealthStatus = if ($partner.ConsecutiveReplicationFailures -eq 0) {"OK"} else {"FAILED"}
                })
            }
        } catch {
            $report.Add([PSCustomObject]@{
                SourceDC     = $dc.Hostname
                SourceSite   = $dc.Site
                HealthStatus = "QueryFailed: $($_.Exception.Message)"
            })
        }
    }

    $failed = $report | Where-Object { $_.HealthStatus -ne "OK" }
    if ($failed) {
        Write-Warning "Replication issues detected:"
        $failed | Format-Table -AutoSize
    } else {
        Write-Host "All replication links healthy" -ForegroundColor Green
    }

    $report | Group-Object SourceSite | ForEach-Object {
        Write-Host "Site: $($_.Name) - $($_.Count) connections"
    }
    $report | Export-Csv "C:ReportsMultiSiteReplHealth.csv" -NoTypeInformation
}

Get-MultiSiteReplicationHealth

# Force replication between specific DCs
repadmin /replicate nyc-dc01 hq-dc01 "DC=corp,DC=local"

# Run dcdiag across all sites
dcdiag /test:replications /v /e

Verification

# Full multi-site AD verification
Write-Host "=== Multi-Site AD Health ===" -ForegroundColor Cyan

# Sites
Write-Host "Sites configured: $(( Get-ADReplicationSite -Filter *).Count)"
Get-ADReplicationSite -Filter * | Select-Object Name | Sort-Object Name | Format-Table

# Subnets
Write-Host "Subnets configured: $((Get-ADReplicationSubnet -Filter *).Count)"

# Site links
Write-Host "Site Links:"
Get-ADReplicationSiteLink -Filter * | 
    Select-Object Name, Cost, ReplicationFrequencyInMinutes | Format-Table

# DC distribution
Write-Host "DC Site Distribution:"
Get-ADDomainController -Filter * | Group-Object Site | 
    Select-Object Name, Count | Format-Table

# Replication topology (connection objects)
repadmin /showrepl * /errorsonly

Summary

A properly designed multi-site Active Directory on Windows Server 2012 R2 ensures that users at each location authenticate against local Domain Controllers, Group Policy is applied efficiently, and directory replication is managed according to available WAN bandwidth. The key components are Sites (representing physical locations), Subnets (mapping IP ranges to sites), Site Links (defining replication paths with costs and schedules), and Domain Controllers placed at each site serving as local authentication points. With Global Catalog servers at major sites, FSMO roles in the most connected location, and regular replication health monitoring, your multi-site AD will provide consistent, reliable identity services across your entire organization.