
Big‑Bang Exchange Cross‑Forest Migration

Drago Petrovic
Microsoft MVP
Big-Bang Exchange Cross-Forest Migration – Full Runbook
Scenario: Migrate all mailbox contents from Exchange 2016 (Source: contoso.com) to Exchange Subscription Edition (Target: fabrikam.net) using native remote moves (MRS/MRSProxy) — no PST — as a Big-Bang cutover.
Table of Contents
- 1) Scope & Assumptions (FULL)
- 2) Timeline & Big-Bang Approach (T-14 ? T+1)
- 3) Technical Preparation in Detail
- 4) Migration Execution – Step by Step
- 5) Cutover, Post-Tasks & Validation
- 6) Rollback Plan
- Appendix A: PowerShell Snippets (concise)
- Appendix B: Checklists
- Appendix C: Performance & Operations
- Script Bundle (01–06)
- CSV Template (BigBang.csv)
- References
1) Scope & Assumptions (FULL)
- Source: Exchange 2016 (on-prem) — contoso.com
- Target: Exchange Subscription Edition (SE) — fabrikam.net.
SE is functionally aligned with Exchange 2019 SE, and supports cross-forest remote moves (native MRS). See Microsoft documentation for cross-forest move support statements. (Ref: Prepare mailboxes for cross-forest moves) - Scale: ~200 mailboxes / ~250 GB total — well-suited for a Big-Bang cutover using online seeding to minimize final downtime.
- No shared SMTP namespace during migration ? plan a DNS cutover (Autodiscover/MX) to the target at the agreed window (no internal relay required in this scenario).
- No PST path — migration must use MRS/MRSProxy exclusively (native remote moves).
This ensures full mailbox content (incl. calendar/contacts/recoverable items/rules) is moved by Exchange, instead of manual PST import/export. - Network: For MRS, ensure HTTPS/443 from Target to the Source EWS endpoint (MRSProxy). The target must trust the source certificate chain (import Root/Intermediate if internal CA). (Ref: Enable MRS Proxy endpoint; Set-WebServicesVirtualDirectory)
Why MailUser (and not empty mailboxes) in Target?
For cross-forest remote moves, the target forest must contain a MailUser for each user with a specific set of Exchange/AD attributes (e.g., LegacyExchangeDN for X.500, ProxyAddresses, mailbox GUIDs where applicable). The Microsoft-provided script Prepare-MoveRequest.ps1 copies the required attributes from the source and creates/updates the MailUser in the target. During the remote move, Exchange converts the MailUser to a full mailbox while pulling data from the source via MRS.
If empty target mailboxes already exist, they must be removed (the AD account stays) so that Prepare-MoveRequest.ps1 can stamp the object as MailUser and the move can proceed. Otherwise the move request will not convert properly. (Ref: Prepare mailboxes for cross-forest move requests / Prepare-MoveRequest.ps1)
2) Timeline & Big-Bang Approach (T-14 ? T+1)
T-14 to T-7 (Preparation)
- Certificates/PKI: Import source CA chain into the target (if using an internal CA) so the source EWS certificate is trusted.
- Enable MRSProxy on Source (EWS virtual directory) and validate reachability from Target (HTTPS/443).
- DNS plan: Reduce TTL for Autodiscover/MX (e.g., 300 s) to make the final switchover fast.
- Best practices: Ensure backups are running, set AV exclusions, optionally enable circular logging on the migration DB to reduce log growth during seeding.
T-7 to T-3 (Object Preparation & Pilot)
- Remove empty target mailboxes (AD accounts stay).
- Run
Prepare-MoveRequest.ps1in Target to create/update MailUsers for all to-be-migrated users. - Test MRS connectivity from Target:
Test-MigrationServerAvailabilityagainst the source EWS. - Run a mini-pilot (2–3 users) all the way to Synced (but not Complete), validate functionality, then remove pilot moves.
T-2 to T-1 (Pre-Cutover)
- Create the Migration Endpoint on Target (using source EWS FQDN).
- Create the BigBang batch for all users, AutoStart, AutoComplete=False ? lets MRS seed mailboxes while users remain on source.
- Monitor until all users are Synced.
T-0 (Cutover window)
- DNS cutover: Switch Autodiscover (and MX if applicable) to Target.
- Run
Complete-MigrationBatch? final switch per mailbox (brief interruption). - Smoke tests & post-tasks.
T+1
- Re-apply delegations, monitor, deliver the close-out report.
3) Technical Preparation in Detail
3.1 Enable MRSProxy on Source & verify EWS
Get-WebServicesVirtualDirectory | fl Identity,ExternalUrl,InternalUrl,MRSProxyEnabled,BasicAuthentication,WindowsAuthentication,MRSProxyMaxConnections Set-WebServicesVirtualDirectory -Identity "EWS (Default Web Site)" ` -MRSProxyEnabled $true ` -ExternalUrl "https://mail.contoso.com/EWS/Exchange.asmx" ` -InternalUrl "https://mail.contoso.local/EWS/Exchange.asmx" ` -BasicAuthentication $true -WindowsAuthentication $true ` -MRSProxyMaxConnections 100 Restart-WebAppPool MSExchangeServicesAppPool
Note: For pull moves (initiated in Target), MRSProxy must be active in the Source forest.
3.2 Certificates & Network
- Open TCP 443 from Target to Source EWS.
- If using an internal CA: import Root/Intermediate CA into Target (Trusted Roots) so EWS SSL validates.
3.3 Prepare target objects (MailUser instead of empty mailboxes)
Case A: Target mailbox exists ? remove it (AD account remains) so the object can be used as MailUser by the script:
Disable-Mailbox -Identity user1@fabrikam.net -Confirm:$false
Case B: No object exists ? the script will create MailUsers in the target OU.
Run Prepare-MoveRequest on Target
cd "$env:ExchangeInstallPath\Scripts" $SrcDC = "dc01.contoso.com" $TgtDC = "dc01.fabrikam.net" $SrcCred = Get-Credential # Source admin $TgtCred = Get-Credential # Target admin $TargetOU = "OU=MailUsers,OU=Exchange,DC=fabrikam,DC=net" $DeliveryDomain = "contoso.com" # Goal: MailUsers with correct attributes (LegacyExchangeDN/X500/ProxyAddresses) .\Prepare-MoveRequest.ps1 ` -RemoteForestDomainController $SrcDC -RemoteForestCredential $SrcCred ` -LocalForestDomainController $TgtDC -LocalForestCredential $TgtCred ` -TargetMailUserOU $TargetOU -MailboxDeliveryDomain $DeliveryDomain ` -UseLocalObject -OverWriteLocalObject
3.4 Test MRS connectivity (from Target)
Test-MigrationServerAvailability -ExchangeRemoteMove ` -RemoteServer mail.contoso.com ` -Credentials (Get-Credential)
4) Migration Execution – Step by Step
4.1 Create Migration Endpoint on Target
$cred = Get-Credential -Message "Enter SOURCE (contoso) admin credentials" New-MigrationEndpoint -Name "SRC2016" -ExchangeRemoteMove ` -RemoteServer "mail.contoso.com" ` -Credentials $cred ` -Autodiscover:$false
4.2 CSV for all users (structure)
user1@fabrikam.net
user2@fabrikam.net
...
4.3 Create the BigBang batch (AutoStart, AutoComplete=False)
$csv = [System.IO.File]::ReadAllBytes("C:\\CFMig\\BigBang.csv")
New-MigrationBatch -Name "BigBang" -CSVData $csv -AutoStart -AutoComplete:$false
4.4 Monitor until all are “Synced”
Get-MigrationBatch Get-MigrationUser -BatchId "BigBang" | Get-MigrationUserStatistics | ft Identity,Status,PercentComplete,ItemsTransferred,BytesTransferred -AutoSize
Diagnostics with report:
Get-MigrationUser -BatchId "BigBang" | Get-MigrationUserStatistics -IncludeReport | fl
4.5 Alternative: single remote move (no batch)
New-MoveRequest -Identity user1@fabrikam.net -Remote ` -RemoteHostName "mail.contoso.com" ` -RemoteCredential (Get-Credential) ` -TargetDatabase "DB01-Target" ` -BatchName "BigBang" ` -SuspendWhenReadyToComplete:$true
5) Cutover, Post-Tasks & Validation
5.1 Cutover (downtime window)
- DNS switch (Autodiscover and MX if applicable) to Target.
- Complete the batch:
Complete-MigrationBatch -Identity "BigBang" - Smoke tests: OWA/Outlook, send/receive, calendars, mobile.
5.2 Post-Tasks
- Re-apply delegations (FullAccess/SendAs/SendOnBehalf) — these do not carry across forests and must be restored post-cutover.
- Validate transport rules/connectors/policies; run health checks (event logs,
Get-ServerHealth), and produce the final report.
6) Rollback Plan
- Before Complete (status “Synced”): do not finalize the batch; keep/revert DNS to Source ? no user impact.
- After DNS cutover, before Complete: revert DNS to Source ? users back on Source; fix root cause.
- After Complete: rollback means another remote move back (time-consuming). Therefore, run all critical validation before Complete.
Appendix A: PowerShell Snippets (concise)
Enable MRSProxy (Source)
Get-WebServicesVirtualDirectory | fl Identity,ExternalUrl,InternalUrl,MRSProxyEnabled,BasicAuthentication,WindowsAuthentication Set-WebServicesVirtualDirectory -Identity "EWS (Default Web Site)" -MRSProxyEnabled $true -ExternalUrl "https://mail.contoso.com/EWS/Exchange.asmx" -InternalUrl "https://mail.contoso.local/EWS/Exchange.asmx" -BasicAuthentication $true -WindowsAuthentication $true -MRSProxyMaxConnections 100 Restart-WebAppPool MSExchangeServicesAppPool
Prepare-MoveRequest (Target)
cd "$env:ExchangeInstallPath\Scripts" $SrcDC="dc01.contoso.com"; $TgtDC="dc01.fabrikam.net" $SrcCred=Get-Credential; $TgtCred=Get-Credential $TargetOU="OU=MailUsers,OU=Exchange,DC=fabrikam,DC=net"; $DeliveryDomain="contoso.com" .\Prepare-MoveRequest.ps1 -RemoteForestDomainController $SrcDC -RemoteForestCredential $SrcCred -LocalForestDomainController $TgtDC -LocalForestCredential $TgtCred -TargetMailUserOU $TargetOU -MailboxDeliveryDomain $DeliveryDomain -UseLocalObject -OverWriteLocalObject
MRS connectivity (Target)
Test-MigrationServerAvailability -ExchangeRemoteMove -RemoteServer mail.contoso.com -Credentials (Get-Credential)
Endpoint & Batch (Target)
$cred = Get-Credential
New-MigrationEndpoint -Name "SRC2016" -ExchangeRemoteMove -RemoteServer "mail.contoso.com" -Credentials $cred -Autodiscover:$false
$csv = [System.IO.File]::ReadAllBytes("C:\\CFMig\\BigBang.csv")
New-MigrationBatch -Name "BigBang" -CSVData $csv -AutoStart -AutoComplete:$false
Monitoring & Complete
Get-MigrationBatch Get-MigrationUser -BatchId "BigBang" | Get-MigrationUserStatistics | ft Identity,Status,PercentComplete -AutoSize Complete-MigrationBatch -Identity "BigBang"
Appendix B: Checklists
Pre-Flight (T-14 ? T-3)
- EWS URL external/internal correct; auth (Basic/Windows) OK; MRSProxy Enabled.
- Certificate chain trusted in Target (if internal CA).
- Firewall: 443 from Target ? Source EWS open.
- Empty target mailboxes removed; MailUsers prepared via
Prepare-MoveRequest.ps1. Test-MigrationServerAvailabilitysuccessful.- CSV
BigBang.csvvalidated. - TTL for Autodiscover/MX reduced.
- Backups/AV exclusions/circular logging reviewed.
Pre-Cutover (T-2 ? T-1)
- Migration Endpoint created.
- Batch started (AutoComplete=False), progress ? Synced.
- Comms to users/helpdesk.
Cutover (T-0)
- DNS (Autodiscover/MX) to Target.
Complete-MigrationBatchexecuted.- Smoke tests (send/receive, OWA/Outlook, mobile, calendars).
Post-Cutover (T+1)
- Re-apply delegations (FullAccess/SendAs/SendOnBehalf).
- Monitoring/event logs OK; close-out report delivered.
Appendix C: Performance & Operations
- MRS scales in parallel and self-throttles; consider increasing
MRSProxyMaxConnectionsmoderately (e.g., 100). - User interruption happens only at Complete (brief) — hence "Synced ? Complete" aligns with a predictable Big-Bang switch.
- Follow best practices (backups, AV exclusions, monitoring) during migration windows.
Script Bundle (01–06)
Copy these scripts to your management workstation.
01_Enable-MRSProxy_Source.ps1
<# 01_Enable-MRSProxy_Source.ps1 Enables MRSProxy on Source (EWS), sets URLs & auth, increases MaxConnections. #> Get-WebServicesVirtualDirectory | fl Identity,ExternalUrl,InternalUrl,MRSProxyEnabled,BasicAuthentication,WindowsAuthentication,MRSProxyMaxConnections Set-WebServicesVirtualDirectory -Identity "EWS (Default Web Site)" ` -MRSProxyEnabled $true ` -ExternalUrl "https://mail.contoso.com/EWS/Exchange.asmx" ` -InternalUrl "https://mail.contoso.local/EWS/Exchange.asmx" ` -BasicAuthentication $true -WindowsAuthentication $true ` -MRSProxyMaxConnections 100 Restart-WebAppPool MSExchangeServicesAppPool Write-Host "MRSProxy on Source is enabled. Validate certificate chain and reachability (443) from Target." -ForegroundColor Green
02_PrepareMailUsers_Target.ps1
<# 02_PrepareMailUsers_Target.ps1
Prepares MailUsers in Target using Prepare-MoveRequest.ps1.
Removes existing empty target mailboxes and uses -UseLocalObject/-OverWriteLocalObject. #>
param(
[string]$SourceDC = "dc01.contoso.com",
[string]$TargetDC = "dc01.fabrikam.net",
[string]$TargetOU = "OU=MailUsers,OU=Exchange,DC=fabrikam,DC=net",
[string]$DeliveryDomain = "contoso.com",
[string]$CsvPath = "C:\\CFMig\\BigBang.csv"
)
# 1) Remove empty target mailboxes (keep AD accounts)
Import-Csv -Path $CsvPath | ForEach-Object {
$upn = $_.EmailAddress
try {
$mbx = Get-Mailbox -Identity $upn -ErrorAction Stop
if ($mbx) {
Write-Host "Disable-Mailbox for $upn (remove target mailbox)" -ForegroundColor Yellow
Disable-Mailbox -Identity $upn -Confirm:$false
}
} catch {
# No target mailbox ? OK
}
}
# 2) Run Prepare-MoveRequest.ps1
$srcCred = Get-Credential -Message "SOURCE (contoso) admin credentials"
$tgtCred = Get-Credential -Message "TARGET (fabrikam) admin credentials"
Set-Location "$env:ExchangeInstallPath\Scripts"
.\Prepare-MoveRequest.ps1 `
-RemoteForestDomainController $SourceDC -RemoteForestCredential $srcCred `
-LocalForestDomainController $TargetDC -LocalForestCredential $tgtCred `
-TargetMailUserOU $TargetOU -MailboxDeliveryDomain $DeliveryDomain `
-UseLocalObject -OverWriteLocalObject
Write-Host "MailUsers in Target are prepared (LegacyExchangeDN/X500/ProxyAddresses set)." -ForegroundColor Green
03_Create-MigrationEndpoint.ps1
<# 03_Create-MigrationEndpoint.ps1 Creates the migration endpoint for cross-forest remote moves (pull). #> $cred = Get-Credential -Message "SOURCE (contoso) admin credentials" New-MigrationEndpoint -Name "SRC2016" -ExchangeRemoteMove ` -RemoteServer "mail.contoso.com" ` -Credentials $cred ` -Autodiscover:$false Write-Host "Migration Endpoint 'SRC2016' created." -ForegroundColor Green
04_Create-And-Monitor-Batch.ps1
<# 04_Create-And-Monitor-Batch.ps1
Creates the BigBang batch, starts online seeding (AutoStart), and monitors progress. #>
param(
[string]$CsvPath = "C:\\CFMig\\BigBang.csv",
[string]$BatchName = "BigBang"
)
$csvBytes = [System.IO.File]::ReadAllBytes($CsvPath)
New-MigrationBatch -Name $BatchName -CSVData $csvBytes -AutoStart -AutoComplete:$false
Write-Host "MigrationBatch '$BatchName' created and started (AutoComplete=False)." -ForegroundColor Green
Write-Host "Monitoring (every 60s) - press CTRL+C to stop" -ForegroundColor Cyan
while ($true) {
$stats = Get-MigrationUser -BatchId $BatchName | Get-MigrationUserStatistics
$agg = $stats | Group-Object Status | Select-Object Name,Count
Clear-Host
Write-Host ("Batch '{0}' status (UTC {1}):" -f $BatchName, (Get-Date).ToUniversalTime().ToString("u")) -ForegroundColor White
$agg | Format-Table -AutoSize
$tot = $stats.Count
$syn = ($stats | Where-Object {$_.Status -eq "Synced"}).Count
$inprog = ($stats | Where-Object {$_.Status -eq "InProgress"}).Count
$fail = ($stats | Where-Object {$_.Status -eq "Failed"}).Count
Write-Host ("Total:{0} Synced:{1} InProgress:{2} Failed:{3}" -f $tot,$syn,$inprog,$fail) -ForegroundColor Yellow
Start-Sleep -Seconds 60
}
05_Complete-Batch.ps1
<# 05_Complete-Batch.ps1 Final cutover (Complete phase). Switch DNS (Autodiscover/MX) beforehand. #> param( [string]$BatchName = "BigBang" ) Get-MigrationUser -BatchId $BatchName | Get-MigrationUserStatistics | ft Identity,Status,PercentComplete -AutoSize Complete-MigrationBatch -Identity $BatchName Write-Host "Complete-MigrationBatch triggered. Users are being switched." -ForegroundColor Green
06_Delegation-Export-Import.ps1 (Template)
<# 06_Delegation-Export-Import.ps1 (Template)
Cross-forest moves do not carry delegations (FullAccess/SendAs/SendOnBehalf).
Export before, re-apply after cutover. #>
param(
[string]$DelegationCsv = "C:\\CFMig\\Delegations.csv"
)
Import-Csv $DelegationCsv | ForEach-Object {
$mbx = $_.Mailbox
$dlg = $_.Delegate
switch ($_.Rights) {
"FullAccess" { Add-MailboxPermission -Identity $mbx -User $dlg -AccessRights FullAccess -AutoMapping:$true -ErrorAction SilentlyContinue }
"SendAs" { Add-ADPermission -Identity $mbx -User $dlg -ExtendedRights "Send As" -ErrorAction SilentlyContinue }
"SendOnBehalf" { Set-Mailbox -Identity $mbx -GrantSendOnBehalfTo @{add="$dlg"} -ErrorAction SilentlyContinue }
}
}
CSV Template (BigBang.csv)
user1@fabrikam.net
user2@fabrikam.net
user3@fabrikam.net
...
References
- Microsoft Learn — Prepare mailboxes for cross-forest move requests (Exchange 2016/2019/SE)
- Microsoft Learn — Prepare-MoveRequest.ps1 (PowerShell)
- Microsoft Learn — Enable the MRS Proxy endpoint (EWS/MRSProxy)
- Microsoft Learn — Set-WebServicesVirtualDirectory (EWS, auth, MRSProxy)
- Microsoft Learn — New-MigrationBatch (batch moves, reporting)
- Ali Tajran — Mailbox migration best practices
- ThatLazyAdmin — MRS Proxy Connection Failed (troubleshooting)
- MS Q&A — Delegations cross-forest (not automatic)