I recently had a client who used Office 365 for Exchange Online and Teams while also having an on-premise Active Directory but did not appear to have AD Connect deployed to synchronize their on-premise Active Directory accounts with their Office 365 Azure AD accounts. This became a problem when we started the WVD deployment so the client agreed to have us focus on synchronizing the two directories before commencing with other planned projects.
Azure AD Connect Soft Match vs Hard Match
As some may already know, there are two ways of matching accounts in on-premise Active Directory and Azure AD:
- Soft Match
- Hard Match
Soft Match uses the properties of userPrincipalName and ProxyAddresses to determine (evaluated by Azure AD) whether an account in the on-premise Active Directory can be merged with an Azure AD account. This essentially means that if an account is found to have the same userPrincipalName or the same primary SMTP address of ProxyAddresses, then AD Connect will merge the two accounts.
More information about ProxyAddresses matching with the primary SMTP address can be found here:
How to use SMTP matching to match on-premises user accounts to Office 365 user accounts for directory synchronization
https://support.microsoft.com/en-us/help/2641663/use-smtp-matching-to-match-on-premises-user-accounts-to-office-365
Hard Match uses the property sourceAnchor/immutableID to match the on-premise Active Directory account to the Office 365 account. The default sourceAnchor that Azure AD Connect uses for the on-premise Active Directory is the objectGUID property and the immutableID property is a value assigned to the Azure AD user account. To perform a Hard Match between two accounts, we would set the immutableID property of the existing user in Azure AD to the Base64 encoded string of the ObjectGUID of the user in the on-premise AD.
More information about soft and hard match can be found here:
Azure AD Connect: When you have an existing tenant
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/how-to-connect-install-existing-tenant#sync-with-existing-users-in-azure-ad
The Problem
The plan for merging the accounts between on-premise and the cloud was to use the soft match method and the initial test with a newly created account worked without any issues. However, proceeding to accounts that have existed in the on-premise Active Directory would consistently throw a Duplicate Attributes and AttributeValueMustBeUnique error in the AD Connect export job. After reviewing the KB article below without finding a resolution, I decided to proceed with the hard match method.
Troubleshooting Errors during synchronization
https://docs.microsoft.com/en-us/azure/active-directory/hybrid/tshoot-connect-sync-errors
The immediate issue I had with the hard match method was that it required a lot of manual labour to extract the ObjectGUID from the on-premise AD account, convert it to a Base64 encoded string, then import it into the Azure AD account’s immutableId attribute.
Extract Immutable ID
$UPN = "jsmith@contoso.com"
$user = Get-ADUser -Filter ‘UserPrincipalName -eq $UPN’
$name = $user.name
$immutableid = [System.Convert]::ToBase64String($user.ObjectGUID.tobytearray())
Import Immutable ID
Set-MsolUser -UserPrincipalName jsmith@contoso.com -ImmutableId <convertedObjectGUID>
Having to perform the above for 50, 500 or 5000 and more accounts would not be efficient.
Solution
As with many laborious tasks in technology, the best way to minimize the amount of manual labour is to script the process and the following demonstrates this.
Step #1 – Extracting accounts in on-premise Active Directory
We will need to first obtain a list of users we’ll be hard matching with the accounts in Azure AD. If you are matching accounts that are nicely organized in OUs, you can use the following PowerShell cmdlet to export them into a CSV file:
Get-ADUser -Filter * -SearchBase "OU=Toronto,OU=Contoso-Users,DC=contoso,DC=com" -Properties * | Select-Object name,UserPrincipalName,emailaddress | export-csv -path c:tempToronto.csv
The PowerShell cmdlet above will export all of the accounts in the specified OU with the fields:
- Name
- UserPrincipalName
- emailAddress
Repeat the above for any other OUs that need to be matched.
Step #2 – Extracting accounts in Azure AD
The environment I worked in did not consistently have mirroring accounts in the on-premise Active Directory and Azure AD so I decided to export the list of accounts in Azure AD to compare in a spreadsheet:
Get-MsolUser | Select-Object DisplayName,UserPrincipalName,@{Name=’ProxyAddresses’;Expression={[string]::join(“;”, ($_.ProxyAddresses))}},ImmutableId | export-csv -path c:tempToronto-MSOL.csv
Step #3 – Compare the accounts in on-premise AD and Azure AD
With the two CSV files extracted, I placed the UPNs into an Excel spreadsheet and used Home > Conditional Formatting > Highlight Cells Rules > Duplicate Values feature to identify which accounts have matching ones in the other directory.
Step #4 – Extract on-premise AD accounts’ ObjectGUID and Convert to ImmutableID
Now that we have a list of UPNs for users who we intend on matching from the on-premise Active Directory, proceed to create a txt file with just the UPNs separated by line breaks and use the following PowerShell script to extract the ObjectGUID then convert the value to Base 64 so it can be assigned as the immutableID:
foreach ($UPN in Get-Content C:tempTorontoAccounts.txt) {
$user = Get-ADUser -Filter ‘UserPrincipalName -eq $UPN’
$name = $user.name
$immutableid = [System.Convert]::ToBase64String($user.ObjectGUID.tobytearray())
#$UPN,$name,$immutableid
#Store the information from this run into the array
[PSCustomObject]@{
UPN = $UPN
Name = $name
ImmutableID = $immutableId
} | Export-Csv C:tempUPNsWithImmutableID.csv -notype -Append
}
Step #5 – Import the UPNs with ImmutableIDs into Azure AD
The final step in this process is to use the CSV created in step #4 to assign the immutableIDs to the identified UPNs in Azure AD with the following script:
$onPremADUsers = Import-Csv c:tempUPNsWithImmutableID.csv
foreach ($row in $onPremADUsers)
{
#$row.UPN, $row.Name, $row.ImmutableID
Set-MsolUser -UserPrincipalName $row.UPN -ImmutableId $row.ImmutableID
}
The above will read the CSV file and assign the immutableID.
Step #6 – Confirm that the ImmutableIDs have been assigned
The last step, which is more of a verification step, is to review the UPNs that were assigned with the immutableIDs:
$onPremADUsers = Import-Csv c:tempUPNsWithImmutableID.csv
foreach ($row in $onPremADUsers)
{
Get-MsolUser -UserPrincipalName $row.UPN | Select-Object DisplayName,UserPrincipalName,ImmutableId
}
Hope this helps anyone who is looking for a quicker way of extracting and assigning sourceAnchor/immutableID so AD Connect can hard match accounts.
3 Responses
Hey there
i have some older on prem ad accounts and teir username doesnt match the username in o365
So for example on prem user is Frank but their o365 is fobrien
only 5 or 6 accounts like this
i have used frank objectguid and used it for fobrien immutable setting. Will this cause any issues?
I have a problem with line 4
$ immutableid = [system.convert] :: ToBase64String ($ user.objectGUID.tobytearray ())
the error reported is as follows:
Cannot call a method in a Null expression.
At character Line: 1: 1
+ $ immutableid = [system.convert] :: ToBase64String ($ user.objectGUID.toby …
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo: InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId: InvokeMethodOnNull
[system.convert] :: ToBase64String ($ user.objectGUID.tobytearray ())
There should not be any space in this command..
Like:
[system.convert]::ToBase64String($user.objectGUID.tobytearray())