Exchange Online Cross-tenant mailbox migration (preview)

Hi All,

There is a Preview for M365 Tenant to Tenant Migration of Exchange Mailboxes. I've tested this in my Lab. Took me several Days to complete the Migration or until i understand everything correctly and had everything fixed.

Cross-tenant mailbox migration (preview)

I've created this Overview to explain it a bit more. Here are all prerequisits to create a Tenant to Tenant (aka Cross-tenant) Mailbox Migration.

Target Tenant

Azure AD Application

Create a new Azure AD App registration

Give it a Name, select Multitenant and Redirect URL is "Web" ""

Add a ClientSecret

Add Permissions from "APIs my organization uses" and search for "Office 365 Exchange"

Select Application Permission and select "Mailbox.Migration"

The default Permission "" can be removed. Afterwards cklick on "Grant Admin Consent"

That's how it should look at the end

Migration Endpoint

Check the OrganizationCustomization

# Enable customization if tenant is dehydrated
$dehydrated = Get-OrganizationConfig | select isdehydrated
if ($dehydrated.isdehydrated -eq $true)

Now you can create a new Migration Endpoint with the AzureAD AppId and the ClientSecret as Password.

#New MigrationEndpoint
$AppId = "6aa3cf87-4754-43e2-8ec6-606f6b938ae8"
$ClientSecret = "YourClientSecret"
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $AppId, (ConvertTo-SecureString -String $ClientSecret -AsPlainText -Force)
New-MigrationEndpoint -RemoteServer -RemoteTenant "" -Credentials $Credential -ExchangeRemoteMove:$true -Name "ServerAliveMigrationEndpoint" -ApplicationId $AppId

Organization Relationship

Create a new Organization Relationship with MailboxMoveCapability Inbound

$OrgRels = Get-OrganizationRelationship
$ExistingOrgRel = $OrgRels | ?{$_.DomainNames -like $sourceTenantId}
If ($null -ne $ExistingOrgRel)
    Set-OrganizationRelationship $existingOrgRel.Name -Enabled:$true -MailboxMoveEnabled:$true -MailboxMoveCapability Inbound
If ($null -eq $existingOrgRel)
    New-OrganizationRelationship $SourceTenantName -Enabled:$true -MailboxMoveEnabled:$true -MailboxMoveCapability Inbound -DomainNames $sourceTenantId

Get-OrganizationRelationship -Identity | fl

Source Tenant

Grant the Permissions to the Azure AD App in the Source Tenant

$SourceTenant = ""
$URL = "$SourceTenant/adminconsent?client_id=$AppID&redirect_uri="

Use the URL in the Browser

Accept the Permissions

Create a Mail enabled Security Group

Create the Mail enabled Security Group. Only Members of that Group can be migrated later on.

#Create MailEnabled Security Group
New-DistributionGroup -Name "T2TMigrationEXO" -Alias T2TMigrationEXO -Type security

Create Organization Relationship

Now we need to create an Organization Relationship with the MailboxMoveCapability RemoteOutbound

#Organization Relationship in Source
$OrgRels = Get-OrganizationRelationship
$ExistingOrgRel = $OrgRels | ?{$_.DomainNames -like $targetTenantId}
If ($null -ne $existingOrgRel)
    Set-OrganizationRelationship $existingOrgRel.Name -Enabled:$true -MailboxMoveEnabled:$true -MailboxMoveCapability RemoteOutbound -OAuthApplicationId $appId -MailboxMovePublishedScopes $scope
If ($null -eq $existingOrgRel)
    New-OrganizationRelationship $TargetTenantName -Enabled:$true -MailboxMoveEnabled:$true -MailboxMoveCapability RemoteOutbound -DomainNames $targetTenantId -OAuthApplicationId $appId -MailboxMovePublishedScopes $scope

Get-OrganizationRelationship -Identity | fl

Source Mailbox

Now it's time to Gather Infos from the Source Mailbox
We need:
  • PrimarySMTPAddress
  • MailboxGUID
  • LegacyExchangeDN
  • All X500 EmailAdresses

Target Mail User

The Target needs to be a Mail user.

In my Environement i create the Mail User on my Exchange Server OnPrem. The ExternalEmailAddress is the PrimarySMTPAddress from the Source.

$Password = ConvertTo-SecureString "MySecretPassword" -AsPlainText -Force
New-Mailuser -Name "Hans Muster" -FirstName "Hans" -LastName "Muster" -PrimarySmtpAddress "" -ExternalEmailAddress "" -Alias "h.muster"  -OrganizationalUnit " Users" -UserPrincipalName "" -SamAccountName "h.muster" -Password $Password

Now we ned to set the MailboxGUID und the LegacyExchangeDN and all X500 from the Soure Mailbox as X500 Addresses on the Target Mail User

$ExchangeGuid = "9e82fc17-be93-4aac-8214-0c1118700728"
$Mailuser = Get-MailUser h.muster
$EmailArray = $Mailuser.EmailAddresses
$EmailArray.Add("X500:/o=ExchangeLabs/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=4b58e230c8a64b16a4fc919c818172a0-Hans Muster")
$EmailArray.Add("x500:/o=First Organization/ou=External (FYDIBOHF25SPDLT)/cn=Recipients/cn=817c735da1b043cd9f44725d6bf06fc3")
$EmailArray.Add("X500:/o=First Organization/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=e7ff61a4af774705ad0872b051070535-Hans")
Set-MailUser h.muster -ExchangeGuid $ExchangeGuid -EmailAddresses $EmailArray

If there was a Mailbox before make sure it is deleted in Exchange Online completely

#Clear old Mailboxes
Set-User k.klammer -PermanentlyClearPreviousMailboxInfo

Let's wait for AAD Connect until the Mail User has been syncronized to Exchange Online

Test Migration

Connect to Exchange Online in the Target Tenant.

Now we can test if everything works. You need to use the MigrationEndpoint we created earlier with the Primary Emailadress of the Target Mail User

If you receive an Error it will look like this.
Check again if you have added all X500 from the Source Mailbox
And also added the LegacyExchangeDN from The Source Mailbox as X500 on the Target Mailuser
Don't forget to set the MailboxGUID on the Target Mailuser

Migration Batch

Now we can create a Migration Batch. The CSV Format for the Batchfiles are documented in the Link below

CSV files for mailbox migration

Now we can create the Migration Batch with the CSV File

New-MigrationBatch -Name T2TMigrationBatch -SourceEndpoint ServerAliveMigrationEndpoint -CSVData ([System.IO.File]::ReadAllBytes('C:\Temp\users.csv')) -Autostart -TargetDeliveryDomain

Check the Migration Batch


After a while you can see also the Moverequests

Get-MoveRequests | Get-MoveRequestStatistics

You can see the Migration Batch also in the Echange Online Admin Center

Every 24 Hours i receive a Status Report per Email

Complete Migration

The Sync of the Mailbox is up to 95%. Now we can complete the Migration Batch.

Get-MigrationBatch -Identity T2TMigrationBatch
Complete-MigrationBatch - Identity T2TMigrationBatch

Once the Migration Batch has been completed, i receive a Completion Mail

The Moverequest has been Completed

Get-MoveRequest -Identity <Identity> | Get-MoveRequestStatistics

Mail User in Source after Migration

After the Migration the Mailbox in the Source has been convertet to a Mail User. The ExternalEmailAddress has been set to the M365 Emailaddress. Emails to will now be forwarded to

Get-Mailuser -Identity hans.muster | fl Name, *Email*

Target Mailbox after Migration

And this is how the Mailbox in the Target Tenant looks after the Migration.

Get-Mailbox h.muster | fl name, *email*, *smtp*

Final Words

This "built-In" Method of Tenant to Tenant (or Cross-tenant) Mailbox Migration works fine.
But for a Migration for multiple Mailboxes, there is some serious Scripting needed.
Get all the Attributes from the Soure Mailboxes and create the Mailusers in the Target Tenant.

But remember, with that only the Mailboxes are moved. But there exist many more Mail enabled Objects:
  • Mail Contacts
  • Mail Users
  • Distribution Groups
  • M365 Groups / Teams
These Objects are not Covered and might have to be created also in the Target Tenant.

Andres Bohren