This is about environments where an AADC (Azure Active Directory Connector) server syncs a local AD to AzureAD / O365. There are matching rules and key attributes that handle the sync relationship between a cloud object and it’s corresponding local AD object. AADC does its job fairly well and you don’t need to care about this stuff too much. But if it comes to migration situations, it’s good to have a closer look behind the scenes here. So, in this blog post, we will take a closer look at the ImmutableID match.
What is the ImmutableID?
The ImmutableID is an object property of each synced Azure AD user account. As the name suggests, the ImmutableID is a marking of the account that (almost) never changes. This property is important because AADC uses it to match these accounts with the associated source accounts in the local Active Directory. The AADC sync process finds the cloud object based on the ImmutableID.
So the local account and the synced cloud account are connected, even if the account changes its object name, or UPN, or mail address. Or even when the AADC server is failing and the object sync has to be rebuilt from scratch. AADC finds the couples again and matches the objects on both sides correctly. With the help of the ImmutableID.
ImmutableID = Base64 encoded GUID?
Based on the equal signs at the end of this value, it’s obvious that this is a Base64 encoded binary value. Administrators often think that the ImmutableID is simply the Object GUID of a local AD user – in Base64 encoding. This GUID is globally unique and also (usually) does not change over the object’s lifetime. For a simple quick check in most cases, you can expect the local AD objectGUID (which is the LDAP attribute for the object GUID) in the cloud property ImmutableID:
But this was only true for older versions of AADC in the dawn of DirSync. Just writing the objectGUID is just not the best option here.
First of all – why couldn’t they (the Microsoft API architects) just write this GUID value as a binary value to the cloud directory? Why did they specify it to be a Base64 value? It would have been possible to use a binary property representation in AzureAD! So we could see in all the administrative portals or PowerShell outputs the fine familiar GUID value. As in our example ‘97684bf9-da4d-4138-a3ee-02ec242cd0c3’. But no – we have to convert first the GUID string into a Base64. Otherwise, it would be just too easy to identify a user on the other sync side! (Sarcasm off). By the way, I wrote a blog post about converting GUIDs from binary to Base64 and vice versa.
And second: ‘A GUID does not change over the object’s lifetime’ is not true for all scenarios. Just think of a migration project for the local Active Directory infrastructure. If we migrate the user account to another local AD, they get a new GUID. Even if you use tools like ADMT, Quest, BinaryTree or whatever. But we want these users to keep their old O365 mailboxes, Onedrive for Business data, Teams memberships, and so on! How can the AADC sync match the migrated user with the same old cloud account?
Match! The mS-DS-ConsistencyGUID solution
The solution is simple: The AADC sync does NOT always use the normal object GUID for matching. Microsoft introduced a new dedicated matching attribute named mS-DS-ConsistencyGUID. AADC uses this attribute since version 1.1.524.0. We can preserve this mS-DS-ConsistencyGUID in a migration – and so we have full control over the matching of local AD users to their old cloud accounts. Here is an example of this ImmutableID match:
The mS-DS-ConsistencyGUID is a binary attribute for AD. The advantage over the exclusive use of the object GUID is that you can change mS-DS-ConsistencyGUID to any value you want. Ok, we cannot see it easily in the AD Admin tools. And maybe dealing with binary values in scripts might be a bit harder, but the ability to write any value is very important. Read how to manage writing to these matching attributes later in this blog post.
Initial filling the mS-DS-ConsitencyGUID attribute
So AADC uses mS-DS-ConsitencyGUID as a matching primary key. If you examine the attributes in a synced environment, you will discover that the ImmutableID in the cloud is still filled up with the object GUID of the connected user in the local AD. And if you look at the mS-DS-ConsitencyGUID: in most cases, the content of this is just the pure binary data of the GUID (read this article about how to convert these kinds of values back and forth).
The reason for this is simple: Every time AADC does find a new user to sync, but with an empty mS-DS-ConsistencyGUID, it takes the following steps:
- AADC takes the objectGUID value from the local AD.
- The sync engine encodes this GUID into a Base64 value. After that, it writes the value to the connected cloud user as the ImmutableID property.
- In the next sync cycle, the AADC writes the ImmutableID value from the cloud back to the local AD into the mS-DS-ConsitencyGUID.
- Then the hard link between the account locally and in the cloud is established and can be used to match these two users even through possible changes in the future (names, mail addresses, migrations).
This is a visible flow of the initial filling of the mS-DS-Consistency based on an example:
Choosing a non-default source anchor attribute
So basically, this is the way it goes when you choose the default settings in the AADC setup wizard. The so-called “source anchor” for matching the cloud object is normally the mS-DS-ConsistencyGUID. You can choose another source anchor in your local AD, but this would be a topic for an additional, separate blog post.
Changing the un-changeable
Hey, this is a blog about PowerShell scripting in the cloud, remember? OK, pretty little scripting so far in this post. Sorry. But finally here are some tasks associated with the ImmutableID matching that requires scripting skills. Imagine that for some reason, you have to adjust the source anchor attribute. Either on the local AD side (mS-DS-ConsitencyGUID) or on the cloud side (ImmutableID).
ImmutableID (Cloud) -> mS-DS-ConsistencyGUID (Local AD)
First example: You have the ImmutableID of a cloud user and want to write this as a binary mS-DS-ConsistencyGUID value to a given account in the local AD. This would enforce an ImmutableID match in the sync between the two accounts.
Import-Module ActiveDirectory
Import-Module AzureAD
Connect-AzureAD
#for the search: surname and LDAP path in local AD (distinguished name)
$sn = "Collings"
$dn = "CN=Irina Collings,OU=Users,OU=Cerro,DC=ldapexplorer,DC=com"
#get the ImmutableID value of the cloud account
$cloud = (Get-AzureADUser -SearchString $sn)
$base64 = $cloud.ImmutableID
#write it as binary GUID to the local Account
$binary = ([system.convert]::FromBase64String($base64))
Set-ADUser $dn -Replace @{"mS-DS-ConsistencyGuid"=$binary}
mS-DS-ConsistencyGUID (Local AD) -> ImmutableID (Cloud)
Second example: You have a local user with a certain mS-DS-Consistency value, and you want to write this value to a specific user in the cloud – also to enforce a sync match between the two accounts. There is one big problem: If the cloud account is already synced by AADC, you cannot touch it – synced accounts are read-only restricted for normal operations. So we have to exclude this account from sync first.
There is only one way to do this: Do something with the linked account in the local AD so that it is not included in the AADC sync anymore. In most cases, moving into an OU which is not synced will be the easiest way. Or you have an AADC filter in place and you can exclude objects from sync by setting specific attribute values.
What happens if you exclude a local AD user from AADC sync? The linked cloud account will be deleted!
Don’t panic – we just restore it from trash with all his data (mailbox, OneDrive …) and then the O365 account can be treated as a normal cloud-only account. You can set the ImmutableID property with standard cmdlets.
So the example starts at a point where the synced cloud account is deleted:
Import-Module ActiveDirectory
Import-Module MSOnline
Connect-MsolService
$upn = "little@up-in-the.cloud"
#get the binary value from the local AD acount
$localUser = Get-ADuser -ldapfilter "(userPrincipalName=$upn)" -Properties "mS-DS-ConsistencyGuid"
$binary = $localUSer."mS-DS-ConsistencyGuid"
$base64 = [system.convert]::ToBase64String(([GUID]$binary).ToByteArray())
#restore the cloud user from trash
Restore-MsolUser -UserPrincipalName $upn
#write the ImmutableID match marker to the cloud account
Set-MsolUser -UserPrincipalName $upn -ImmutableId $base64
By the way, I use the MSOnline PowerShell module here instead of the AzureAD module, because we need it to restore the account. And this is a thing that the AzureAD cmdlet does not provide!
objectGUID (Local AD) -> mS-DS-ConsistencyGUID (Local AD)
Third example: You want to transfer a GUID from a local AD user as an mS-DS-ConsistencyGuid value for another local AD user. This could be a preparation of an ImmutableID match.
Import-Module ActiveDirectory
$user1 = "CN=Edith Kirk,OU=Cerro,DC=ldapexplorer,DC=com"
$user2 = "CN=Paulina Knox,OU=Cerro,DC=ldapexplorer,DC=com"
#get the GUID of account 1 and convert it to a binary array
$usr = Get-ADUSer $user1 -Properties objectGUID
$binary = $usr.objectGUID.ToByteArray()
#write the value to account 2
Set-ADUser $user2 -Replace @{"mS-DS-ConsistencyGuid"=$binary}