Back to Home
Big‑Bang Exchange Cross‑Forest Migration
Exchange24. Januar 2026

Big‑Bang Exchange Cross‑Forest Migration

Drago Petrovic

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.

Deliverable: Complete, step-by-step runbook including timeline, preparations, PowerShell commands & scripts, checklists, cutover, post-tasks, rollback plan, and 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.ps1 in Target to create/update MailUsers for all to-be-migrated users.
  • Test MRS connectivity from Target: Test-MigrationServerAvailability against 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)

  1. DNS cutover: Switch Autodiscover (and MX if applicable) to Target.
  2. Run Complete-MigrationBatch ? final switch per mailbox (brief interruption).
  3. 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)

EmailAddress
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)

  1. DNS switch (Autodiscover and MX if applicable) to Target.
  2. Complete the batch:
    Complete-MigrationBatch -Identity "BigBang"
  3. 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-MigrationServerAvailability successful.
  • CSV BigBang.csv validated.
  • 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-MigrationBatch executed.
  • 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 MRSProxyMaxConnections moderately (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)

EmailAddress
user1@fabrikam.net
user2@fabrikam.net
user3@fabrikam.net
...

References