Back to script library
Entra / Microsoft 365 · Users & guests

Migrate user profile card settings

Migrate custom properties on the Microsoft 365 user profile card to standard Entra ID attributes such as EmployeeId and CostCenter.

Connect & set up

Run these once per session. All scopes are read-only unless the script makes changes.

Connect-MgGraph -NoWelcome

Run it

The main script. Copy it, or download the .ps1 and run it from your console.

Connect-MgGraph -NoWelcome
# Check that we have the right permissions - in Azure Automation, we assume that the automation account has the right permissions
If ($Interactive) {
[string[]]$CurrentScopes = (Get-MgContext).Scopes
[string[]]$RequiredScopes = @('PeopleSettings.ReadWrite.All', 'User.ReadWrite.All')
$CheckScopes =[object[]][Linq.Enumerable]::Intersect($RequiredScopes,$CurrentScopes)
If ($CheckScopes.Count -ne 2) {
Write-Host ("To run this script, you need to connect to Microsoft Graph with the following scopes: {0}" -f $RequiredScopes) -ForegroundColor Red
Disconnect-Graph
Break
}
}
# Get licensed member accounts for the tenant, excluding utility accounts
[array]$Users = Get-MgUser -All -PageSize 500 -Filter "usertype eq 'member' and accountenabled eq true and employeeType ne 'Utility' and assignedLicenses/`$count ne 0" `
-Sort displayName -ConsistencyLevel Eventual -CountVariable Count `
-Property DisplayName, UserPrincipalName, id, employeeType, userType, employeeOrgData, accountEnabled, employeeId, OnPremisesExtensionAttributes, department
Write-Host ("Found {0} licensed member accounts to process" -f $Users.Count) -ForegroundColor Green
$Report = [System.Collections.Generic.List[Object]]::new()
[int]$i = 0
ForEach ($User in $Users) {
$i++
Write-Host ("Processing user {0} of {1}: {2}" -f $i, $Count, $User.DisplayName) -ForegroundColor Yellow
# Fetch the data from the on-premises extension attributes
$CostCenter = $User.onpremisesExtensionAttributes.extensionAttribute15
$EmployeeId = $User.onpremisesExtensionAttributes.extensionAttribute12
$EmployeeType = $User.onpremisesExtensionAttributes.extensionAttribute11
$Division = $User.department
# Set some default values if values are missing in the custom attributes
If ($null -eq $CostCenter) { $CostCenter = "Not defined" }
If ($null -eq $EmployeeId) { $EmployeeId = "000000" }
If ($null -eq $EmployeeType) { $EmployeeType = "Permanent" }
If ($null -eq $Division) { $Division = "HQ" }
$Parameters = @{
employeeOrgData = @{
"costCenter" = $CostCenter
"division" = $Division
}
EmployeeId = $EmployeeId
EmployeeType = $EmployeeType
}
Try {
Update-MgUser -UserId $User.Id -BodyParameter $Parameters -ErrorAction Stop
$DataLine = [PSCustomObject][ordered]@{
User = $User.displayName
UserPrincipalName = $User.UserPrincipalName
EmployeeId = $EmployeeId
EmployeeType = $EmployeeType
CostCenter = $CostCenter
Division = $Division
}
$Report.Add($DataLine)
} Catch {
Write-Host ("Failed to update user {0}: {1}" -f $User.DisplayName, $_.Exception.Message) -ForegroundColor Red
}
}
# Now remove the old custom attributes
Write-Host "Removing old custom attributes from profile card" -ForegroundColor Green
Remove-MgAdminPeopleProfileCardProperty -ProfileCardPropertyId CustomAttribute11
Remove-MgAdminPeopleProfileCardProperty -ProfileCardPropertyId CustomAttribute12
Remove-MgAdminPeopleProfileCardProperty -ProfileCardPropertyId CustomAttribute15
$Report | Export-Csv -Path ".\UserProfileCardMigrationReport.csv" -NoTypeInformation -Encoding UTF8
$Report | Out-GridView -Title "User Profile Card Migration Report"
Attribution