Skip to content

Instantly share code, notes, and snippets.

@rbrayb
Created November 25, 2025 01:32
Show Gist options
  • Select an option

  • Save rbrayb/c8ad22cea0d84189ddadac613d4f443d to your computer and use it in GitHub Desktop.

Select an option

Save rbrayb/c8ad22cea0d84189ddadac613d4f443d to your computer and use it in GitHub Desktop.
Using PowerShell 7 with Entra External ID (EEID) to link identities
# If you haven't done this already...
# Install-Module -Name Microsoft.Graph -Repository PSGallery -Scope CurrentUser -Force -AllowClobber
# Install-Module -Name Microsoft.Entra -Repository PSGallery -Scope CurrentUser -Force -AllowClobber
# Import-Module Microsoft.Graph
# Import-Module Microsoft.Entra
# Sign in interactively to your EEID tenant.
Connect-MgGraph -Scopes 'User.ReadWrite.All', 'Directory.ReadWrite.All'
# Update your values
$userObjectId = "2c...00" # User Object ID, User Principal Name, or email
$identityProvider = "facebook.com" # issuer value as used by the external identity provider
$issuerUserId = "5eecb0cd" # issuerUserId for that external identity provider
$signInType = "federated" # e.g. emailAddress, userName, userPrincipalName, federated
try {
# Read current identities - MUST include $select to get identities property
$user = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/users/$userObjectId`?`
$select=id,displayName,userPrincipalName,identities"
if (-not $user) {
Write-Error "User not found: $userObjectId"
exit 1
}
Write-Host "Found user: $($user.displayName) ($($user.id))"
Write-Host "`nCurrent identities:"
if ($user.identities -and $user.identities.Count -gt 0) {
$user.identities | Format-Table signInType, issuer, issuerAssignedId -AutoSize
} else {
Write-Host " (No existing identities found)"
}
# Prepare new identity object
$newIdentity = @{
signInType = $signInType
issuer = $identityProvider
issuerAssignedId = $issuerUserId
}
# Build identities array - preserve ALL existing identities
$identities = [System.Collections.ArrayList]@()
if ($user.identities -and $user.identities.Count -gt 0) {
Write-Host "`nPreserving $($user.identities.Count) existing identities..."
# Convert each existing identity to a proper hashtable
foreach ($identity in $user.identities) {
$existingIdentity = @{
signInType = $identity.signInType
issuer = if ($identity.issuer) { $identity.issuer } else { $null }
issuerAssignedId = $identity.issuerAssignedId
}
# Remove null issuer if present (for userPrincipalName type)
if ($null -eq $existingIdentity.issuer) {
$existingIdentity.Remove('issuer')
}
[void]$identities.Add($existingIdentity)
Write-Host " - Preserved: $($identity.signInType) | $($identity.issuer) | $($identity.issuerAssignedId)"
}
}
# Check if the new identity already exists
$exists = $false
foreach ($identity in $identities) {
if ($identity.issuer -eq $newIdentity.issuer -and
$identity.issuerAssignedId -eq $newIdentity.issuerAssignedId -and
$identity.signInType -eq $newIdentity.signInType) {
$exists = $true
break
}
}
if (-not $exists) {
# Add the new federated identity to the existing identities
[void]$identities.Add($newIdentity)
Write-Host "`nAdding new identity for provider: $identityProvider"
Write-Host "Total identities to update: $($identities.Count)"
# Debug: Show what we're sending
Write-Host "`nIdentities being sent to API:"
$identities | ForEach-Object {
Write-Host " - $($_.signInType) | $($_.issuer) | $($_.issuerAssignedId)"
}
# Update the user with ALL identities (existing + new)
$body = @{
identities = @($identities)
}
$jsonBody = $body | ConvertTo-Json -Depth 10
Write-Host "`nJSON Body:"
Write-Host $jsonBody
Invoke-MgGraphRequest -Method PATCH -Uri "https://graph.microsoft.com/v1.0/users/$($user.id)" -Body $jsonBody
-ContentType "application/json"
Write-Host "`nUser identities updated successfully"
}
else {
Write-Host "`nFederated identity already exists for this user"
}
# Verify the linking - include $select for identities
Write-Host "`nUpdated identities for user:"
Start-Sleep -Seconds 2 # Brief pause to ensure changes are committed
$updatedUser = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/v1.0/users/$($user.id)?`$select=identities"
if ($updatedUser.identities -and $updatedUser.identities.Count -gt 0) {
Write-Host "Total identities: $($updatedUser.identities.Count)"
foreach ($identity in $updatedUser.identities) {
Write-Host " - Type: $($identity.signInType)"
Write-Host " Issuer: $($identity.issuer)"
Write-Host " IssuerAssignedId: $($identity.issuerAssignedId)"
Write-Host ""
}
} else {
Write-Host " (No identities found - this may indicate an issue)"
}
}
catch {
Write-Error "An error occurred: $_"
Write-Error $_.Exception.Message
if ($_.Exception.Response) {
$reader = [System.IO.StreamReader]::new($_.Exception.Response.GetResponseStream())
$responseBody = $reader.ReadToEnd()
Write-Error "Response: $responseBody"
}
exit 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment