How to hard match user accounts in Azure AD

Azure AD Hard Match User Accounts

Recently we were asked if we could help out one of our clients with something I’m sure many other companies have found themselves in, user account separation. They have been using Office 365 and manually creating users that match their existing on premise accounts. It started innocently enough, with just a few test users and over time grew to 300! Of course this created huge managed overhead as they had to manage the same user in Azure and on premise AD. Of course AD Connect will allow you to synchronise your on premise users but they didn’t want to disrupt their cloud based users in the process.

Now, if you attempt to sync your on-prem users to Azure AD that have the same UPN, the sync will fail with an error indicating that the user already exists – duplicate account.

OK, so what are our options here?

One option is to delete the cloud account and have AD Connect recreate it. However, this could have issues with licensing, mailbox access and you may still have other sync issues and end up with some users missing.

Either way, the client did not want to go down this path, so the only other option is to “hard match” the cloud account with its relevant on premise object.

AD Connect uses an attribute called the “ImmutableID” to match the Azure AD object with the on premise object. However, the on premise account doesn’t have an ImmutableID attribute so you can’t just find it and apply it, instead it uses the ObjectGUID and converts it to a base64 string to get the ImmutableID.

You can see the ObjectGUID for any  user by looking in ADUC, Attribute Editor tab.

OK, a bit to take in there. So here’s a quick table outlining it all.

User On-prem AD ObjectGUID On-prem AD ObjectGUID (converted to Base64) Azure AD ImmutableID
[email protected] 4acbdc47-2a79-4836-9285-593ea01e9d3f R9zLSnkqNkiShVk+oB6dPw== R9zLSnkqNkiShVk+oB6dPw==

As you can see, when the ObjectGUID attribute is converted to a Base64 string, the value matches the ImmutableID. If these 2 objects match, AD Connect sees them as one object and happily syncs them.

Now, when a user is manually created in Azure AD, the ImmutableID is blank. So if you have an on premise user with a UPN of [email protected] and you manually create the same user name in Azure AD, the ImmutableID will be blank, and when AD Connect sees the object it will kick out a “duplicate object” error.

OK, so how do we fix this mess?

What we need to do is get a list of all the cloud accounts, find their equivalent on premise account, get the objectGUID, convert it to Base64 and then apply that value to the cloud account. AD Connect will then match the 2 objects.

How do we do this?

PowerShell of course.

You will need a few things for this:
The MSOnline powershell module
The ActiveDirectory powershell module
Global Admin access to the tenant containing your users
Read access to your on prem AD

If you don’t have the MSOnline module, open up PowerShell and run Install-module MSonline

Below is the code we used to hard match the user objects, it’s far from pretty but it did the job in the time we had.

WARNING: If you decide to use our script in your environment, you do so at your own risk, we accept no responsibility for any negative impacts it may cause.

Import-module msonline

Import-Module activedirectory


#Get a list of all the Azure users

$users = get-msoluser

foreach ($user in $users) {

#Ensures the object has an @CompanyX UPN, has never been synced, and contains details for a first and last name

if ($user.UserPrincipalName -match “” -and !$user.LastDirSyncTime -and $user.FirstName -and $user.LastName) {

#Put the SAM account together by getting the last name, adding an underscore and adding the first name (eg. smith_john). This will need to be modified to match whatever your company uses as a SAM account format.

$sam = $user.LastName + “_” + $user.firstname

#Get the AD user object based on the created SAM above, get the ObjectGUID value and convert it to a base64 value.

$ImmID = Get-ADUser -identity $sam -Properties ObjectGUID | select ObjectGUID | foreach {[system.convert]::ToBase64String(([GUID]($_.ObjectGUID)).tobytearray())}

#Sets the converted ObjectGUID as the ImmutableID for the user

set-msoluser -UserPrincipalName $user.UserPrincipalName -ImmutableId $ImmID



After the script was executed we kicked off a sync of AD Connect which matched up all the user objects with their on premise user account and had the 300 plus manually created user accounts now synced.