Exchange Online Native Tenant to Tenant Migrations (Preview)

With the proliferation of Microsoft 365 as the collaboration platform of choice in the enterprise space, it’s rare to find a large organization that hasn’t undergone some form of tenant to tenant migration. This can be a result of mergers, acquisitions or divestitures. Microsoft have not previously had any native tooling to facilitate this and third parties such as BitTitan and Quest have built up some really slick products to help organizations manage this technical transition.

This has slowly begun to change with the Microsoft acquisition of Mover in 2019 to help facilitate file migrations to Office 365. Microsoft seem to be making more native migration functionality available as part of the service. The most mature of the migration tools is also the oldest, the native Exchange on-premises migration tools using Exchange MRS functionality. This has also been improved recently with the availability of the Exchange modern hybrid configuration, removing the need to open up on-premises endpoints to the cloud by leveraging application proxy technology.

This Exchange functionality has now been extended to cross-tenant migrations allowing the migration of mailboxes from one tenancy to another using the familiar Exchange migration tools.

Prepare for Migration

First we need to set up our environments for the tenant to tenant migration. To understand the configuration, Microsoft have published the below diagram which explains the process in detail:

So from this diagram, we can see the high level componants of the migration infrastructure are:

  • A Tenant relationship application registration in the destination tenancy with the below API permissions
    • Exchange: Mailbox.Migration
    • Graph: Directory.ReadWrite.All
  • Azure KeyVault stores the app secret details for this app
  • The Source Tenant grants consent to the tenant relationship app created in the destination tenant
  • A two way Organization Relationship
  • A mail enabled security group in the source tenant to scope mailboxes for migration

Luckily, Microsoft have automated a lot of this setup with PowerShell scripts located on GitHub:

Source – SetupCrossTenantRelationshipForResourceTenant.ps1

Target – SetupCrossTenantRelationshipForTargetTenant.ps1

Prepare the Target Tenant

To prepare the target tenant, download the SetupCrossTenantRelationshipForTargetTenant.ps1 script.

To run the setup script, ensure you have the ExchangeOnlineManagement, AzureAD (the Preview Module doesn’t seem to work) and AzureRM PowerShell modules installed, if you don’t, you can do that with the below commands:

Install-Module ExchangeOnlineManagement
Install-Module AzureRM
Install-Module AzureAD

Once the modules are installed, connect to Exchange Online with:


Now we can finally run the first script. The following paramaters are required to run:

  • -ResourceTenantDomain The mail domain of the source tenant
  • -ResourceTenantAdminEmail The email address for the admin account in the source tenant. Ensure this account has a valid mailbox.
  • -TargetTenantDomain the mail domain of the target tenant
  • -ResourceTenantId The source tenant Azure AD Directory ID
  • -SubscriptionId The Subscription ID to create the KeyVault in
  • -ResourceGroup A name for the KeyVault Resource Group
  • -KeyVaultName A name for the KeyVault
  • -CertificateName A name for the certificate
  • -CertificateSubject A certificate subject name: “CN=admin_seanmc”
  • -AzureAppPermissions The permissions to grant: Exchange, MSGraph
  • -UseAppAndCertGeneratedForSendingInvitation
.\SetupCrossTenantRelationshipForTargetTenant.ps1 -ResourceTenantDomain <Source Tenant mail domain> -ResourceTenantAdminEmail <Source Tenant Admin Account Email> -TargetTenantDomain <Target tenant domain> -ResourceTenantId <Source Tenant Directory ID> -SubscriptionId <Azure Subscription ID> -ResourceGroup "CrossTenantMoveRG" -KeyVaultName "adminseanmc-Cross-TenantMovesVault" -CertificateName "adminseanmc-cert" -CertificateSubject "CN=admin_seanmc" -AzureAppPermissions Exchange, MSGraph -UseAppAndCertGeneratedForSendingInvitation 

This script will prompt for destination tenant credentials twice during its run and then will pause, asking for you to grant consent to the new app registration. In Azure AD App Registrations, open the new app and grant consent to the API permissions.

When consent is granted, hit enter on the script to continue and set up the Organization relationship.

Finally, note down the Application ID that is saved to the $AppID variable in the PowerShell session. If you miss this you can get it from the Azure AD app registrations page also.

Prepare the Source Tenant

Now that the destination tenant is configured, we can move on to the source tenant. When running the previous script, we were asked for an admin email address in the source tenant. When we log into this account we will find a B2B invitation from the destination tenant admin. Open this mail and accept the invitation.

Next, accept the permission request from the application to allow it to pull mailbox data.

With the permissions in place, we now create a mail-enabled security group to manage our migration scope. All mailboxes to be migrated will be part of this group. To create a group you can run the below Exchange Online PowerShell Command in the source tenant.

New-DistributionGroup t2tmigrationscope -Type security

Then add any in-scope mailboxes to the group with the below command.

Add-DistributionGroupMember -Identity t2tmigrationscope -Member <Mailbox to add>

With our scope in place, we can now prepare and run the source tenant preparation script. To run the script, we need the following parameters:

  • SourceMailboxMovePublishedScopes – This is our mail enabled security group created previously
  • ResourceTenantDomain – This is our source tenant mail domain
  • TargetTenantDomain – This is our target tenant mail domain
  • ApplicationId – This is the Application ID we noted during the target configuration
  • TargetTenantId – Azure AD Directory ID of the target tenant

With all of this information to hand, run the script SetupCrossTenantRelationshipForResourceTenant.ps1 as below:

SetupCrossTenantRelationshipForResourceTenant.ps1 -SourceMailboxMovePublishedScopes <security group identity> -ResourceTenantDomain <source tenant mail domain> -TargetTenantDomain <target tenant domain> -ApplicationId s<AppID> -TargetTenantId <source tenant directory ID>

When this is complete we have all permissions in place and our Organization Relationship is in place so we can move on to preparing our users.

Prepare Destination User Accounts

To migrate a mailbox cross-tenant, we need to have a valid mail user in the destination tenant. There are several attributes we need to ensure align between the two to make sure the migration is successful. To gather the required data, run the below command against the mailbox(s) you wish to move in the source tenant.

get-mailbox <mailbox> |select exchangeguid,archiveguid,legacyexchangedn,userprincipalname,primarysmtpaddress 

This will give an output similar to the below.

Use this output to create a new mail user in the destination tenant. This setup can vary depending on if your destination environment is synchronized with Active Directory but for a non-synchronized environment, the below commands in Exchange Online PowerShell should create the user with the appropriate attributes.

New-MailUser <alias> -ExternalEmailAddress <source tenant email> -PrimarySmtpAddress <destination tenant email> -MicrosoftOnlineServicesID <destination tenant username>    

PS C:> Set-MailUser debrab -ExchangeGuid <exchangeGUID from source> -ArchiveGuid <archiveGUID from source> -EmailAddresses @{Add="x500:<LegacyExchangeDN from Source>"}                                                          

Finally, once these attributes are present, give the new user(s) a valid Exchange Online license. If everything was done correctly, no Exchange Online mailbox will be provisioned when the user is licensed.

With the account(s) created, finally all the prep work is done so we can now move on to testing migrations.

Start Cross-Tenant Migration Batch

Before starting the migration, we can create a comma delimited CSV file so we can import our batch. the CSV only needs a single column named ‘EmailAddress’ and should specify each target tenant email address for our user batch.

To create a new cross tenant migration request, we navigate to the new Exchange Admin Center at from the destination tenant and open up the “Migration” section. From here we create a new migration batch and select “Migration to exchange Online”

Next we select the migration type “Cross tenant migration”

We can see the prerequisites we’ve worked through listed on the next page, since we’ve done all the work already, we can hit next.

On the next page, we select the migration endpoint our script configured and hit next.

Next, upload the CSV file we prepared earlier.

Finalize the standard move configuration settings.

Configure any scheduling we need to perform and finally hit “save” to kick off the migration batch.

When the batch is created, we’ll see the success page below and then we can check the status throughout via the migration batches or by PowerShell.

After a little while the migration is synced. We can complete it as we would with any other migration batch.

We have now successfully migrated from one Exchange Online Tenant to another with native tools. When this functionality goes GA, it could really change the way a lot of Organizations approach multi-tenant configurations and migrations. For more information on Tenant to Tenant migrations, see the official Microsoft documentation here: Cross-tenant mailbox migration – Microsoft 365 Enterprise | Microsoft Docs

Azure AD Group Role Assignment – Exchange Online Access Denied

Azure AD Group Role Assignment is a great new preview feature that provides a lot of flexibility and governance to assigning admin roles in Azure AD / Office 365. When combined with Privileged Identity Managements new Privileged Access Groups (Preview) feature, we can begin to set up a really slick permission eligibility structure that is both easy to manage and easy to administer.

I recently came across an issue when testing this set up. I had requested and activated my Global Admin role via a dedicated global admin role group and got into the Admin Portal without issue. I then opened the Exchange Online Admin Portal and was greeted with this message:

Very strange considering I was now logged in as a Global Admin and could see pretty much everything in the Admin Portal. I tried the usual signing out and clearing cookies etc. but couldn’t get it to work.

Finally I did some digging into the documentation and sure enough found my problem within the known issues section of the ‘Assign Roles to Groups‘ section.

“Use the new Exchange Admin Center for role assignments via group membership. The old Exchange Admin Center doesn’t support this feature yet. Exchange PowerShell cmdlets will work as expected.”

From the documentation I could see that the regular Exchange Admin Center doesn’t support Group Based role assignments yet. Ok, no problem, except the link in the Admin Portal takes me directly to the old Admin Center, with no option for the new until you are logged in.

To work around this we can just go directly to and gain access with our group based role assignment.

Luckily Microsoft documentation is miles ahead of where it used to be and this was quickly found and resolved, even if I felt a bit stupid for not realizing this limitation in the first place. Can’t really complain considering it’s a preview feature currently.

There are a few other known issues to be aware of with Group Based role assignments but for the most part I have found the perform very well and are a welcome addition:

Group Based Role Assignments Known Issues

  • The Enable staged rollout for managed user sign-in feature doesn’t support assignment via group.
  • Azure AD P2 licensed customers only: Don’t assign a group as Active to a role through both Azure AD and Privileged Identity Management (PIM). Specifically, don’t assign a role to a role-assignable group when it’s being created and assign a role to the group using PIM later. This will lead to issues where users can’t see their active role assignments in the PIM as well as the inability to remove that PIM assignment. Eligible assignments are not affected in this scenario. If you do attempt to make this assignment, you might see unexpected behavior such as:
    • End time for the role assignment might display incorrectly.
    • In the PIM portal, My Roles can show only one role assignment regardless of how many methods by which the assignment is granted (through one or more groups and directly).
  • Azure AD P2 licensed customers only Even after deleting the group, it is still shown an eligible member of the role in PIM UI. Functionally there’s no problem; it’s just a cache issue in the Azure portal.
  • Use the new Exchange Admin Center for role assignments via group membership. The old Exchange Admin Center doesn’t support this feature yet. Exchange PowerShell cmdlets will work as expected.
  • Azure Information Protection Portal (the classic portal) doesn’t recognize role membership via group yet. You can migrate to the unified sensitivity labeling platform and then use the Office 365 Security & Compliance center to use group assignments to manage roles.

Protecting Exchange Online Mail With DKIM

DomainKeys Identified Mail is a security standard for email which leverages public and private certificates to secure the transit of mails by signing them as they leave the source environment. The recipients can then verify the sender by looking up the public key via DNS lookup. Having DKIM set up for your mail domains goes a long way towards protecting your domain from being used in Phishing/Spoofing attacks.

To set up DKIM on any mail system requires a good deal of setup including key hosting, IIS configuration, firewall rules and DKIM addons or plugins for different mail systems. In Exchange Online, a lot of the heavy lifting around DKIM has been done for us by Microsoft. We leverage our tenant name (“Onmicrosoft” Domain) as the default signing domain and redirect our custom domains back to that.

Setting Up DKIM in EOL

Setting up DKIM for your custom domains in Exchange Online is very straightforward. To enable DKIM functionality for a domain, first run the below cmdlet in the Exchange Online Management Shell to add the functionality.

New-DkimSigningConfig -DomainName <> -KeySize 2048 -Enabled $True

This will give you an output of two CNAME records to configure. A DKIM record for Exchange Online will look like the below in the public DNS of your custom domain:

Record TypeHost NameValueTTL

Once the records are in place, the DKIM configuration can be found in the ATP Policy section of the Security & Compliance Center, under ‘Additional Policies’ – ‘DKIM’.

Here we can select our domain and select ‘Enable’ to turn on DKIM signing for the domain, easy! Note that DNS may take a while to replicate so we may need to wait a while for this to be detected and enable successfully.

We can also manually rotate the signing keys at intervals from this page.

DKIM is a great security measure to protect your email domains from being spoofed. Along with DKIM, make sure your SPF and DMARC records are up to date to provide your recipients with the best possible information about your source environment. If you have alternate mail sources, such as independent relays, make sure to factor them into your DKIM configuration also.

Finally, ensure that your mail system, whatever it may be is inspecting the SPF, DKIM and DMARC of inbound mails and taking appropriate actions when these policies arent met!