In part 3a, we explained how ADFS can be used in
cross-forest migrations to ensure all users (migrated or not) can still
authenticate. In part 3B we will be looking at Pass-Through authentication and
how it affects migrated/non-migrated users.
First of all, we need to make sure we have pass-through authentication
agents deployed. In my environment I already have these agents deployed in the
source (FORESTROOT), but not in the target domain. Obviously non-migrated users
on the pass-through domain can authenticate.
So in order to first prove that the user is authenticating against the local domain (rather than using password sync), after the login, I checked the Security eventlog on the domain controller:
The event shows that the AzureADConnectAuthenticationAgentService.exe
is requesting impersonation.
We can now also deploy additional agents on the target system, in my case I installed the agent on the target domain controller (but obviously you should follow official recommendations). The agent can be downloaded from the portal:
After the installation, I wanted to make sure that the newly deployed agent was able to authenticate my non-migrated users. Similar to how ADFS (see chapter 3a) setup was done. In order to force the new domain controller to authenticate my users, I stopped the agent on the FORESTROOT domain controller.
Now when we try to login to AAD with a non-migrated user, we will still see the following entry in the FORESTROOT domain controller, indicating a successful login. You will actually notice 2 entries in the security eventlog. The first being a 4768 and the second being 4769
These two events basically indicate a cross-forest authentication. What is important to note though is the User ID field in the 4768 event. The username is not represented as a UPN, but with the NETBIOS name. So let’s proceed to move this user to the new domain. Similar to the ADFS setup, I manually set the UPN for the user and ensured the ms-ds-consistencyGuid is the same on the source and migrated objects. The difference between pass-through and ADFS now becomes clear. Until the AADSync synchronizes the data, the user will continue to be authenticated in the source forest. This as the pass-through agents will use the NETBIOS information. This is visible when we look at the export details in the MIIS console for our export to AAD after we migrated the user:
As indicated in yellow, the netBiosName changed to the
TARGET domain name. I manually edited the UPN of the user (in capitals for
In short, AAD will now upon entering a username in the login
field, get the netBiosName and validate the user against that.
It is not that only the pass-through agents of the TARGET forest will pick-up the authentication, any agent can pick it up, but it will perform an authentication for NETBIOS\Username using the information known (netBiosName + onPremisesSamAccountName).
So as you can see, even pass-through authentication can be used for authentication to AAD in cross-forest migration scenarios!
Next up is the cross-forest authentications for regular services (like file servers..)
To continue our coverage of ADMT and AAD, part three of the
series. I know I promised 3 articles, but given the amount of data, I’ll split
part 3 (authentication) in a few more posts..
We have 1 AAD and 2 AD’s; FORESTOOT.local as the source and
TARGET.local is still the target AD forest. There is a two-way forest trust
between the two forests Forestroot.local is still based on Windows 2016, TARGET
is still based on 2012R2. And we continue to have our members server in the
target.local domain that functions as the ADMT and AAD Connect server.
This post will dive further into authentication and access
as users are migrated from the source to the target.
When looking at ADMT and migrations in combination with AAD,
we have two types of authentication that we need to take care of. Firstly, the
cross-forest authentication to member servers and resources, and secondly the
authentication on AAD itself. In our earlier migrations we ensured that we
would authenticate against the AAD itself by synchronizing the passwords and
using managed domains, but there are 3 types of authentication possible with
AAD, which we will start with.
AAD Based Authentication
With federated authentication, a user that tries to login to
AAD will be redirected to a federation server (usually ADFS) and needs to
perform an authentication there. Upon successful authentication, a token is
provided that the user then provides to AAD to indicate a successful
authentication and providing identity proof. It is up to the federation server
to authenticate the user (in any form) and provide the token. Basically, AAD
doesn’t care how you authenticated, as long as the token the user provides is valid.
In our cross-forest authentication scenario, this comes down to essentially the same as accessing cross forest resources. In our setup, we did not add any UPN suffixes to the TARGET domain nor did we add them to the routing table (as having conflicting UPN suffixes would not be supported). During our user migration (using ADMT) the UPN automatically got updated on the new user object in the TARGET domain to represent target.local.
Given our users need to login with their email (UPN), means
that if our federated user wanted to authenticate against the ADFS server
hosted in forestroot.net, the server would validate the UPN only at its own forest.
This as the UPN routing table in the forest trust has the suffix “forestroot.net”
pointing to the forestroot.local forest (this as the UPN suffix was not added
to TARGET.local, nor was it added in the UPN suffix routing table on the trust).
Only if users where to change their login name to TARGET\username would the forest trust be applicable. So in order to avoid this situation, we can actually move the ADFS services to the target domain. This way, non-migrated users authenticating with their UPN, would be authenticated against the FORESTROOT.local forest, given their UPN matches the UPN routing suffix in the forest trust. But (migrated) users, who have their UPN set locally (in the target.local forest) can be authenticated by the Target.local domain controllers.
In my demo environment, I’ve setup another federation server in the target.local forest and gave it a new public URL. I’ve also manually set the UPN for my (migrated) user in the target domain to match the UPN of that object in the forestroot.local domain (matching the user’s e-mail address), as well as ensured that the ms-ds-ConsistencyGuid was equal for both objects.
The thing we must do now, is switch the federation service
manually on Azure AD for our specific domain. Switching means that all users
trying to authenticate with @forestroot.net to Azure AD will be redirected to
the target.local ADFS server. Given the forest trust and UPN routing suffix on
that trust, users trying to authenticate to the ADFS server and that do not
exist in the local domain(!) will be validated over the trust.
(Note that in this
case, the ADFS can only look-up UPN’s in its own domain, not forest. Given the
UPN forestroot.net was not added on forest level, only domain wide
authentication can be performed. Adding forestroot.net to the target forest
would result in the UPN suffix routing table disabling the routing for the
suffix and therefore render this solution unusable).
In order to change the AAD configuration, I loaded up PowerShell
and logged into MSOL and changed the domain federation configuration:
Next up, is changing the ADFS configuration. By default it
will use the objectGUID for validation (see my other entries) and as such, we
need to configure ADFS to use the ms-ds-consistencyGuid. You can obviously also
have AAD Connect configure this for you. I followed this article.
Now after this is all set, we are ready to go. You can try to login to Offic365 and the main Microsoft AAD page will redirect now to the new ADFS server. There you can login using the migrated account (in the form or TARGET\user, or email@example.com) or you can actually also login still using the original account using FORESTROOT\user. Non-Migrated (@forestroot.net) users will be authenticated based on their UPN over the forest trust.
In short, this article showed you the inner workings of the
O365 login. It uses a combination of UPN + ms-ds-ConsistencyGuid which can
exist on more than one domain. Using some trickery we can actually move all our
users to the new forest while still allowing non-migrated users access to a new
ADFS farm to login. Migrated users can continue to use their existing UPN while
logging on to the new forest, even though that new forest does not have their
UPN suffix officially registered.
I promised I would make three blog post entries.. but will
continue in part 3b with the PassThrough Authentication.
In our previous post we explored the backend of Azure AD
Connect and what happens in multi-forest scenarios. In this post we will be looking
into the ADMT migration and the effects on the cloud accounts.
The FORESTROOT domain has a user (firstname.lastname@example.org) which has been assigned a full E5 license to Office 365. The user is able to login and has a mailbox as well as some other things configured.
We continue to build on our previous installation, but in
order to support the migration, we will be switching the Azure AD Connect
instance to the stand-by instance and disabling the Azure AD Connect on the
Ensuring all users are there
But prior to doing this, let’s make sure the details will be the same when switching over. On the FORESTROOT AADConnect server, open the MIISClient (“C:\Program Files\Microsoft Azure AD Sync\UIShell\miisclient.exe”) and select the metaverse tab and search for the user:
Now most-importantly is the sourceAnchor. As indicated, its f8ys/….
On the TARGET Azure AD Connect server, open the MIIS client,
and if not already available in the MetaVerse, run an import and sync job.
If you notice that the
user is not in the metaverse, then this is because you left the mail attribute
field empty. As this is the unique identifier for the users in each forest in
our scenario, you need to ensure all users have the “cross-forest anchor”
attribute (mail) populated.
When opening the properties of the user, you should see the
Prior to disabling the
FORESTROOT or SOURCE AADConnect, make sure the TARGET AADConnect can see and
read all existing objects.
Switching Azure AD Connect’s
Open Azure AD Connect on FORESTROOT, and click configure on the main page. Then select Configure staging modeOpen Azure AD Connect on FORESTROOT, and click configure on the main page. Then select Configure staging mode
Login to the tenant, and then select enable staging mode and
de-select the start synchronization process when the configuration completes.
This basically disables the AAD on the FORESTROOT.
Now we can do the same on the TARGET Azure AD Connect, but
here we want to disable the staging mode and there remove the checkbox. On this
system we can initiate the sync process.
ADMT – Migrating a user
Let’s suppose we perform a standard ADMT without setting any option for the migration. To ensure the Azure AD Connect does not run (as I want to have control over it), I open up Azure AD Connect (from the Desktop).
I start ADMT with my special ADMT user and perform the migration of email@example.com
Given I still want to use the source account, I leave it enabled, but will also migrate the user’s SID (for other purposes outside the scope of this post).
As you can see, I did not exclude any attribute from the migration.
After the migration we take a look at what would happen with the account in Azure AD, we do this by opening the MIIS Client and performing an import on TARGET and FORESTROOT followed by a synchronization on FORESTROOT and TARGET. You will notice nothing has changed. The object in Azure AD Connect is still the FORESTROOT object and the TARGET object is ignored. Why? Let’s checkout the migrated object in TARGET in the ADUC console:
As you can see, the default ADMT migration does not include the mail attribute.
Which is strange, given we did not exclude any attribute by default.
Set o = CreateObject("ADMT.Migration") WScript.Echo o.SystemPropertiesToExclude
On the prompt, go to C:\Windows\SysWow64
The output will show all the excluded properties of the system, and as you will see, it contains the mail, proxyaddresses, and a whole lot more. The output will show all the excluded properties of the system, and as you will see, it contains the mail, proxyaddresses, and a whole lot more.
Next what we need to do is ensure we include the properties
that we want in our migrations. For this, execute the following on the same
Copy the attribute list as shown above
Create a new file
Paste the following information:
Set o = CreateObject("ADMT.Migration") o.SystemPropertiesToExclude = "msDS-PSOApplied,msDS-HostS………"
Where the SystemPropertiesToExclude is the list
you actually want to exclude I removed, mail and proxyAddresses, DepartmentNumber,
EmployeeNumber, employeeType, homePostalAddress and some other properties..
Run the first script to validate the inclusion
of the attributes
Now we can re-do the ADMT migration by deleting the object
in TARGET, or update the ADMT migration by running it again and allowing
I just deleted the object and re-did the entire ADMT. Now in ADUC we actually see that the mail attribute was copied too. What is the effect on our object in AAD Connect, now that the mail field was populated too?
You will notice that the Contributing MA has been switched
to TARGET.local for our user. But as you can see the cloud anchor is still set
to f8ys/…. Which means, this user’s mailbox, login and all is still safe.
Now we can close the still opened Azure AD Connect configuration
page that was pausing our synchronization and execute a delta sync through
How come we don’t have a problem with this user compared to
our previous post where a change in the sourceAnchor was detected?
When Azure AD Connect synchronizes users, it will take the
ObjectGUID from a user and copy it into the ms-DS-ConsistencyGuid attribute
field (or any other field you have specified as the immutableID field and that
is capable of hosting the same data type). When performing an inter-forest migration
using ADMT, the process actually copies the ms-DS-ConsistencyGuid attribute to
the migrated object.
Given the uniqueness of ObjectGuid for every forest/domain, you cannot copy the ObjectGuid from source to target. That is why the migrated user will have a unique ObjectGuid. If ms-DS-ConsistencyGuid was not populated yet (because it was a brand new user), or another attribute that is excluded from ADMT is used as the ImmutableID, the new Azure AD Connect will create a new ImmutableID. In our example, the migrated user Smith, has an ObjectID of :
While his ms-DS-ConsistencyGuid (copied from FORESTROOT) looks like:
In the next blog-post we will see what happened to the authentication of the migrated user. Cause as some readers may have noticed, we still do not have implemented the azureinfra.com UPN on the TARGET domain…….
My posts on the ImmutableID seem to continue attraction from all over the world, and thus, let’s continue the fun. In a new series of posts we will be looking at the influence of the ImmutableID and Cross-Forest Anchor (name given by me, not sure if it is the actual name for it) in an ADMT cross-forest migration scenario. Or in other words, how can we make sure to keep the AAD (/Office 365) user the same, while migrating the backend user between forests.
In the first part we will go over the tools and show how certain things work in the back-end by importing duplicate users.
First the setup, I have 1 AAD and 2 AD’s; FORESTOOT.local is the source and TARGET.local is the target AD forest. While Forestroot.local is based on Windows 2016, TARGET is based on 2012R2, just for the sake of showing this will work also on older AD implementations.
In the target.local domain I have a member server that will
function as the ADMT and AAD Connect server.
First things first, let’s install ADMT:
Create a new user “admt-admin”
Add the user to Domain Admins
Create the Forest trust to Forestroot.local can
be one way or two way)
On the PDC of Forestroot.local:
Create a local domain security group called
Create the Registry Entry: TcpClientSupport = 1
(DWORD) under HKLM/CCS/Control/LSA
Enable Account Management Audit (success /
failure) in the Default Domain Controller Policy
Add admt-admin to the Built-in\Administrators
Login to the ADMT member server as admt-admin and install ADMT
Secondly, let’s install AAD Connect:
have AAD Connect on my Forestroot domain controller. But given we are now going
to use 2 forests, we have to be able to select our immutableID and cross-forest
anchor. Furthermore, usually these migrations end-up in removing the source
forest all together, so we’d need to install AAD Connect again anyway.
The idea here is to install the 2nd AAD Connect in Staging mode only. This allows us to review the configuration, the exported objects and if indeed our ruleset and settings replace the backend accounts on our AAD users, rather than creating new ones, or removing them! (which can happen in a faulty config). So on the ADMT server, install AAD Connect and choose the custom installation option, add both forests to the configuration:
On the UPN screen, select Continue without adding UPN suffixes to verified domains. This is because we don’t want to interrupt the UPN routing between the two domains as part of the forest trust. When we migrate the users, we will also migrate their UPN itself.
Next is the screen for uniquely identifying our users, in
this screen there are two settings that need to be configured.
First is the what I call Cross-Forest
Anchor. This attribute identifies a single user having two accounts (one in
each forest). The link between the two can be based on any attribute, but
usually it is the mail attribute field, or in the case of an Exchange ResourceForest,
it is the ObjectSID and the msExchangeMasterAccountSID (the 2nd
option). It is also possible that the sAMAcountName is the same (but not
I’ve configured the system to use PassThrough Authentication. This is to make things a bit more complex, the easiest would be to use Password Sync and the hardest would be to use Federation (in case the UPN of the user does not change), but we will cover the authentication part later.
If two of “the same” users are found that don’t have a matching
attribute, two things can happen. The users get removed from the metaverse (as
we will see later), or two accounts are created in AAD.
The second option is the ImmutableID. In the later versions
of AAD Connect, when choosing Let Azure manage the source anchor, the
ObjectGUID of the user is automatically copied into the ms-DS-ConsistencyGuid
attribute and that is used for the anchor. But you can also specify your own
In our previous posts, this anchor was used to match two user objects to a single AAD user in the metaverse. But with the later versions, the Cross-Forest Anchor does this for us automatically. As I want to use the default ms-DS-ConsistencyGuid anyway, I left it to the default setting. I finished the installation of AAD Connect, but making sure to select Staging mode.
The initial look
We will start by creating duplicate accounts, and matching
them on email attribute.
Now we open the MIISClient, so we can see under the hood
what’s actually going on. Go to C:\Program Files\Microsoft Azure AD
Sync\UIShell and open MIISClient.exe
Under the connectors tab, we see 3 connectors, one to the
AAD tenant, and two for AD (Forestroot / Target)
The way MIIS (AAD Connect
is based on it), works, is that there is a metaverse. A central database with
all our users, groups and other objects. Each Connector also has a connector
space. This space is a 1:1 match to the connected system (in this example AD).
It keeps track of all the imported and ready to be exported objects. The system
works as follows: An Import reads the source (AD) and puts all the objects in
the Connector Space. A Synchronization moves the objects into the metaverse,
keeping track of all the rules that apply to this connector (for example,
joins, renames, etc). Once a change in the metaverse for an object is detected it
is placed in the connector space ready for export. And on an export job, it
actually pushes the changes to the connected system.
Right-click the AD connectors, and select Full Import, once completed, right click TARGET and select Full Synchronization. This ensures that our initial object is in the metaverse. On the FORESTROOT connector, we are going to perform some investigations (to learn what happens). Right click the connector and select Search Connector Space. Leave the Scope to Sub-Tree and click search.
The list shown is the list of users in the connector space only. This is the 1:1 copy of the AD information, but it’s not yet in the metaverse itself. In the list you will find our Duplicate User. Click it and select properties (or double click).
The pop-up shows you the user and the changes (add to the
system in this case) and the attributes that have been read from the user.
Given this user does not have a lot of attributes set, there is only a limited
Before actually moving/importing the user in the metaverse, we can run a simulation. This can be done by clicking Preview..
There are two options available, delta and full. In this
case it doesn’t really matter which one you choose, so we will go ahead with
the Full Synchronization – Click Generate Preview
The preview generates what would happen to this particular object if a full sync would be executed.
It shows the Source Object Details similar to the ones shown
before, but in our case more importantly, there is a Join and Projection tab
available too. This one shows us that this object would be matched (joined) to
an existing object in the metaverse (remember, we already imported the user
from the TARGET AD and that was already synchronized to the MetaVerse).
Go back to the Start Preview tab, and click Commit (a warning will show indicating a new preview will be re-generated). By issuing the commit, we now have successfully copied the object into the metaverse and now should have a single object with 3 connectors in the metaverse. To check, close all the pop-up windows and select metaverse, and then search:
Find the user and double click to get its properties.
As you can see, the user was updated with the TARGET AD
information. Remember, the FORESTROOT sAMAccount name was “duplicate user”.
So an important lesson now, the order of the rules in the
AAD Sync Engine determines which AD is authoritative for objects and
attributes. Given we want to move to the TARGET domain, I added that one first
to AAD Connect, and then added the source domain.
If on the window we select Connectors, you can actually see the three connectors this object is connected to:
Now let’s take a look at where this join is configured in the ruleset. For this, we open the rule editor, let’s take a look at the configuration: Go to C:\Program Files\Microsoft Azure AD Sync\UIShell and open SyncRulesEditor:
The SyncRulesEditor shows you all the rules that are applicable to AAD Connect. In MIIS you had to programmatically set the rules, but in AAD Connect it’s a bit easier. As you can see, the first two rules are the User Join rules. Click the first one and select Edit (a pop-up will show, click NO). Select Join Rules and you will see:
This means that if the source attribute (from TARGET AD:
mail) is equal to an existing object in the metaverse with attribute mail,
these objects are Joined together.
As you can see, the 2nd rule has the same settings
as this applies to FORESTROOT. This means that when importing objects, they are
not matched on AD-to-AD and then pushed into the metaverse, but they are
AD->Metaverse and AD2->Metaverse.
Now let’s see what happens if we have a single object in FORESTROOT and after a while a new object is created in TARGET with the same mail attribute.
First, Jon Doe in FORESTROOT. It is added to the metaverse with a sourceAnchor of pPkD….. during a normal synchronization. We then created Jane Doe in TARGET and imported it as well. In this case I ran just the delta import from TARGET to show what is happening:
Next click the AAD Connector, select search Connector Space and set the scope to Pending Export. Click search. When you only have a few objects just click through the users to find the right one (in very large organizations, check the object in the MetaVerse first, grab the GUID for the right connector on the connectors tab, and search for that one in the pending export window).
The image above shows the export attributes (to AAD) for JaneDoe (which used to be Jon Doe), with a new sourceAnchor (4uYO….), but the two accounts are merged in the metaverse:
The change of the sourceAnchor attribute does not have to be
that bad, but we will see in a later chapter how to avoid this from happening.
When connecting AAD Connect to two or more forests, it will ask you if objects are unique within each forest, or if in the ruleset a join rule must be created. If you enable this option (which you should if you are doing AD Migrations) you should be aware that unwanted matches can occur. If running in complex environments, choose your attribute wisely. We’ve also seen that the first forest added to the configuration is leading. This means that the existing objects might be changed due to the objects (and their different values) in the first forest.
One of the most looked at topics on this blogpost is the ImmutableID series for Azure AD Connect and AADSync. And I wanted to give an update to this, given the latest versions of Azure AD Connect seemed to have adopted the idea to use the ms-ds-ConsistencyGuid (or any other value) to replace the ImmutableID used for synchronization. Don’t worry, please keep reading the other posts, as they clearly explain the how behind the idea of using the alternative ImmutableID.. and this post is just to tell you.. Microsoft has made the implementation a lot easier!
The good thing about new software is that bugs and ‘features’ are removed.. the bad is that sometimes what ever you have blogged about makes either no sense, or even worse it only applies half to it from that point on.
So as AADSync was replaced by AD Connect, I got emails about the configuration of the mD-DS-ConsistencyGuid configuration in AD Connect not correctly working anymore. So, in order to relieve me from those email (you can still send them no worries) but more to make everyone aware of how this works in AD Connect (tested version 18.104.22.168); part two of the mS-DS-ConsistencyGuid as the immutable ID.
So a recent project got me thinking about this. In this particular scenario there is already a forest (1 domain) using DirSync to replicate their users to AAD, and the requirement is to prepare for an AD migration, while also adding other users to the same AAD tenant. As usual, user objects might be duplicate between the two forests and we want to use the mS-DS-ConsistencyGuid attribute to be the immutableID.