With Exchange Server 2016 and 2019 having reached their end of support, organizations running hybrid or fully on-premises environments have migrated (or are actively migrating) to Exchange Server Subscription Edition (SE).
However, Microsoft's servicing model for Exchange Server SE introduces a critical operational roadblock: strict coexistence pre-flight checks.
Unlike legacy Exchange setups that merely issued warnings during prerequisite analysis, subsequent Exchange Server SE Cumulative Updates (such as SE CU2) will hard-block and abort installation if any legacy Exchange Server objects (Exchange 2013, 2016, or 2019) remain registered inside your Active Directory configuration partition.
In many real-world enterprises, old Exchange servers were abruptly powered down, VM-deleted, or decommissioned without a clean Setup.exe /Mode:Uninstall. Their residual metadata remains entombed in Active Directory, waiting to fail your next Exchange SE CU upgrade.
In this runbook, we break down where Exchange server metadata lives in Active Directory, provide a production-ready PowerShell audit script to identify orphaned Exchange objects, and explain the safe, step-by-step remediation procedure.
---
Where Exchange Server Metadata Resides in Active Directory
When an Exchange server joins the organization, its identity and roles are recorded in the Active Directory Configuration Partition:
CN=Configuration,DC=yourdomain,DC=com
└── CN=Services
└── CN=Microsoft Exchange
└── CN=<ExchangeOrganizationName>
└── CN=Administrative Groups
└── CN=Exchange Administrative Group (FYDIBOHF23SPDLT)
└── CN=Servers
├── CN=EXSE01 (Exchange Server SE - Active)
├── CN=EX2019 (Exchange 2019 - Stale / Orphaned)
└── CN=EX2016 (Exchange 2016 - Stale / Orphaned)
During setup, Setup.exe /Mode:Upgrade interrogates this container. If any object has an AdminDisplayVersion corresponding to an unsupported legacy release (Exchange 2013 15.0., Exchange 2016 15.1., or Exchange 2019 15.2.*), setup halts with a fatal prerequisite failure:
[ERROR] An unsupported version of Exchange Server was detected in the organization.
Exchange Server SE Cumulative Updates require all Exchange 2016 and 2019 servers to be decommissioned.
---
Pre-Flight Audit: Identifying Stale Exchange Server Objects
Before scheduling maintenance windows or running Exchange SE CU installers, run this PowerShell script on any domain-joined management machine equipped with the ActiveDirectory module.
The script queries the Configuration naming context, inspects every server object, extracts version numbers, compares them against Exchange Server build thresholds, and tests network/RPC reachability to detect dead hosts.
<#
.SYNOPSIS
Scans Active Directory Configuration partition for legacy or orphaned Exchange Server objects.
.DESCRIPTION
Audits CN=Servers under the Exchange Administrative Group to detect legacy
Exchange 2013, 2016, and 2019 server metadata that blocks Exchange SE CU installations.
.NOTES
Author: Sunil Chauhan (https://www.lab365.in)
Requirements: ActiveDirectory PowerShell Module, Domain/Enterprise Read Access
#>
[CmdletBinding()]
param (
[Parameter(Mandatory = $false)]
[string]$ExportPath = ".\Exchange_Server_SE_PreFlight_Audit_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
)
# Import ActiveDirectory Module
if (-not (Get-Module -Name ActiveDirectory -ListAvailable)) {
Throw "ActiveDirectory PowerShell module is required. Please install RSAT: Active Directory Domain Services."
}
Import-Module ActiveDirectory -ErrorAction Stop
Write-Host "==========================================================" -ForegroundColor Cyan
Write-Host " Exchange Server SE: Legacy Server Object AD Pre-Flight " -ForegroundColor Cyan
Write-Host "==========================================================" -ForegroundColor Cyan
# Locate Configuration Partition
$rootDSE = Get-ADRootDSE
$configNC = $rootDSE.configurationNamingContext
# Locate Exchange Organization Container
$exchOrgFilter = "(objectClass=msExchOrganizationContainer)"
$exchOrg = Get-ADObject -SearchBase $configNC -LDAPFilter $exchOrgFilter -Properties name
if (-not $exchOrg) {
Throw "No Microsoft Exchange organization container found in Active Directory ($configNC)."
}
Write-Host "[+] Found Exchange Organization: '$($exchOrg.Name)'" -ForegroundColor Green
# Path to the Servers container in the Exchange Administrative Group
$serversDN = "CN=Servers,CN=Exchange Administrative Group (FYDIBOHF23SPDLT),CN=Administrative Groups,$($exchOrg.DistinguishedName)"
if (-not (Test-Path "AD:\$serversDN")) {
Throw "Servers container does not exist at: $serversDN"
}
Write-Host "[*] Auditing servers registered in AD Configuration partition..." -ForegroundColor Yellow
$adServers = Get-ADObject -SearchBase $serversDN -LDAPFilter "(objectClass=msExchExchangeServer)" `
-Properties name, serialNumber, versionNumber, adminDisplayVersion, msExchServerSite, dNSHostName, whenCreated, whenChanged
$results = [System.Collections.Generic.List[PSCustomObject]]::new()
foreach ($server in $adServers) {
$versionRaw = $server.adminDisplayVersion
$friendlyVersion = "Unknown"
$isLegacy = $false
# Classify Exchange Build Version
if ($versionRaw -match "^Version 15\.3") {
$friendlyVersion = "Exchange Server SE"
$isLegacy = $false
} elseif ($versionRaw -match "^Version 15\.2") {
$friendlyVersion = "Exchange Server 2019 (Legacy)"
$isLegacy = $true
} elseif ($versionRaw -match "^Version 15\.1") {
$friendlyVersion = "Exchange Server 2016 (Legacy)"
$isLegacy = $true
} elseif ($versionRaw -match "^Version 15\.0") {
$friendlyVersion = "Exchange Server 2013 (Legacy)"
$isLegacy = $true
} elseif ($versionRaw -match "^Version 14\.") {
$friendlyVersion = "Exchange Server 2010 (Legacy)"
$isLegacy = $true
}
# Test network responsiveness
$dnsName = $server.dNSHostName
$isOnline = $false
if ($dnsName) {
$ping = Test-Connection -ComputerName $dnsName -Count 1 -Quiet -ErrorAction SilentlyContinue
$isOnline = [bool]$ping
}
# Flag state
$complianceStatus = if ($isLegacy) {
"BLOCKING: Must be decommissioned before SE CU install"
} else {
"COMPLIANT: Exchange Server SE"
}
$results.Add([PSCustomObject]@{
ServerName = $server.Name
DNSHostName = $server.dNSHostName
AdminVersion = $versionRaw
ProductEdition = $friendlyVersion
IsLegacyObject = $isLegacy
IsPingable = $isOnline
ADSite = ($server.msExchServerSite -split ',')[0] -replace 'CN='
ComplianceStatus = $complianceStatus
DistinguishedName = $server.DistinguishedName
LastModified = $server.whenChanged
})
}
Write-Host ""
$legacyCount = ($results | Where-Object IsLegacyObject -eq $true).Count
if ($legacyCount -gt 0) {
Write-Host "[!] ALERT: Found $legacyCount legacy Exchange server object(s) in Active Directory!" -ForegroundColor Red
$results | Format-Table ServerName, ProductEdition, IsPingable, ComplianceStatus -AutoSize
} else {
Write-Host "[✓] All registered Exchange server objects are running Exchange Server SE. AD is ready for CU update!" -ForegroundColor Green
$results | Format-Table ServerName, ProductEdition, ComplianceStatus -AutoSize
}
$results | Export-Csv -Path $ExportPath -NoTypeInformation -Encoding utf8
Write-Host "[+] Audit report exported to: $ExportPath" -ForegroundColor Cyan
---
Safe Remediation: Removing Orphaned Exchange Metadata
If your audit detected legacy Exchange 2016 or 2019 servers that no longer physically exist, you must clean their Active Directory configuration cleanly.
[!CAUTION]
Important Rule: If the legacy server is still running and healthy, always perform a supported decommission using Setup.exe /Mode:Uninstall from the operating system. Manual AD deletion is strictly reserved for dead servers whose physical/virtual hosts have been permanently destroyed.
Step 1: Verify Dependencies Before Deleting
Before removing any Exchange server object from AD, verify that: 1. Mailbox Databases: The server does not host any active mailbox database copies or arbitration mailboxes. 2. Send Connectors: The server is not designated as a source transport server on any active Send Connectors (Get-SendConnector).
3. DAG Membership: If the server was part of a Database Availability Group (DAG), remove it from the cluster and DAG definition first:
Remove-DatabaseAvailabilityGroupServer -Identity DAG01 -MailboxServer EX2019 -ConfigurationOnly
Step 2: Remove Orphaned Child Objects (Databases & Protocols)
In AD, an Exchange server container has multiple subordinate containers (InformationStore, Protocols, Autodiscover). Attempting to delete the parent container while child objects exist can throw LDAP errors.
Using ADSI Edit (adsiedit.msc):
1. Connect to the Configuration naming context.
2. Navigate to:
CN=Configuration,DC=domain,DC=com > CN=Services > CN=Microsoft Exchange > CN=<OrgName> > CN=Administrative Groups > CN=Exchange Administrative Group (FYDIBOHF23SPDLT) > CN=Servers.
3. Locate the dead server object (e.g., CN=EX2019).
4. Expand CN=EX2019 and delete child containers (such as CN=InformationStore) if no mailboxes reside there.
Step 3: Remove the Server Object with PowerShell
Once verified, an Enterprise Administrator or member of Organization Management can remove the orphaned object safely usingRemove-ADObject:
# Define target orphaned server DN
$orphanDN = "CN=EX2019,CN=Servers,CN=Exchange Administrative Group (FYDIBOHF23SPDLT),CN=Administrative Groups,CN=LAB365,CN=Microsoft Exchange,CN=Services,CN=Configuration,DC=lab365,DC=in"
# Delete the server object and any residual child metadata recursively
Remove-ADObject -Identity $orphanDN -Recursive -Confirm:$true
Step 4: Clean Residual DNS & Computer Accounts
Don't forget the Active Directory Domain partition:- Remove the stale Windows Computer account from
CN=Computersor yourOU=Servers. - Remove static forward and reverse DNS host (A/AAAA) records from internal DNS zones.
Post-Cleanup Verification
Once Active Directory replication converges across all Domain Controllers, re-run our pre-flight PowerShell audit script.
When the script confirms:
[✓] All registered Exchange server objects are running Exchange Server SE. AD is ready for CU update!
You can execute the Exchange Server SE Cumulative Update ISO installer with full confidence that prerequisite checks will pass without blocking setup.
---
Summary Checklist
- [ ] Execute
Exchange_Server_SE_PreFlight_Audit.ps1across your Active Directory forest. - [ ] Ensure all legitimate Exchange 2016/2019 servers undergo graceful
Setup.exe /Mode:Uninstall. - [ ] For dead/destroyed servers, verify absence of Send Connector transport source and DAG memberships.
- [ ] Clean orphaned
CN=Serversmetadata in the Configuration container usingRemove-ADObject -Recursive. - [ ] Verify AD replication topology before launching Exchange Server SE CU setup.
Related reading: Exchange Server SE vs 2019: In-Place Upgrade Runbook · Migrating from Windows PowerShell 5.1 to PowerShell 7 for Microsoft Graph