Chat now with support
Chat mit Support

On Demand Migration Current - Active Directory Microsoft Entra ID Intune Device Migration Quick Start Guide

High level Custom Task Explanation

Autopilot Cleanup

This script runs automatically when the ODMAD task runs.

This script searches the HKLM\SOFTWARE\Microsoft\Provisioning and the HKLM\SOFTWARE\Microsoft\Provisioning\Diagnostics for child keys that have Autopilot in their names. It will then delete these values and keys from the workstation.

Autopilot Cleanup.txt

Param (
)
$output = New-Object BinaryTree.ADM.Agent.PSHelpers.PSOutput
 
### Script Configurable Parameters ###
 
# Parent Regisry Keys to search #
$RegistryKeys = "HKLM:\SOFTWARE\Microsoft\Provisioning" , "HKLM:\SOFTWARE\Microsoft\Provisioning\Diagnostics"
 
######################################
 
Write-Output "Evaluating $($RegistryKeys.Count) Registry Hive(s)"
ForEach ($Key in $RegistryKeys) {
                Write-Output " Processing: $($Key)"
                If (Test-Path -Path $Key) {
                   $StoreKey = Get-ChildItem -Path $Key | Where-Object {$_.Name -like '*Autopilot*'}
                   Write-Output "  Processing $($Storekey.Name.Count) Registry Entries"
                   ForEach($S in $StoreKey){
                     Write-Output "    $($S)"
                   }
                   Write-Output "  Removing Registry Keys"
                   ForEach($S in $Storekey){
                      Write-Output "    Removing: $($S)"
                      $S | Remove-Item -Recurse -Force -Confirm:$false -ErrorAction SilentlyContinue
                      $KeyTest = Get-Item -Path Registry::$S -ErrorAction SilentlyContinue
                      If([string]::IsNullOrWhitespace($KeyTest)){
                         Write-Output "      Delete Suceeded"
                      }
                      Else{
                         Write-Output "      Delete Failed"
                         $KeyTest = $Null
                   `  }
                   }
    }
}
 
return ($output)

Intune Cleanup

To allow enrolling the workstation into the target Intune, it is important to remove the source Intune Enrollment information. Otherwise, the workstation thinks that it is already part of an Intune Enrollment and will not try to enroll in the target.

This script will find the Intune Enrollment ID from the Scheduled Task that Intune uses. The script then searches the following parent registry keys for the EnrollmentID and removes the registry values and Keys:

  • HKLM:\SOFTWARE\Microsoft\Enrollments

  • HKLM:\SOFTWARE\Microsoft\Enrollments\Status

  • HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked

  • HKLM:\SOFTWARE\Microsoft\PolicyManager\AdmxInstalled

  • HKLM:\SOFTWARE\Microsoft\PolicyManager\Providers

  • HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts

  • HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Logger

  • HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Sessions

    The script will also remove the Intune Enrollment Scheduled Task (this task will automatically get recreated when the machine joins the target tenant) and will remove the existing Intune Certificate from the Computer Certificate store.

Intune Cleanup.txt

Param (
)
$output = New-Object BinaryTree.ADM.Agent.PSHelpers.PSOutput
 
### Script Configurable Parameters ###
 
# Declare Parent Registry Keys  to search for EnrollmentID #
$RegistryKeys = "HKLM:\SOFTWARE\Microsoft\Enrollments", "HKLM:\SOFTWARE\Microsoft\Enrollments\Status","HKLM:\SOFTWARE\Microsoft\EnterpriseResourceManager\Tracked", "HKLM:\SOFTWARE\Microsoft\PolicyManager\AdmxInstalled", "HKLM:\SOFTWARE\Microsoft\PolicyManager\Providers","HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Accounts", "HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Logger", "HKLM:\SOFTWARE\Microsoft\Provisioning\OMADM\Sessions"
 
 
######################################
 
Write-Output "Getting Intune Enrollment ID:"
### Find the Intune EnrollmentID from Intune Enrollment Scheduled Task ###
$EnrollmentID = Get-ScheduledTask | Where-Object {$_.TaskPath -like "*Microsoft*Windows*EnterpriseMgmt*"} | Select-Object -ExpandProperty TaskPath -Unique | Where-Object {$_ -like "*-*-*"} | Split-Path -Leaf
Write-Output "  Intune Enrollment ID: $($EnrollmentID)"
If([string]::IsNullOrWhitespace($EnrollmentID)){
    Write-Output "  No Intune Enrollment ID Found..Terminating"
    Exit 0
}
 
### Remove Intune Certificate from Certificate Store ###
Write-Output "Removing Intune MDM Certificate"
 
If((Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Issuer -match "Intune MDM"})){
    Write-Output "  Intune MDM Certificate Found..Collecting Certificate Information"
    $IntuneCert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Issuer -match "Intune MDM"}
    ForEach($Cert in $IntuneCert){
        Write-Output "  Found $($Cert.Subject)..Certificate will be removed"
        $Cert | Remove-Item
        $IntuneCertTest = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object {$_.Subject -match $Cert.Subject}
        If([string]::IsNullOrWhitespace($IntuneCertTest)){
        Write-Output "    Delete Succeeded"
        }
        Else{Write-Output "    Delete Failed"}
        $IntuneCertTest = $Null
         
    }
Else {Write-Output "Intune MDM Certificate Not Found"}
 
 
### Delete Scheduled Tasks ###    
Write-Output "Finding Enrollment Scheduled Tasks"
$ScheduledTasks = Get-ScheduledTask | Where-Object {$_.Taskpath -match $EnrollmentID}
Write-Output "  Evaluating $($ScheduledTasks.count) Scheduled Tasks:"
ForEach($Task in $ScheduledTasks){
    Write-Output "    Found Task: $($Task.Taskname) with path: $($Task.TaskPath)"
}
 
Write-Output "Removing Intune Enrollment Scheduled Tasks"
ForEach($T in $ScheduledTasks){
    Write-Output " Removing $($T.Taskname)"
    #Get-ScheduledTask | Where-Object {$_.Taskname -match $T.TaskName}
    Get-ScheduledTask | Where-Object {$_.TaskName -match $T.TaskName} | Unregister-ScheduledTask -Confirm:$false
    $TestScheduledTask = Get-ScheduledTask | Where-Object {$_.Taskname -match $T.TaskName}
    If([string]::IsNullOrWhitespace($TestScheduledTask)){
        Write-Output "    Delete Succeeded"
    }
    Else{Write-Output "    Delete Failed"}
    $TestScheduledTask = $Null
}    
 
 
### Search Registry keys for EnrollmentID and Remove Registry Keys            
Write-Output "Removing Enrollment Registry Keys"
Write-Output "  Evaluating $($RegistryKeys.Count) Registry Hive(s)"
Foreach ($K in $RegistryKeys) {
    Write-Output "    $($K)"
}
Foreach ($Key in $RegistryKeys) {
    If (Test-Path -Path $Key) {
       Write-Output "  Found: $($Key)"
       Get-ChildItem -Path $Key | Where-Object {$_.Name -match $EnrollmentID} | Remove-Item -Recurse -Force -Confirm:$false -ErrorAction SilentlyContinue
    }
    If (Test-Path -Path $Key){
       Write-Output "    Deleted Failed"
    }
    Else{Write-Output "    Deleted Succeeded"} 
}
 
return ($output)

SetUserEmailValues

SetUserEmailValues

When the machine enrolls in the target Intune, it will look for an Intune Licensed user in M365 using the UserEmail value found in the workstation registry. By default, this value is set to the Bulk Enrollment user, which does not have the relevant license, and prevents the Intune service from running correctly.

This script creates a separate PowerShell script on the workstation called UpdateCloudJoinInfo.ps1 in the ODMAD agent folder and creates a Scheduled Task to execute UpdateCloudJoinInfo.ps1 when the first target user logs on.

When the UpdateCloudJoinInfo script runs during the first login post-migration, it will update the UserEmail value in the following registry key, setting it to the UPN of the logged-on target user.

  • HKLM:\System\CurrentControlSet\Control\CloudDomainJoin\JoinInfo

    The script will also create a log file in the ODM agent Files folder and then perform cleanup to remove the Scheduled Task and remove the script itself.

SetUserEmailValues.txt

Param (
)
 
$output = New-Object BinaryTree.ADM.Agent.PSHelpers.PSOutput
Try{
   $ODMADService = Get-Service -Name ODMActiveDirectory -ErrorAction SilentlyContinue
   }
Catch{
    Write-Output "Error Retrieving Service Status...Terminating with error: $($Error)"
    Exit 1
    }
If($ODMADService){
    Write-Output "ODM AD Agent Service Found...Finding ODM AD Agent Service Path"
    $ODMADServicePath = (Get-ItemProperty -Path HKLM:SYSTEM\CurrentControlSet\Services\ODMActiveDirectory).ImagePath
    $ODMAgentPath = Split-Path $ODMADServicePath
    $ODMAgentPath = $ODMAgentPath.Trim("`"")
    Write-Output "ODM AD Service Path: $($ODMAgentPath)"
}
Else{
    Write-Output "No ODM Agent Service Found...Terminating"
    Exit 1
    }
 
$ScriptName = "UpdateCloudJoinInfo.ps1"
 
 
##### The $Script contains the PS script that gets create in the ODMAD agent folder.
$Script = @"
 
`$TranscriptFile = "`$(`$ODMAgentPath)\Files\PowerShell-`$(Get-Date -f yyyyMMdd-HHMM)-UpdateCloudDomainJoinReg.log"
Start-Transcript -Path `$TranscriptFile
 
Try{
   `$ODMADService = Get-Service -Name ODMActiveDirectory
   }
Catch{
     Write-Output "Error Retrieving Service Status...Terminating with error: `$(`$Error)"
     Exit 1
     {
If(`$ODMADService){
    Write-Output "ODM AD Agent Service Found...Finding ODM AD Agent Service Path"
    `$ODMADServicePath = (Get-ItemProperty -Path HKLM:SYSTEM\CurrentControlSet\Services\ODMActiveDirectory).ImagePath
    `$ODMAgentPath = Split-Path `$ODMADServicePath
    `$ODMAgentPath = `$ODMAgentPath.Trim("``"")
    Write-Output "ODM AD Service Path: `$(`$ODMAgentPath)"
}
Else{
    Write-Output "No ODM Agent Service Found...Terminating"
    Exit 1
    }
 
# Get Workgroup/AD User
`$CurrentLoggedOnUser = (Get-CimInstance -Classname Win32_ComputerSystem | Select-Object -expand UserName)
Write-Output "  DEBUG: Current Logged On User: `$(`$CurrentLoggedOnUser)"
`$LoggedonUserArray = `$CurrentLoggedOnUser.Split("\")
`$LoggedonUser_Username = `$LoggedonUserArray[1]
Write-Output "  DEBUG: Current Logged On Username: `$(`$LoggedonUser_Username)"
`$LoggedonUser_Domain = `$LoggedonUserArray[0]
Write-Output "  DEBUG: Current Logged On Domain: `$(`$LoggedonUser_Domain)"
If (!([String]::IsNullOrWhiteSpace(`$CurrentLoggedOnUser)))
    {
        `$CurrentUser = Get-Itemproperty "Registry::\HKEY_USERS\S-1-12*\Volatile Environment"|Where-Object {`$_.USERDOMAIN -match `$LoggedonUser_Domain}
         Write-Output "  DEBUG: CurrentUser: `$(`$CurrentUser)"      
        If (![String]::IsNullOrWhiteSpace(`$CurrentUser))
            {
                `$CurrentLoggedOnUser = "`$(`$CurrentUser.USERDOMAIN)\`$(`$CurrentUser.USERNAME)"
                Write-Output "  DEBUG: Current Logged On User: `$(`$CurrentLoggedOnUser)"
                `$CurrentLoggedOnUserSID = split-path `$CurrentUser.PSParentPath -leaf
                Write-Output "  DEBUG: Current Logged On User SID: `$(`$CurrentLoggedOnUserSID)"
                If(`$CurrentUser.USERDOMAIN -match `$LoggedonUser_Domain)
                    {
                        `$UPNKeys = `$(reg query hklm\SOFTWARE\Microsoft\IdentityStore\LogonCache /reg:64).Split([Environment]::NewLine)| where{`$_ -ne ""}
                         Write-Output "  DEBUG: UPN Keys (Can be Multi-Valued): `$(`$UPNKeys)"
                        ForEach (`$item in `$UPNKeys)
                            {
                                `$UPN = reg @('query',"`$item\Sid2Name\`$CurrentLoggedOnUserSID",'/v','IdentityName','/reg:64')
                                 Write-Output "  DEBUG: UPN: `$(`$UPN)"
                                If (`$LASTEXITCODE -eq 0){`$CurrentLoggedOnUserUPN = (`$UPN[2] -split ' {2,}')[3] ; Break}
                            }
                    }
            }
    }
 
Write-Output "  DEBUG: Current Logged On User UPN: `$(`$CurrentLoggedOnUserUPN)"
`$LoggedonUser = `$CurrentLoggedOnUserUPN
Write-Output "  DEBUG: Logged On User: `$(`$LoggedonUser)"
 
## Get Tenant ID from Registry
`$TenantInfoKey = "HKLM:\System\CurrentControlSet\Control\CloudDomainJoin\TenantInfo"
If(Test-Path -Path `$TenantInfoKey) {
    `$TenantInfo = Get-ChildItem -Path `$TenantInfoKey
    `$TenantID = `$TenantInfo.Name.split("\")[-1]
     Write-Output " TenantID: `$(`$TenantID)"
}
 
`$JoinInfoPath = "HKLM:\System\CurrentControlSet\Control\CloudDomainJoin\JoinInfo"
If(Test-Path -Path `$JoinInfoPath) {
    `$JoinInfo = Get-ChildItem -Path `$JoinInfoPath
    `$JoinInfoGUID = `$JoinInfo.Name.Split("\")[-1]
    `$ValuePath = `$JoinInfoPath+"\"+(`$JoinInfo.Name.Split("\")[-1])
    `$UserEmailValue = (Get-ItemProperty -path `$ValuePath -Name UserEmail)
     Write-Output "  Current UserEmail Value: `$(`$UserEmailValue)"
    If(`$UserEmailValue.UserEmail -ne `$LoggedonUser) {
        Write-Output "  DEBUG: Will Change Value"
        Set-ItemProperty `$ValuePath -Name UserEmail -Value `$LoggedOnUser}
}
 
### Clean Up Environment
Write-Output "Cleaning Up Script Environment, Deleteing files and removing Scheduled Task"
 
Unregister-ScheduledTask -TaskName "Update Cloud Join Info" -Confirm:`$false
Remove-Item -path "`$ODMAgentPath\$($ScriptName)" -Force
Stop-Transcript
 
"@
 
############################################################################################################
 
### Create Powershell Script
$AgentPath = "$ODMAgentPath\"
$ScriptFullName = $AgentPath+$ScriptName
If(!(Test-Path $ScriptFullName)) {
    New-item -path $AgentPath -Name $ScriptName -Type "File" -Value $Script
}
 
$TaskName = "Update Cloud Join Info"
$Argument = "-ExecutionPolicy Bypass -File `"$($ODMAgentPath)\$($ScriptName)`""
$Action = New-ScheduledTaskAction -Execute "PowerShell.exe" -Argument $Argument
$Settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries
$Principal = New-ScheduledTaskPrincipal -UserId "LOCALSERVICE" -LogonType ServiceAccount
$Trigger = New-ScheduledTaskTrigger -Atlogon
$Trigger.Delay = "PT8M"
$ScheduledTask = New-ScheduledTask -Action $Action -Trigger $Trigger -Settings $Settings
# Register Scheduled Task 
Register-ScheduledTask -TaskName $TaskName -InputObject $ScheduledTask -User "NT AUTHORITY\SYSTEM" -Force
 
 
return ($output)
Verwandte Dokumente

The document was helpful.

Bewertung auswählen

I easily found the information I needed.

Bewertung auswählen