🧩Introduction
Several years ago, that was a pleasure for me to work with 🔗Artur as one of my customers. A lot of things have changed since when, Artur is working now on different projects, in particular related to Office 365 and Exchange Server.
Several times he helped customers with cross-tenant migrations related to Exchange Online specifically and we decided that it would be great to share his experience on that topic.
✅Scenario description
Not a long time ago Microsoft included the requirement of having Cross Tenant User Data Migration License for mailbox migrations between tenants. This Add-on is available only for Enterprise Agreement customers.

For more information, please, visit 🔗Cross-tenant mailbox migration official article.
Of course, the easiest way to resolve this issue is to get an appropriate license. But sometimes, customers are not able to purchase this license for any reason.
The most interesting thing about this: What I have to do if I have few small tenants, like 2 or 3 or higher and my company doesn’t have Enterprise Agreement?
You might be using two ways in this situation:
- Buy a 3rd party solution to accomplish migration between tenants. For example, Quest On Demand Data Migration or BitTitan MigrationWiz.
- Handle migration through Exchange On-Premises.
In some specific situations customers can have appropriate licenses or even have some Exchange on-premises servers already installed, but they don’t maintain hybrid configuration.
Also, Exchange trial edition functions just like an Exchange Standard Edition server and is helpful if you want to try out Exchange before you buy it, or to run tests in a lab. The only difference is that you can only use an Exchange server licensed as a trial edition for up to 180 days . In this way you shouldn’t waste money on one time using migration software. Additional information can be found here 🔗Additional information on Exchange Server Licensing. That’s also a good idea to consult Microsoft Licensing services to be sure that you don’t violate any licensing rules.
💡Note. Standard Edition is limited to five mounted databases per server. Also, default database size limit for Microsoft Exchange Server Standard Edition is 1,024 gigabytes (GB). There is no default database size limit for the Enterprise Edition. The Exchange store checks database size limits periodically and dismounts a database when the size limit is reached. This issue is described in article below: 🔗Exchange Server 2013, 2016 and 2019 Standard Edition can’t mount databases that are larger than 1024 GB You need to take this into account, while planning your infrastructure.
Today we’re going to share the process of mailbox migration from Exchange Online to Exchange on-premises without running Hybrid Deployment Wizard and configuring most important settings manually. The result of it you’ll have the possibility to migrate mailboxes from EXO to on-premises. It helps you in the situation when you have to migrate to on-prem and you can’t do this because you already have Hybrid Deployment with your current tenant.
The same process also suits in scenarios of merging or taking-over companies. Of course, you’ll be able to access free/busy information and / or perform cross-organization mailbox migration (per this article this was tested only one way, from EXO to on-prem).
📌Test enrollment
Test enrollment used in specific scenario is described below:
- Exchange Server 2019 CU12 Standard edition (Exchange 2016 is also applicable);
- Test O365 tenant;
- Accepted domain sl-myapp.online configured in Exchange 2019 organization;
- Trusted wildcard certificate issued by Let’s Encrypt and configured on Exchange 2019 servers;
- Public IP. Mikrotik CHR is used for publishing SMTP and Exchange Web Services;
- Test mailboxes in EXO;
💡Note. While migrating mailboxes from one tenant to another, there will be a specific period when mailboxes will be located temporarily on your Exchange on-premises servers. You should define your requirements for high availability and fault tolerance, co-existence between EXO and on-premises mailboxes (free / busy, delegation and so on). It’s also important to understand how long users will live in co-existing scenarios. If you need to migrate a small number of users, you would probably do it fast during weekend with small interruption of services than waste your time on configuring rich co-existence close to full-hybrid mode.
But in some cases, you will probably need to implement high availability configuration with Database Availability Groups, load balancing and so on. Use 🔗Exchange Server 2019 Sizing Calculator to estimate the hardware requirements for new Exchange Server environments.
🧩Configure federation trust with Microsoft Entra Authentication System
If you still not familiar with 🔗Deep Dive: How Hybrid Authentication Really Works blog post, we would recommend to go though it to read more about Federation Trust, DAUTH, OAUTH and etc. in more detail.
In case of long co-existence, if you don’t have Hybrid mode configured with another tenant, it would be probably easier and recommended running HCW and configuring a full hybrid mode. In organization with latest Exchange versions HCW doesn’t create federation trust and 🔗configures OAUTH only instead.
We could also go in this way, but configuring federation trust is less complex. A 🔗federation trust is a trust relationship between a Microsoft Exchange organization and the Microsoft Entra authentication system (known before as Microsoft Federation Gateway). It is possible that in a particular scenario you could use an existing federated trust, which would further simplify the configuration process.
- If you already have an on-premises Exchange environment, it’s not brand new, probably in Hybrid mode with another tenant, verify if you have federation trust already configured.

If you see similar output, you should test your federation trust with Test-FederationTrust cmdlet (discussed later in this chapter). If everything is OK, you can go to next chapter “Configure Exchange On-Premises”
If you don’t have federation trust in place, proceed with the next steps. There are no specific steps in here comparing to 🔗official article.
2. Create new certificate and federation trust:
$ExchKeyId = [System.Guid]::NewGuid().ToString(“N”)
New-ExchangeCertificate -FriendlyName “Exchange Federated Sharing” -DomainName
$env:USERDNSDOMAIN -Services Federation -KeySize 2048 -PrivateKeyExportable $true -SubjectKeyIdentifier $ExchKeyId
Get-ExchangeCertificate | ?{$_.FriendlyName -eq “Exchange Federated Sharing”} | New-FederationTrust -Name “Trust to MFG”

3. Next command will return the proof of domain ownership TXT record that’s required for any domain that you’ll configure for the federation trust:
Get-FederatedDomainProof -DomainName sl-myapp.online

Just insert the corresponding txt record in your public DNS zone and wait for about 15 -30 minutes.
4. Then, retrieve metadata and certificate from MFG:
Set-FederationTrust -RefreshMetadata -Identity “Trust to MFG”

5. Configure the primary shared domain for the federation trust:
Set-FederatedOrganizationIdentifier -DelegationFederationTrust “Trust to MFG” -AccountNamespace sl-myapp.online -Enabled $true

6. Try to check federation trust by the command below. Below we added alias postmaster for administrator’s on-premises mailbox:
Test-FederationTrust -UserIdentity postmaster@sl-myapp.online

All 6 steps mentioned above must be finished successfully.
🧩Configure Exchange On-Premises
In this article we will skip configuration steps for SPF, MX DNS records and publishing Exchange Server because it’s out of scope of this blog post.
The next step is configuring organization relationship for your on-premises Exchange. Don’t forget to enable MRS Proxy on EWS virtual directory.
Get-WebServicesVirtualDirectory | select MRSProxyEnabled, *url*
By default, MRS Proxy is disabled, and you must enable it by the next command:

Set-WebServicesVirtualDirectory -Identity “EX01\EWS (Default Web Site)” -MRSProxyEnabled $true
At this step, we expect that our Exchange server is published correctly. Let’s try to check connectivity and use 🔗Microsoft Remote Connectivity Analyzer (Exchange Server -> Outlook Connectivity test) to test user1 created especially for this step.

You can see some warnings, but for this scenario it’s ok, nothing special. Results will be different for various configurations, review them carefully.
The next step is creating a special service on-premises user and granting him Recipient Management Role. You can use existing user with appropriate permissions or create a new on and add him to appropriate Active Directory group:

🧩Configure organization relationship in Exchange On-Premises
The command below will create organization relationship between your Exchange on-premises and EXO tenant. Optionally, you can enable availability information (Free / Busy), mailtips and other features, but it’s not necessary for initial scenario. Don’t forget to customize this command and point DomainNames parameter to your native M365 mail domain (your_domain.mail.onmicrosoft.com):
New-OrganizationRelationship -Name to-EXO -TargetAutodiscoverEpr https://autodiscover-s.outlook.com/autodiscover/autodiscover.svc/WSSecurity -TargetApplicationUri outlook.com -TargetOwaURL https://outlook.office.com/mail -FreeBusyAccessEnabled 1 -FreeBusyAccessLevel LimitedDetails -MailboxMoveEnabled 1 -Enabled 1 -MailTipsAccessEnabled 1 -MailTipsAccessLevel All -PhotosEnabled 1 -DomainNames sl-myapp.online,YOUR_NATIVE_M365_MAIL_DOMAIN.mail.onmicrosoft.com, YOUR_NATIVE_M365_DOMAIN.onmicrosoft.com

🧩Configure organization relationship and migration endpoint in Exchange Online
- Next, we need to perform the same step in Exchange Online.
You might need to run 🔗Enable-OrganizationCustomization cmdlet first. Use the next command to verify and correct your current configuration if needed:
$dehydrated=Get-OrganizationConfig | select isdehydrated
if ($dehydrated.isdehydrated -eq $true) {Enable-OrganizationCustomization}

2. After that we need to create a migration endpoint. Customize this command and set your external url for Exchange server and corresponding credentials for user account, created on previous steps:
$User = ‘contoso\svc_migration-onprem’
$PWord = ConvertTo-SecureString -String ‘password’ -AsPlainText -Force
$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $PWord
New-MigrationEndpoint -ExchangeRemoteMove:$true -RemoteServer “mail.sl-myapp.online” -Credentials $Credential “to-On-Prem”

3. Now, let’s create Organization Relationship.
New-OrganizationRelationship “to-Exchange-On-Premises” -Enabled:$true -DomainNames sl-myapp.online -MailboxMoveEnabled:$true -MailboxMoveCapability RemoteOutbound -MailboxMovePublishedScopes $scope -FreeBusyAccessEnabled:$true -FreeBusyAccessLevel LimitedDetails -MailTipsAccessEnabled:$true -MailTipsAccessLevel All -PhotosEnabled:$true -TargetApplicationUri FYDIBOHF25SPDLT.sl-myapp.online -TargetAutodiscoverEpr https://autodiscover.sl-myapp.online/autodiscover/autodiscover.svc/WSSecurity

4. Also, in this part we will create distribution group which members will be able to migrate mailboxes to on-premises.
$scope=”Group for Migration from EXO”
New-DistributionGroup -Type Security -Name $scope
Don’t forget to add cloud users to this group. For example, in the command below we’ve added AdeleV mailbox in the group.

5. Check the relationships between organizations.
Example below will show relationship verification from Exchange Online side:

Next, try to check relationship from Exchange on-premises:

🧩Prepare User Object
Firstly, we need to draw your attention on next moment: in this guide we tell about sl-myapp.online domain, which is accepted domain in Exchange Online and Exchange On-premises. But it doesn’t matter which domain you use. The most important thing is about appointing attributes.
Microsoft has an article 🔗Cross-tenant mailbox migration that describes specific prerequisites for target user objects. This article contains a lot of detailed information, so if you would like to get more on that topic, you can dig into it.
Next step we will create a user2 in on-premises environment – you can use Active Directory Users and Computers snap-in or other way you got used to create user’s accounts. This mailbox will match AdeleV user mailbox in Exchange Online. To make it work, we will get the required information about AdeleV mailbox from EXO and provision user2 as MailUser with specific attributes.
Run command below in Exchange on-premises powershell to enable remote mailbox for user2 (we suppose that user2 is already created in on-premises Active Directory):
Enable-RemoteMailbox user2 -RemoteRoutingAddress “AdeleV@Your_M365_Tenant_Name.onmicrosoft.com” -PrimarySmtpAddress “user2@sl-myapp.online”
In this scenario cloud mailbox will not be created, as active directory synchronization is not configured.
On other way, you can create mail user for that object:
new-mailuser user2 -ExternalEmailAddress “AdeleV@Your_M365_Tenant_Name.onmicrosoft.com” -PrimarySmtpAddress “user2@sl-myapp.online”
For most scenarios, it’s enough that target MailUser will have attributes below from the source EXO mailbox:
- ExchangeGuid
We need to get ExchangeGuid attribute from EXO user AdeleV and set corresponding value for user2:
[guid]$ExchangeGUID = (Get-Mailbox AdeleV).ExchangeGuid
$ExchangeGUID.Guid

Then set msExchMailboxGuid attribute in AD DS for user2 to corresponding value:
Set-ADUser user2 -Replace @{‘msExchMailboxGuid’=$ExchangeGUID}

2. ArchiveGUID
Perform similar steps for ArchiveGUID attribute.
[guid]$ArchiveGUID = (Get-Mailbox AdeleV).ArchiveGuid
$ArchiveGUID.Guid
Set-ADUser user2 -Replace @{‘msExchArchiveGUID’=$ArchiveGUID}

3. LegacyExchangeDN
As we know, this attribute is used for message delivery in Exchange environments. In Outlook, autocomplete cache stores all LegacyExchangeDN’s attributes for every recipient you’ve ever sent emails before. If you’ve migrated mailbox to another Exchange organization the LegacyExchangeDN attribute will be changed and user’s will get errors after sending emails to mailbox which was migrated.
We can prevent this issue by adding LegacyExchangeDN in proxyAddress attribute in format of x500 address: x500:/LegacyExchangeDN (from old Exchange).
[string]$ProxyAddress = (Get-Mailbox AdeleV).LegacyExchangeDN
$ProxyAddress
Set-ADUser user2 -Add @{‘ProxyAddresses’=”x500:”+$ProxyAddress}

4. ProxyAddresses
We must add all email addresses from EXO to On-premises user. In my situation it’s just one email address based on native Microsoft domain.
$EmailAddresses = ((Get-Mailbox AdeleV).emailaddresses | Select-String -Pattern “smtp”).ToString().ToLower()
Set-ADUser user2 -Add @{‘ProxyAddresses’=$EmailAddresses}

Let’s check provisioned user in AD DS.

Note. In specific scenarios, you would also like to migrate additional attributes like msExchBlockedSendersHash and so on, if user consume specific functionality in EXO. Please, review article Cross-tenant mailbox migration for more information.
🧩Start offboarding batch from EXO
Before we can start mailbox migration, it would be good to verify that basic functionality works as expected.
For example, we can test availability of migration endpoint from EXO:
Test-MigrationServerAvailability -EndPoint “to-On-Prem” -TestMailbox “user2@sl-myapp.online”

Next, create the CSV file with emails of users, you need to migrate from EXO to on-prem. CSV file contains only emails from source tenant:

Next, let’s create and start migration batch. You also might create batches in Exchange Online Admin Center.
New-MigrationBatch -Name OneUserBatch -TargetEndpoint to-On-Prem -CSVData ([System.IO.File]::ReadAllBytes(‘C:\users.csv’)) -Autostart -TargetDeliveryDomain sl-myapp.online -TargetDatabases MDB01 -TargetArchiveDatabases MDB01 -AutoComplete

In this example we don’t explicitly set target mailbox and database names, but you can do that if you want.
You can check the process in Exchange Online Admin Center in Migration menu or by using PowerShell.
Get-MigrationUser AdeleV@Your_M365_Tenant_Name.OnMicrosoft.com | Get-MigrationUserStatistics | select BatchId, Identity, Status, StatusSummary, State,WorkflowStep, WorkflowStage

In this specific scenario we can also check Mikrotik CHR for the process.

A few minutes later we be able to see the result.

Let’s check what was happened after migration with recipient object in EXO.
Get-Recipient AdeleV | select Alias,RecipientTypeDetails,PrimarySmtpAddress,ExternalEmailAddress

Check the same in Exchange On-Premises:

That means that messages sent from users in EXO to AdeleV now will be relayed to Exchange On-premises. Because we configured federation trust, free/busy information will be available without GAL sync.
Next, we will open OWA for user@sl-myapp.online

You can check which items were skipped during the migration.
Get-MigrationUser AdeleV@Your_M365_Tenant_Name.OnMicrosoft.com | Get-MigrationUserStatistics -IncludeSkippedItems | select Skip*
🔍Conclusion
In his blog we’ve demonstrated how to use special technic Artur usually use to migrate from EXO to on-prem. After performing stage 1 (Offboarding from EXO), you must dis assign your custom domain in Microsoft Entra and start stage 2 (Onboarding to new EXO tenant) preferably by using Azure AD Connect and Hybrid Configuration Wizard (and in some cases, this configuration with new tenant will be already in-place).
Of course, you can do this without AAD connect and HCW, but you must create users in Microsoft Entra with or without Azure AD Connect with the same specific attributes. But this is not a recommended way to achieve the goal.
End.

Leave a comment