Wednesday, 24 March 2021

Implementing hybrid AAD join over a VPN - the userCertificate attribute saga

Do you know what the userCertificate attribute is? If you don't then keep on reading.

This was fun. Once I learned more about how hybrid Azure AD join worked, I understood the behavior and was able to figure out how to make this work.

First, a little bit about the basics of HAADJ. What is a HAADJ device? This is a device that is joined to AD and registered with Azure AD. You can't be joined to both directories at the same time. Also you can't sign into a HAADJ device with Azure AD credentials. 

We know that we need an Azure AD Connect server. 

Version 1.1.819.0 and later of Azure AD Connect includes an option to configure Hybrid AAD Join. But what does that mean? When you choose this option the wizard creates a Service Connection Point in AD. The SCP contains all the information that a workstation needs to perform the HAADJ process.  

This isn't just a notional thing. You can actually see the SCP in AD using ADSIEDIT and connecting to the domain in the Configuration context. This is the SCP. The GUID (62a0ff2e-97b9-4513-943f-0d221bd30080) is what Windows 10 devices search for using an LDAP query, and is the same from organization to organization.

Have a look at the keywords and you will see the details of the specific organization's Azure AD domain and directory ID.

The next thing we do is to synchronize the workstations with AAD. Again we do this using Azure AD Connect. 

Check the box for the OU you need. The AAD Connect synchronization service runs on a schedule and creates computer objects in AAD for your workstations.


That's only the behind-the-scenes prep work though. On the workstation a scheduled task runs (Microsoft>Windows>WorkPlace Join). This task actually implements the Workplace join element. The device must have already synced to AAD for this to be successful.

That's it, that's all you need to do to implement HAADJ for an organization and to be fair, it just works. However there are some complications when most of the devices are remote and connect to the VPN infrequently. Then the process doesn't work and you need to understand the process and behavior a little more in order to make it work.

The first thing to understand is that the scheduled task really only runs when the user logs on to the workstation. That's the first trigger associated with the task.

There is a second trigger for this task. It runs whenever it detects Event ID 4096 in the event logs. In my experience though, this doesn't make any difference, and the task doesn't run again after the logon.


"Automatic device join pre-check tasks completed. The device can NOT be joined because a domain controller could not be located. The device must be connected to a network with connectivity to an Active Directory domain controller".

In the event log we get this continual error. We can see that workplace join fails as the device does not have line of sight to a domain controller. Unfortunately we are not connected to the VPN at that stage. The user may then connect to the VPN but at that stage it's too late, the scheduled task doesn't run again. You can see why this works seamlessly on the LAN, as the workstation is authenticating with a domain controller on log on and not using cached credentials.

OK, what if I run a script to run that scheduled task after the user connects to the VPN? I should be able to figure that out, right.

schtasks /Run /TN “Microsoft\Windows\Workplace Join\Automatic-Device-Join”

This is the command you need to run to kick that off.

However I found that it is not that simple. There are several steps involved to workplace join a device and you have to wait for the various schedules to see that in action. I'll explain the steps and introduce a new concept - the userCertificate attribute.


Azure AD Connect is configured to only synchronize devices that have the userCertificate attribute configured. AAD Connect does its job well and just filters out any devices that don't have this attribute set. You don't get an error or a warning to say that they are missing, which is a real nuisance.

So where does the attribute come from? These are two computers from the same organization, computer A has it and computer B doesn't. Computer A has synchronized with AAD but computer B has not. So how does that happen?

The science bit

Whenever the workplace join scheduled task runs it checks for a direct connection to a domain controller. When it finds one it looks for the Service Connection Point in AD using an LDAP query. The SCP has information on which AAD tenant the device should join. At that point the computer generates a self-signed certificate and the userCertificate attribute is added to the computer properties in AD. All is well at that stage and the computer will workplace join. Well, not really, quite a bit has to happen yet. If we run the workplace join scheduled task again at that point it will fail.

Automatic registration failed at join phase. Exit code: Unknown HResult Error code: 0x801c03f2. Server error: The device object by the given id (876df222-8565-4118-8193-f1d051d12e19) is not found.

It will tell us that the directory object cannot be found. Of course that makes sense. The device did not synchronize with AAD because of the missing userCertificate attribute. Now that we have forced that to happen, we must wait for the AAD Connect sync service to run again and this time the device sync successfully to AAD.

Now we must wait for the workplace join scheduled task to run again and this time, all the elements are in place and the workplace join is successful. This all works seamlessly for computers on the LAN but it does not work very well for VPN connected computers.


I created a task sequence that executes the workplace join scheduled task and I deployed it to VPN connected devices.

The script will execute the scheduled task every 10 mins. Then I encourage users to connect to the VPN and the magic happens.

  • Script executes #1 (needs to have line of sight to DC) - scheduled task runs and finds SCP in AD with LDAP query. The computer generates a self-signed certificate and the userCertificate Attribute is updated in computer properties.
  • AAD Connect sync service runs on a schedule - sync computer object to AAD
  • Script executes #2 (needs to have line of sight to DC) - scheduled task runs and finds SCP in AD with LDAP query. Device is workplace joined.
  • User that signs into the device will get an Azure AD user token that can be used to authenticate with Azure AD-based services

Don't forget to remove the deployment afterwards.

You can search AD to get a list of computers that are missing the userCertificate attribute.

Get-ADComputer -LDAPFilter '(!(userCertificate=*))' | Select Name,DNSHostName | export-csv -path C:\GH\Emptyattrib.csv

This will get you started but will include servers. You can filter them out.


You can also do a custom search on a specific OU using the LDAP query: 

(!(userCertificate=*))

I hope this helps you to understand what is going on with HAADJ. Until next time……..