It isn’t a frequent task but moving a subscription from one Azure AD tenant to another can be a real headache since, although resources aren’t actually moved, there are plenny of manual work to be done. On top of this, the experience doesn’t always work as it should.

Let’s set the stage

Let’s say for a minute that you have two tenants in your organization (for whatever reason that is), you have 2 Azure AD tenants: “Tenant A” and “Tenant B”. Users exist on “Tenant A” and they are “invited” (through B2B) into “Tenant B”. Also, your subscriptions are linked to “Tenant B”, the scenario would look like something like this:

Stage

Now you decide or found a reason to move all or some of the subscriptions to the source tenant (Tenant A).

What’s the process?

In order to move subscriptions, the process seems pretty simple however there are a couple of things to keep in mind before starting:

  • The account executing the process must be “Global Admin” in both tenants
  • The process is done manually and per-subscription; this mean you must go and manually move one subscription at a time.

What do you loss?

Well, as part of the migration, anything tenant dependant will be lost, this is:

  • RBAC in the subscription will be lost and the only one left with “Owner” rights will be the account doing the switch
  • Certain Azure resources will be unavailable given their tenant dependency. For example, Azure KeyVault will be there but linked to the old tenant (for which they will be unusable), Azure DataBricks too.

How does the manual process looks like?

To do this manually, you should follow these steps:

  1. Make sure you are “Global Admin” in both tenants
  2. On “Tenant B”, in Azure Portal, go to subscriptions, click on one subscription
  3. Click button “-> Change Directory”
  4. Select destination tenant and click “Change”
    Screenshot - 28_09_2018 , 12_32_00
  5. Repeat steps 2 to 4 until all your subscriptions are “in progress” state.
  6. Believe and pray
  7. Fix subscription RBAC
  8. Fix Azure KeyVault Access Policies

Why “Believe and pray”? well, weird things are going to start happening. According to Microsoft documentation, the process can take up to 10 minutes. During these endless 10 minutes, and if everything goes fine, you will start seeing subscription to have state “Unknown” in the previous tenant OR just desappear for both tenantns OR start showing up in the new tenant. Don’t panic, just be patiente.

Why if everything goes fine?

Well, experience has tought me otherwise and this process not always works as expected.  In my experience we did this migration three times, for a POC we ran with 3 subscriptions, for Development (15 subscriptions) and for Production (43 subscriptions). In all of these cases, at least half of the subscriptions didn’t switch tenant and we had to open a case with Microsoft for them to do a “manual sync”. When subscriptions don’t move, it’s generally because of a synchronization issue which Microsoft checks the backend and the subscription are already in the destination tenant but in the frontend, you see them still in the old tenant. Just to share some numbers:

Environment Total Subscriptions Successfully Moved Microsoft Intervention Required
POC 3 1 2
Development 15 10 5
Production 43 20 23

Botton line: If you are going to do this and you have Premier Support, submit a pro-active case to have a Subscription specialist assigned to you on the time frame you will be doing the click. They cannot do it on your behalf.

Isn’t a better way to do this?

Well, as you saw, most of the steps are manual and there’s no API to do that. But, but….. you could script re-applying RBAC in the subscriptions and Azure KeyVault which also involved re-creating Azure AD Groups and Service Principal Names. Doing this manually is a lot of work with real chances to mess it up. That’s why, I put together a couple of script to help and ease this process, they can be found at GitHub.

A better approach

So, what’s the recommended approach to do this with lossing all your hair in the middle and keep some sanity. Well, this approach is what we implemented to migrate our Production environment based on the previous experience and helped us to do that in only 4 hours during working hours. That’s it:

  • Moving 43 subscriptions
  • Re-creating Azure AD Groups and SPNs
  • Fixing all Azure KeyVaults with the same access policies they used to have
  • Re-applying RBAC to all of the subscriptions

Pre-Requirements

  • Get a copy of the script in my GitHub repository. Each script has an MD file explaining what it does and what parameters are available.
  • If you have “Premier Support”, open a pro-active case to have an Azure Subscription Specialist assigned and in-stand-by for the time you are planning to do the switch.

The Steps

Before the Subscription Specialist is online

  1. Open a Powershell console
  2. Make sure you have the latest version of AzureRM and AzureAD modules
  3. Login to Azure AD (Connect-AzureAD -TenantId Tenant_B_Id) and Azure RM (Login-AzureRmAccount)
  4. Execute “Backup-AzureApplication.ps1”
  5. Execute “Backup-AzureGroups.ps1”
  6. Execute “Backup-AzureServicePrincipal.ps1”
  7. Execute “Backup-AzureSubscriptions.ps1”
  8. Execute “Backup-AzureUser.ps1”
  9. Execute “Restore-AzureRBAC.ps1” with switch “-Verify”

PS C:\Temp\azure-tenant-migration> Install-Module -Name AzureRM

PS C:\Temp\azure-tenant-migration> Install-Module -Name AzureAD

PS C:\Temp\azure-tenant-migration> Connect-AzureAD -TenantId "Tenant_B_Id"

PS C:\Temp\azure-tenant-migration> Login-AzureRmAccount

PS C:\Temp\azure-tenant-migration> .\Backup-AzureApplication.ps1

PS C:\Temp\azure-tenant-migration> .\Backup-AzureGroups.ps1

PS C:\Temp\azure-tenant-migration> .\Backup-AzureServicePrincipal.ps1

PS C:\Temp\azure-tenant-migration> .\Backup-AzureSubscriptions.ps1

PS C:\Temp\azure-tenant-migration> .\Backup-AzureUser.ps1

PS C:\Temp\azure-tenant-migration> .\Restore-AzureRBAC.ps1 -GroupExport ".\AAD_Groups.xml" -UserExport ".\AAD_Users.xml" -ServicePrincipalExport ".\AAD_ServicePrincipal.xml" -SubscriptionExport ".\Subscriptions.xml" -Verify

Subscription Specialist is ready

  1. Login to Azure Portal in the old tenant
  2. On “Tenant B”, in Azure Portal, go to subscriptions, click on one subscription
  3. Click button “-> Change Directory”
  4. Select destination tenant (“Tenant A”) and click “Change”
  5. Repeat steps 2 to 4 for all subscriptions
    Screenshot - 28_09_2018 , 12_32_00
  6. If after 10 minutes, the subscription is still visible in “Tenant B” and you cannot see it in “Tenant A”, then ask Subscription Specialist to do a sync in the backend. (they generally disappear immediatly)

After subscriptions have been moved

WARNING: If Azure AD Groups or SPNs don’t exists, this process will automatically create them, fill the membership (for Groups) and configure Reply URLs, etc (for SPN). If you pre-create them manually, the process will find them and re-use them (if the names match)

  1. In the same or a new Powershell console
  2. Clean up Azure RM Context by running “Clear-AzureRmContext -Scope CurrentUser -Force”
  3. Clear your Azure RM account by running “Remove-AzureRmAccount -Username “your_user_name” -Scope CurrentUser”
  4. Login to Azure AD (Connect-AzureAD -TenantId Tenant_A_Id) and Azure RM (Login-AzureRmAccount)
  5. Execute “Restore-AzureRBAC.ps1”. You can use “-Prefix” switch in case you want to prefix all Azure AD Group or SPN created during the process.

PS C:\Temp\azure-tenant-migration> Clear-AzureRmContext -Scope CurrentUser -Force

PS C:\Temp\azure-tenant-migration> Remove-AzureRmAccount -Username "your_user_name" -Scope CurrentUser

PS C:\Temp\azure-tenant-migration> Connect-AzureAD -TenantId "Tenant_A_Id"

PS C:\Temp\azure-tenant-migration> Login-AzureRmAccount

PS C:\Temp\azure-tenant-migration> .\Restore-AzureRBAC.ps1 -GroupExport ".\AAD_Groups.xml" -UserExport ".\AAD_Users.xml" -ServicePrincipalExport ".\AAD_ServicePrincipal.xml" -SubscriptionExport ".\Subscriptions.xml"

And that’s it. You might need to re-run step 5 a couple of times given Azure Powershell isn’t that reliable sometimes and you get token access errors. Re-running over and over won’t break anything since it just adds permission, it doesn’t remove.

Again, this is the process we followed and we were successful with it. These scripts probably have space to improve for which Pull Requests are welcome. Hopefully, this saves some time for you too.