ImmutableID – mS-DS-ConsistencyGuid – AADConnect – ADMT – Part 4 – Groups

In earlier posts I talked about ADMT and user accounts. Now a migration is never a full migration if groups are not migrated too. But how Azure AD Connect deals with users and groups is a bit different, certainly when custom anchors are being used. In this post we will be looking at how we can migrate groups from our SOURCE forest to a TARGET forest while maintaining the same link to the groups in Azure AD itself. First a review of anchors, attributes and metaverses:

In the picture above we see a quick representation of a user in Active Directory being synchronized to Azure AD. The ObjectGuid (copied into mS-DS-ConsistencyGuid) is copied into the sourceAnchor attribute of the user in the metaverse (database of Azure AD Connect) and that value is again copied into the cloudSourceAnchor attribute in Azure AD.

For additional linkage, the CloudAnchor attribute (created by Azure AD) is copied back to the metaverse as the CloudAnchor and then into the msDS-ExternalDirectoryObjectID in Active Directory for a user.

By having the same values on Active Directory and Azure AD – we can match users between the two directory services. When we perform an ADMT – and copy users from a source to a target, we just have to make sure these attributes remain the same – OR that we have a successful join of the now 2 source objects (2x Active Directory) in the metaverse.

A join makes sure there is only 1 representation of a user object in the metaverse of Azure AD Connect – and as such – only a single user in Azure AD.

In Azure AD Connect, you can configure the join rule based on an “anchor”. I call it the forest anchor as I don’t think there is a formal word for it.

Forest Anchor and groups

The forest anchor that you configure during the custom installation of Azure AD Connect however only applies to user objects. Not groups or devices. Now, devices do not really matter for this post – so I will focus on Groups only. And specifically security groups, as (AD) distribution groups are not synchronized to Azure AD at all.

By default, AAD Connect does have a join rule for Groups. The join rule is based solely on the msDS-ConsistencyGuid attribute, and thus you would think that in a standard ADMT migration for a group where the SOURCE attribute mS-DS-ConsistencyGuid is copied into the same target attribute would fix everything. However, this is where things go wrong: Where for users the ObjectGUID of a user in AD is copied into the mS-DS-ConsistencyGuid attribute field for that same user by Azure AD Connect, the same does not apply to groups. Meaning – by default the mS-DS-ConsistencyGuid of a group stays empty.

This means that prior to a migration we need to manually copy the source group OBJECTGUID into that group’s mS-DS-ConsistencyGuid field for mapping to happen. Once the mS-DS-ConsistencyGuid of the source group is set, then ADMT can copy this value to the target group during migration. Again, this is something ADMT or AADConnect will not do. Failing to manually copy this will result in multiple groups in Azure AD Connect – and thus Azure AD.

While each group might have the same members because of ADMT, their Object Id’s in Azure are different and thus permissions will not be applied to the new group (and to be more honest – it is confusing as you don’t know which group is from which AD).

So, we need to ensure we can join the groups and as said there are 2 options.

  1. Set the mS-DS-ConsistencyGuid on the source prior to the ADMT migration
    this will result in a matching attribute and a join rule will be activated. To help with this, I’ve added instructions on how to make sure this is set automatically in the source environment later in this post.
showing joined groups based on consistencyGuid match
  1. We create a custom rule that allows joining on something else than just msDS-ConsistencyGuid, but for example on the “custom” forest anchor we used for user objects. Given the complexity, this I will leave for now, but it is doable.

mS-DS-ConsistencyGuid for Groups

User objects in Active Directory will see their msDS-ConsistencyGuid being updated by Azure AD – is the attribute had a NULL value prior to synchronization. Effectively allowing Azure AD Connect to copy the ObjectGuid value into the msDS-ConsistencyGuid attribute. While this is not automated for groups, we could do exactly the same to prepare ourselves for an ADMT migration. In short, the instructions below will copy the user behavior to groups as well.

First, check if your Azure AD Connect configuration runs in Exchange Hybrid Mode – without this mode the group rules will not fire. – if you want to use a Pshell script.. check the last paragraph on this post..

  • In the synchronization rules, under Direction – select the Outbound direction and then click Add new rule
  • On the initial page:
    • give the rule a name (Out to AD – Group ImmutableId)
    • select SOURCE AD as the Connected System
    • Select Group as the Connected System Object Type
    • Select Group as the metaverse object type
    • Set Link type to Join
    • Set Precedence to +1 of the last rule (usually >200 is good)
  • Select transformations page and
    • Set flow type to Expression
    • Set target attribute to mS-DS-ConsistencyGuid
    • Paste the code below in the Source field
    • Leave Apply Once deselected
    • Set merge type to Update
  • Click Save
IIF(IsPresent([sourceAnchor]),IIF(IsPresent([sourceAnchorBinary]),[sourceAnchorBinary],IgnoreThisFlow),IgnoreThisFlow)

And this new rule will trigger the same attribute flow as for users, ensuring groups also have their mS-DS-ConsistencyGuid attribute filled with the ObjectGUID (or actually the cloudSourceAnchorBinary from the metaverse, but that is filled by the ObjectGUID). When performing ADMT, the migrated groups will be joined together.

Synchronizing

You might be thinking this is all. However, if you had already imported the groups, the join rule will not kick-in. You will need to remove the groups from scope (effectively deleting them from the metaverse) and then reimport them to make the join work. This because of the fact that the sourceAnchor (based on ObjectGUID that was not copied) is still the immutable unique identifier for them in the metaverse and the created cloudAnchor in Azure AD is unique to each of the group objects as well.

Members of a group

While users are easily migrated, a group object is a bit more complex as it contains members. And members is an array on the group that is imported. Azure AD Connect will not append that array (the membership list) it will put in one source.

Similar to the ADMT migration of users and AAD Connect rule priorities, one AD is the winner for the attributes. This means in short – the first AD Domain/Forest added to Azure AD Connect is the winner for the “members” attribute for groups. In short, if the SOURCE AD was added first the members of the groups in SOURCE will always be replicated to Azure AD – and all members of the TARGET ADMT migrated group will be discarded.

If you would like to change this, and have the target as the primary, you’d need to change the order of the rules ensuring TARGET has a higher precedence than SOURCE.

Conclusion

It is a bit of a shame that someone forgot the rule to write-back the mS-DS-ConsistencyGuid for groups, certainly as it is by default being used in the join rules when multiple forests are connected. Now even when it is connected – be very aware that only the highest priority domain wins the members of the group and multiple groups are not merged. If you needed to have specific groups be the “winner” for the members you can create a separate inbound rule with the scope for those groups and the members attribute set, but that’s for another day … (or when requested)

PowerShell script

There are many scripts that can write the mS-DS-ConsistencyGuid for groups, but most of them require an input file with the groups. Something I would not like to do.. because it can contain typo’s etc. And obviously I want a script I can run over and over and over without it destroying stuff. So instead I wrote my own (in case you don’t want to use the method above). The script essentially scans a SearchDN for all groups without the ms-ds-consistencyGuid and only for those object copies those objectGuids into it. Furthermore, the script has a -confirm mode so you can actually scan first…

script to set ms-ds-ConsistencyGuid on groups that do not have this yet…

#script to set ms-ds-ConsistencyGuid on groups that do not have this yet... 

Param(
	[Parameter(
		Mandatory=$true,
		HelpMessage="Type the DN of teh OU / forest to target.. for example: ou=production,dc=domain,dc=root,dc=local"
		)]
	    [ValidateNotNullOrEmpty()]
        [string[]]
    	[Alias('Please provide the DN')]	
	    $DN,
        [Parameter(
        Mandatory=$false,
        HelpMessage='write $true to confirm writing of the ms-ds-ConsistencyGuid - else monitoring mode only - default is $false'
		)]
          	[Alias('Please use $true to confirm and write changes')]	
	    $Confirm = $false
)

Write-host "Targetting: $DN"
 $GroupsWithoutCon=Get-ADGroup  -Properties ms-ds-ConsistencyGuid -Filter * -SearchBase "$DN" | where {$_.'ms-ds-consistencyGuid' -eq $null}

 If ($Confirm) {Write-host "Confirm is set to $true - Writing changes" -ForegroundColor Yellow}
 else {Write-host "Confirm is set to $False - not writing - display only" -ForegroundColor Green}

 ForEach ($Group in $GroupsWithoutCon) {
    write-host ("setting ms-ds-consistencyGuid on " + $group.DistinguishedName)
    If ($confirm) {
        
        Set-AdGroup -identity $Group -Replace @{'mS-DS-ConsistencyGuid' = $group.ObjectGUID.guid}
    }else{
        
        Set-AdGroup -identity $Group -Replace @{'mS-DS-ConsistencyGuid' = $group.ObjectGUID.guid} -WhatIf
    }
 }

 

et voila..

Tagged , , , ,