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" "https://office.com"
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 "User.read" 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)
{
Enable-OrganizationCustomization
}
$dehydrated = Get-OrganizationConfig | select isdehydrated
if ($dehydrated.isdehydrated -eq $true)
{
Enable-OrganizationCustomization
}
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 outlook.office.com -RemoteTenant "serveralive.onmicrosoft.com" -Credentials $Credential -ExchangeRemoteMove:$true -Name "ServerAliveMigrationEndpoint" -ApplicationId $AppId
$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 outlook.office.com -RemoteTenant "serveralive.onmicrosoft.com" -Credentials $Credential -ExchangeRemoteMove:$true -Name "ServerAliveMigrationEndpoint" -ApplicationId $AppId
Organization Relationship
Create a new Organization Relationship with MailboxMoveCapability Inbound
#OrganizationRelationship
$SourceTenantName="serveralive.onmicrosoft.com"
$SourceTenantId="ebc81bf5-2cef-414c-a948-2bbb116fae48"
$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 serveralive.onmicrosoft.com | fl
$SourceTenantName="serveralive.onmicrosoft.com"
$SourceTenantId="ebc81bf5-2cef-414c-a948-2bbb116fae48"
$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 serveralive.onmicrosoft.com | fl
Source Tenant
Grant the Permissions to the Azure AD App in the Source Tenant
$AppID="6aa3cf87-4754-43e2-8ec6-606f6b938ae8"
$SourceTenant = "serveralive.onmicrosoft.com"
$URL = "https://login.microsoftonline.com/$SourceTenant/adminconsent?client_id=$AppID&redirect_uri=https://office.com"
$URL
$SourceTenant = "serveralive.onmicrosoft.com"
$URL = "https://login.microsoftonline.com/$SourceTenant/adminconsent?client_id=$AppID&redirect_uri=https://office.com"
$URL
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
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
$TargetTenantName="icewolfch.onmicrosoft.com"
$TargetTenantId="46bbad84-29f0-4e03-8d34-f6841a5071ad"
$AppID="6aa3cf87-4754-43e2-8ec6-606f6b938ae8"
$scope="T2TMigrationEXO"
$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 icewolfch.onmicrosoft.com | fl
$TargetTenantId="46bbad84-29f0-4e03-8d34-f6841a5071ad"
$AppID="6aa3cf87-4754-43e2-8ec6-606f6b938ae8"
$scope="T2TMigrationEXO"
$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 icewolfch.onmicrosoft.com | 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 "h.muster@icewolf.ch" -ExternalEmailAddress "hans.muster@serveralive.ch" -Alias "h.muster" -OrganizationalUnit "corp.icewolf.ch/Icewolf Users" -UserPrincipalName "h.muster@icewolf.ch" -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
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 icewolfch.onmicrosoft.com
Check the Migration Batch
Get-MigrationBatch
After a while you can see also the Moverequests
Get-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
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-MigrationBatch
Get-MoveRequest
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 Hans.Muster@serveralive.ch will now be forwarded to h.muster@icewolfch.onmicrosoft.com.
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.
Regards
Andres Bohren