How to hard-match Entra ID users via the Graph API or the Graph SDK for PowerShell

Long story short, I was answering a question around hard-matching user objects earlier today and wanted to include an article with detailed instructions on how the process works. Interestingly, all the articles I could find online seem to leverage the now deprecated MSOnline/AzureAD modules, and while these should still do the job, better solutions are available now. So, here’s a quick and dirty article on how to perform hard-match via the Graph API methods or the corresponding Graph SDK for PowerShell cmdlets.

First, a very quick introduction for those that are unaware how hard-match works. In a nutshell, the process “generates”  an unique identifier for the on-premises user object and stamps it against the “matching” cloud object. Back in the day, the objectGUID property was used for this, with the mS-DS-ConsistencyGuid one taking over few years ago. Either way, we have a GUID value, which we need to transform and “stamp” on the cloud object’s ImmutableId property. Effectively, you are the one deciding which two objects to link together.

To generate the corresponding immutable ID value, we take the object’s GUID from AD and convert it to Base64-encoded string. This operation can of course easily be performed via PowerShell, and in turn we can leverage the AD cmdlets in order to fetch the value from the user’s object to streamline the process. Here are some examples:

#Generate ImmutableID for given AD user
[system.convert]::ToBase64String((Get-ADUser pesho -Properties mS-DS-ConsistencyGuid)."mS-DS-ConsistencyGuid")
LspMdPCr8k2xp6yXApVuqA==

#Generate ImmutableIDs for all AD users</pre>
Get-ADUser -Filter * | select UserPrincipalName,ObjectGUID,@{n="ImmutableID";e={[System.Convert]::ToBase64String($_.ObjectGUID.tobytearray())} } | Export-Csv -nti C:\temp\immutableID.csv

The resulting string will looks something like “LspMdPCr8k2xp6yXApVuqA==”. Once we have it, all we need to do is to add its value to the corresponding user object within Entra ID. When using the good old MSOnline or Azure AD PowerShell modules, the corresponding property is ImmutableId. When using the Graph methods however, you will have to instead use the OnPremisesImmutableId property. Here are some examples:

#Update the OnPremisesImmutableId for a given user directly
Update-MgUser -UserId user@domain.com -OnPremisesImmutableId "LspMdPCr8k2xp6yXApVuqA=="
Get-MgUser -UserId shared2021@michev.info -Property OnPremisesImmutableId | select OnPremisesImmutableId

OnPremisesImmutableId
---------------------
LspMdPCr8k2xp6yXApVuqA==

Of course, doing things one at a time is boring and prone to copy/paste errors. So here is an example that leverages sample CSV file, such as the one we exported above. We have a column UserPrincipalName to designate the user (the UPN of the users will most likely not match if you are resorting to hard-match, but it’s just an example after all), the Entra ID user that is, and a column ImmutableID to designate the value we want to stamp on the OnPremisesImmutableId property.

#Bulk update ImmutableID based on a CSV file
$var = Import-CSV C:\temp\immutableID.csv
$var | % { Update-MgUser -UserId $_.UserPrincipalName -OnPremisesImmutableId $_.ImmutableId }

For the sake of completeness, here are also the “raw” Graph API methods you can leverage for the same operation. Basically, a PATCH operation against the /users/{userId} endpoint, simple stuff:

PATCH https://graph.microsoft.com/v1.0/users/user@domain.com
{
"OnPremisesImmutableId": "xc/mL6kUzEqfKPAZV7Zd+g=="
}

GraphHardMatch

And that’s it. Wait for the sync to run (or force it) and the Entra ID user should now be “linked” to the on-premises one. Happy “matching”!

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.