I had issues with the Directory Migration script where usernames were not lining up correctly.
- Ensure new tenant and Azure is syncing (recommend custom app permissions)
- Move computer to new tenant
- Set Primary User in Immy
- Deploy , and set the Path to the Profile you want to migrate
I tend to deploy as Ad-Hoc, schedule with the end user, backup bookmarks and browser passwords, and then run.
Ocassoinally I have issues with inTune registration, I use this site to fix the issues : Intune Device Enrollment errors | MDM enrollment issues
Or, will use the PS module InTuneSyncDebugtool and the command Test-intunesyncerrors
## Thanks to DarrenDK for the original Directory Migration scripts.
## Big thanks to the entire ImmyBot team
## Extra big thanks to all of those active in the ImmyBot Community.
##
## I re-worked Darren's script for specific use case scenario to migrating M365 to M365 tenant where user alias is changing (Ie [email protected] to [email protected])
## Immy's current Directory Profile Migration really struggles matchign the correct user here.
## I have simplified the migration choices here.
## We are manually specifiying the directory path ie C:\Users\ProfilePath
## Do not put a trailing \ at the end of the profile path.
##
## You need to have the new Immy Tenant setup, and Azure sync.
## I recommend that use use custom permissions vs default Immy app permissions.
##
## Transfer the computer to the new Immy Tenant
## Set the Primary Person on the computer, this is a hard requirement.
##
## Set up your deployment. I recommend using an Ad-Hoc deployment, and scheduling your profile migration with your user.
## We also recommend that you back up the user's Browser Bookmarks and Passwords in case something bad happens.
## When I schedule with end users, I usually book a 2 hour session. I let them know they will NOT be able to use their computer during migration
## After Immy is finished, Verify you see the device in Entra Devices. Make sure the MDM is showing inTune if you are using inTune.
## I have seen several times, that Automatic inTune fails to join.
## I usually use the Powershell module IntuneSyncDebugTool
## The command is "test-intunesyncerrors"
## If you have further issues, I recommend reviewing this guy's blog, particularry this page: https://call4cloud.nl/intune-device-enrollment-errors-mdm-enrollment/#7_The_0x80192ee2_0x82aa0008_Errors
## Depending on your policy settings, you may also need to use User enrollment.
## Use the same acocunt as your Oauth/DEM user to finalize enrollment.
##
## This is not tested to do migrations to AD, Migrations to Local, please use the original Directory Migration task to process those migrations.
param(
[Parameter(Position=0,Mandatory=$False,HelpMessage=@'
C:\Users\UserProfilePath (do not include a trailing \)
'@)]
[String]$ProfileToMigrate='ProfileToMigrate'
)
dynamicparam {
New-ParameterCollection @(
Get-DirectoryTypeParameters -DirectoryTypeVariableName 'DestinationDirectoryType'
$DirectoryType = $DestinationDirectoryType
switch ($DirectoryType) {
'AzureAD' {
Get-JoinAzureADParameters
}
'ActiveDirectory' {
New-JoinableDomainsDropDown
New-Parameter -Name StaticallyAssignDomainControllerAsDNSServer -Position 6 -Type 'Boolean' -DefaultValue $false -HelpMessage 'Useful for ensuring the machines can hit the new DC'
}
}
)
}
begin {
$VerbosePreference = 'continue'
Invoke-ImmyCommand {
Get-WmiObject Win32_OperatingSystem -Property Caption | ForEach-Object {
if ($_.Caption -like "*home*") {
throw "$($_.Caption) is not supported"
}
}
}
#region Functions
$TestResults = @{}
$TestResults.AllProfilesHaveDestinationUsers = $true
[bool]$OnPremisesSyncEnabled = $false
if ($DirectoryType -eq 'AzureAD' -and $ProfileTypesToMigrate -match 'AzureAD|All|WorkplaceJoined') {
try {
$onPremisesSyncEnabledResult = Get-MSGraphApiResults -ErrorAction Stop -Endpoint organization -Select onPremisesSyncEnabled | Select-Object -Expand onPremisesSyncEnabled
} catch {
$_.Exception | Write-Variable
throw
}
try {
$OnPremisesSyncEnabled = !!$onPremisesSyncEnabledResult
} catch {
Write-Warning ($_ | Out-String)
$onPremisesSyncEnabledResult | Format-List * | Out-String | Write-Verbose
}
}
if ($method -eq 'set') {
if ($RebootPreference -like 'suppress') {
$RebootPreference = 'IfNecessary'
throw "Reboots need to be allowed for Azure AD Migration. Please re-run session with reboots allowed."
}
}
$PSDefaultParameterValues."Invoke-RestMethod:ProgressAction" = 'SilentlyContinue'
$PSDefaultParameterValues."Invoke-WebRequest:ProgressAction" = 'SilentlyContinue'
#endregion
#region Check Prerequisites
Write-Progress "Destination DirectoryType: $DirectoryType"
switch ($DirectoryType) {
"AzureAD" {
try {
$null = Connect-ImmyAzureAD -ErrorAction Stop
} catch {
throw "Unable to connect to Azure AD, ensure Secret is not expired under Settings->Azure`r`n$($_.Exception.Message)"
}
# Get-AzureADVerifiedDomains
if (($OAuthInfo)?.accessToken) {
Write-Progress "Retrieving destination TenantId from OAuthInfo"
$ParsedJwt = Parse-JWT $OAuthInfo.accessToken
$DestinationTenantID = $ParsedJwt | ForEach-Object { $_.tid }
$DEMUsername = $ParsedJwt | ForEach-Object { $_.upn }
}
if ($DEMUsername) {
$DestinationTenantDomain = $DEMUsername -Split '@' | Select-Object -Last 1 | ForEach-Object {$_.Trim()}
}
if (!$DestinationTenantID) {
if (!$DEMUsername) {
throw "Unable to determine destination tenantId as DEMUsername is null"
}
Write-Progress "Looking up Destination AzureTenantId for $DestinationTenantDomain"
if (!$DestinationTenantDomain) {
throw "Aborting: Invalid DeviceEnrollmentManagerUsername: $DEMUsername"
}
Write-Progress "Verifying Tenant exists for $DestinationTenantDomain" -PercentComplete 5
$DestinationTenantID = Get-AzureADTenantID -DomainName $DestinationTenantDomain
if (!$DestinationTenantID) {
throw "$DestinationTenantDomain is not a valid Azure AD Tenant Domain."
}
}
$Computer = Get-ImmyComputer
if ($null -eq $Computer.TenantPrincipalId -or $Computer.TenantPrincipalId -ne $DestinationTenantID) {
throw "Aborting: Computer not associated with the same tenant as the DEM user`r`nOpen the computer in Immy, go to the Onboarding tab, select the appropriate tenant, click Save and then Skip Onboarding"
}
Write-Progress "Getting AzureAD Join Status..."
$AzureADStatus = Get-AzureADJoinStatus
Write-Progress "CurrentTenantID: $($AzureADStatus.TenantDetails.TenantId)"
Write-Progress "DestinationTenantID: $DestinationTenantID"
Write-Progress "DomainJoined: $($AzureADStatus.DeviceState.DomainJoined)"
$HybridJoined = $AzureADStatus.DeviceState.DomainJoined -and $AzureADStatus.DeviceState.AzureAdJoined
Write-Progress "HybridJoined: $HybridJoined"
if ($null -eq (($AzureADStatus)?.TenantDetails)?.TenantId) {
Write-Warning "Machine is not joined to AzureAD. Should be joined to tenant $DestinationTenantID"
$TestResults.AzureADJoined = $false
} elseif ($AzureADStatus.TenantDetails.TenantId -ne $DestinationTenantID) {
Write-Warning "Machine is joined to the incorrect AzureAD"
$TestResults.CorrectAzureADTenant = $false
}
Write-Progress "Destination $DestinationTenantDomain ($DestinationTenantID) OnPremisesSyncEnabled: $onPremisesSyncEnabled"
$UserJoinInfo = Get-AzureADUserJoinInfo
if ($UserJoinInfo) {
Write-Verbose "AzureADUserJoinInfo:`r`n$($UserJoinInfo | Format-List * | Out-String)" -Verbose
} else {
Write-Verbose "Not User Joined"
}
# After deleting the local users that previously owned the profile, the SID will remain but the Owner (NTAccount formatted) will be gone.
#14393
$WindowsVersion = Invoke-ImmyCommand {
[System.Environment]::OSVersion.Version
}
}
"ActiveDirectory" {
# TODO: Verify connectivity to domain controller?
}
}
#endregion
}
process {
$PPE=(Get-ImmyComputer).PrimaryPersonEmail
$PPEntraSID=(Get-ImmyAzureADUser -Email $PrimaryPersonEmail).SID
$DestinationUserSID=$PPEntraSID
$PPDisplayName=(Get-ImmyAzureADUser -Email $PrimaryPersonEmail).displayName
switch($method)
{
"test" {
Write-Host "Primary Person is $($PPE)"
Write-Host "The Entra User object SID is: $($PPEntraSID)"
## FIX this, this is not right.
if($PPE -ne $null -and $PPEntraSID -ne $Null){ return $false} else { return $true}
}
"get" {
$Stringreturn= "User SID: $PPEntraSID; is Domain Joined? $AzureADStatus"
return $Stringreturn
}
"set"{
switch ($DirectoryType) {
"AzureAD" {
if ($AzureADStatus.TenantDetails.TenantId) {
if ($AzureADStatus.TenantDetails.TenantId -ne $DestinationTenantID) {
Write-Progress "Machine is not in desired tenant."
Write-Progress "Leaving AzureAD..." -PercentComplete 50
Get-ImmyComputer | Invoke-ImmyCommand {
dsregcmd /leave
}
Restart-ComputerAndWait
Write-Progress "Updating AzureAD Join Status..."
$AzureADStatus = Get-AzureADJoinStatus
} else {
if ($false -eq $TestResults.NotHybridJoined) {
Write-Progress "Machine is Hybrid Joined to AzureAD, do something fancy to fix it"
} else {
Write-Progress "Machine already in desired tenant"
}
}
} else {
Write-Progress "Machine not joined to AzureAD"
}
}
"ActiveDirectory" {
# No need to unjoin domain before migration to ActiveDirectory
}
}
Write-Progress "Migrating Profiles..." -PercentComplete 50
$UserIdentifier = $PPE
#Line 982 from Immy's Profile Migartion This is where we need to make major changes.
Write-Progress "Invoking ImmyWiz to map $($ProfileToMigrate) to $DirectoryType SID $($DestinationUserSID) ($($PPDisplayName) $($UserIdentifier))"
try {
$Result = Set-UserProfileOwner -ProfilePath $ProfileToMigrate -SID $DestinationUserSID -ErrorAction Stop
if ($Result -ne 0) {
throw "$($ProfileToMigrate) ChangeOwner() returned $Result"
}
} catch {
Write-Error "Aborting migration. There was an error migrating $($ProfileToMigrate)`r`n$($_ | Out-String)" -ErrorAction Stop
}
Write-Progress "Setting $UserIdentifier to be the selected user for next logon"
$LogonUIPath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Authentication\LogonUI'
$DisplayName = $PPDisplayName
Get-WindowsRegistryValue -Path $LogonUIPath -Name LastLoggedOnUserSID | RegistryShould-Be -Value $DestinationUserSID
Get-WindowsRegistryValue -Path $LogonUIPath -Name SelectedUserSID | RegistryShould-Be -Value $DestinationUserSID
Get-WindowsRegistryValue -Path $LogonUIPath -Name LastLoggedOnDisplayName | RegistryShould-Be -Value $DisplayName
Write-Progress "Restarting LogonUI to force update"
Invoke-ImmyCommand {
taskkill /IM logonui.exe /f 2>&1 | Out-Null
}
if ((Test-PartOfDomain)) {
# throw "Aborting: Machine is still domain joined (Profwiz likely failed)"
Write-Progress "Machine is Domain Joined, Unjoining" -PercentComplete 95
$UnjoinResult = Unjoin-Domain
if (!$UnjoinResult) {
throw "Unjoin attempt returned error $($UnjoinResult.ReturnValue) (0x$($UnjoinResult.ReturnValue.ToString('X8'))"
}
Restart-ComputerAndWait -IgnoreRebootPreference
if ((Test-PartOfDomain)) {
throw "Aborting: Machine is still domain joined after Unjoin attempt"
}
}
Write-Progress "Machine is not domain joined, joining AzureAD: $($DestinationTenantDomain)" -PercentComplete 97
$JoinAzureADParams = @{}
if (($OAuthInfo).AccessToken) {
$JoinAzureADParams.OAuthInfo = $OAuthInfo
} else {
$JoinAzureADParams.DEMUsername = $DEMUsername
$JoinAzureADParams.DEMPassword = $DEMPassword
}
# $JoinResult = Join-AzureAD @JoinAzureADParams -PreferCachedBPRT:$false -SkipRegistryTest -ClearExistingEnrollments
# Chaned above line to remove PreferCachedBPRT per CB - DH #202407165
$JoinResult = Join-AzureAD @JoinAzureADParams -SkipRegistryTest -ClearExistingEnrollments -RequireIntuneEnrollment:$RequireIntuneEnrollment
Write-Progress "AzureADJoinResult: $($JoinResult | Format-List * | Out-String)"
Write-Progress "Complete" -PercentComplete 100
}
}
}