Introduction
Why was this created?
As more and more organizations adopt Intune to manage PCs, this was an inevitable scenario. Companies can split into several companies, business acquire new businesses, organizations divest; all reasons you may need to move a PC to a different tenant. This isn’t new, as Active Directory domain migrations are a prevalent process.
But when your PC is Entra ID joined, Autopilot registered, and Intune managed, the only way to move it is to wipe or reimage the device, de-register it from Autopilot, and start all over again in the new tenant. Well, the only “official” way as supported by Microsoft.
Wiping a PC, re-registering it, and waiting for it to go through the Autopilot provisioning process again probably takes a minimum of 2 hours, at best. At worst, you could have users going a whole day or more without a working machine. That’s not good. At least that’s what a large customer of mine thought about 3 years ago when they were facing a divestiture.
This customer had roughly 15,000 Windows machines deployed via Autopilot and Intune. Due to the divestiture, about half of those users would now belong to a new Azure AD tenant, and their PC would need to move to a new Intune environment as well. While evaluating how to move PCs, they were very clear that any extended downtime was unacceptable, despite Microsoft stating this is “just how the process works”.
The customer asked me if there was anyway to automate this process to streamline it and make the end user experience as quick and painless as possible. After some tinkering, Jesse (my lead solutions architect) and I came up with a workable solution. It wasn’t perfect, but it worked, requiring nothing more than one reboot, which satisfied our customer’s ask.
Since that time, we have been gradually refining the process, adding more capabilities and automating more pieces. Finally, I believe it is at a point where it can be shared and hopefully help those who are in a similar situation.
How does it work?
Solution workflow
sequenceDiagram
autonumber
Source->>PC: Deploy package
activate PC
deactivate PC
loop Copy files
PC->>PC: From package to local path
end
activate PC
deactivate PC
PC-->>Source: Request to authenticate
Source-xPC: Return access token headers
Note over PC,Destination: If $targetTenant...
PC-->>Destination: Request to authenticate
Destination-xPC: Return access token headers
activate PC
deactivate PC
loop Get attributes
PC->>PC: deviceObject, userObject
end
activate PC
Note over PC: Write attributes to registry
Note over PC,Destination: If migration:
PC--xDestination: Get new user attributes
Destination->>PC: Write new user attributes to registry
deactivate PC
Note over Source,PC: If Intune/Entra joined...
PC->>Source: Remove Intune MDM certificate
PC->>Source: dsregcmd /leave
Note right of PC: Leave Entra
Note over Source,PC: If domain joined...
loop Check domain line of sight
PC-->>Source: If line of sight, change DNS to break
end
PC->>Source: Unjoin domain with local admin
Note right of PC: Leave Domain
Note over Source,PC: If SCCM managed...
PC->>Source: Uninstall SCCM client
activate PC
Note over PC: install provisioning package
deactivate PC
PC->>Destination: Enroll to destination environment
Note over Source,Destination: Reboot
PC-xDestination: User logs into destination
loop disable tasks
PC->>PC: reboot.xml, postMigrate.xml
end
PC-->>Destination: Request to authenticate
Destination-xPC: Return access token headers
Note over PC,Source: If no destination
PC-->>Source: Auth to Source if !($targetTenant)
PC->>Destination: Update primaryUser in Intune
PC->>Destination: Update 'groupTag' in Entra
Note over PC: If $bitLocker: 'decrypt'
loop BitLocker
PC->>PC: Decrypt BitLocker key
end
Note over PC,Destination: If $bitlocker: 'migrate'
PC--xDestination: Escrow BitLocker key
PC->>Destination: Register to Autopilot
Watch the demo
Remember, you can watch the entire migration process in action on the YouTube site
The migration solution comprises several scripts and files that are compiled into an .intunewin file using the Microsoft Win32 Content Prep Tool. When the application is installed, the startMigrate.ps1 script is launched and begins to orchestrate the migration. A provisioning package must be created using the Windows Configuration Designer.
Once the migration starts, the solution goes through 5 phases:
Phase 1 | Gather
graph TB
A[Migration package is deployed] --- |Files copied to 'C:\ProgramData\IntuneMigration' | B[Parse $config from config.json] ---|Using Graph API| C(Authenticate to source);
C --> D{$targetTenant?};
D --->|If destination in JSON| E(Authenticate to destination);
D --->|If not| F[Get device and user attributes];
E --- F
F --> G[Authenticate to Graph API];
G ---|"(migration only)"| H[Get newUser object];
H --> I[Write attributes to registry]
Phase 2 | Prepare
graph TB
A1[Set local policies to allow for migration];
A1 --->|via registry| A2([AllowMicrosoftAccountConnection=1]);
A2 --- A3([AutoAdminLogon=1]);
A3 --- A4([DontDisplayLastUserName=1]);
B>Create user] ---|'MigrationInProgress'| A3;
A4 --> A5[Set migration tasks];
A5 --- C[[reboot.xml]];
A5 --- D[[postMigrate.xml]];
Phase 3 | Remove
graph TD
A{Intune?} ---> |Yes| A1([Remove certificate]);
A1 --- A2([Remove reg keys]);
A --> |No| A3{SCCM?};
A2 --- A3;
A3 --> |Yes| A4[Uninstall SCCM];
A3 --> |No| A5{Entra ID joined?};
A4 --- A5;
A5 --> |Yes| A6[unjoin -dsregcmd /leave];
A5 --> |No| A7{Domain joined?};
A7 --> |Yes| A8{line-of-sight?};
A8 --> |Yes| A9([Change DNS]);
A8 --> |No| A10[unjoin];
A9 --- A10;
A6 --- A7;
A7 --> |No| A11[install ppkg];
A10 --> A11;
B[/join target\] --- A11;
A11 --- A12((Reboot));
C>break line-of-sight] --- A9;
Info
Device will reboot here
Phase 4 | Change owner
graph TD
A[Retrieve attributes from registry];
A --- B([device object]);
B --- C([user object]);
C --> D[Create new user profile];
E((new SID)) --- |new user|C;
D --> |delete| F((new profile));
H([replace SID]) --> |keep user data| G;
F --> |change owner| G((old profile));
E --- H;
G --> I[[registry cleanup]];
Phase 5 | Post migrate
graph TD
A[User logs in] --> B([Disable migration tasks]);
B --- C{Target tenant?};
C --> |Yes| C1[Authenticate to destination];
C --> |No| C2[Authenticate to source];
C1 --- D([Update 'primaryUser' - Intune]);
C2 --- D;
D --- E([Update 'groupTag' - Entra]);
E --- F{Bitlocker?};
F --> |'migrate'| F1[migrate key];
F --> |'decrypt'| F2[decrypt key];
Y>From config JSON] --- |get|F;
F1 --- G[Autopilot register];
F2 --- G;
G --> H[Cleanup local files];
Assumptions
Source tenant
- Users have requried Microsoft licensing assigned to enable Intune and Entra ID (P1 or P2)
- Devices are in one of the following states:
- Entra ID joined
- Active Directory Domain joined
- Entra hybrid joined
- Devices are enrolled and managed by Intune
- Devices are registered in Autopilot (not required)
Warning
Prior to device migratioin, the following tenant migration activities MUST occur:
- User identities from source tenant have been migrated to destination
- User data has been migrated from source to destination tenant including SharePoint, OneDrive, Exchange Online, and Teams.
Destination tenant
Once complete, we will assume the following about the destination tenant:
- User identities are assigned the required Microsoft licensing to enable Intune and Entra ID (P1 or P2)
- Intune is configured to support the required management of Windows devices including but not limited to
- Policy configurations
- Application packages
- Windows updates
- Device settings
- Intune configuration has been validated with device enrollment