The Mysterious Case of the $ (a.k.a. Dollar Sign) Character in Hybrid Azure AD Joined Devices

Hi Everyone, Jorge Lopez here.  I'm a Hybrid Identity Premier Field Engineer at Microsoft. 

Today I'll be sharing with you an interesting scenario with a customer and their hybrid Azure AD joined devices.

For this scenario , I won't go into the details on how Hybrid Azure AD Join works, so If you are not familiar with the concept,  stop for a second and read this documentation :  This scenario does not apply for Azure AD registered or “pure” Azure AD Joined devices.

One morning, I was still on my second sip of coffee when I was contacted by a customer regarding the appearance of a dollar sign character at the end of the names on Hybrid-Joined Azure AD Devices.

At the beginning it didn't feel like a big deal since as you may know Hybrid Joined Devices in Azure AD are synced or “joined” using a common Source Anchor , this anchor attribute is usually ObjectGUID in AD -> DeviceID in , this means that  no matter how many changes you make to the rest of the attributes of the object these are bound or joined through this anchor that will never change during the lifetime of the object (or that's the idea)  , so even if the display name is different ,  in the backend Azure AD knows it's the same object, so there wasn't really an issue here.  

The issue for this customer is that they were doing some custom scripting to generate reports about Bitlocker status from all their Windows 10 devices in Azure, for this to be accurate, both on-prem and Azure AD display names would be needed to have an exact match.

Their results were inconsistent , since for a period of time it was not able to find a matching computer in Azure AD with the same name of the On-prem AD this is because … yes you guessed it … in Azure AD the object display name had a trailing “$” at the end while the on-prem computer object did not.   

We first thought about modifying the script to use a different attribute or even add some logic to the script to validate both with or without the “$” but hey! that would have been too easy right?  

At this point I was intrigued and decided to dig deeper into this and try to find exactly what was happening.

The first step was to try to replicate the issue, so we took an existing machine named PFEWIN10.

Computer Name in OS Settings:


Display Name in Azure AD Devices:


So far so good – names match, then we renamed it through the system properties within the Operating System from PFEWIN10 to NEW-PFEWIN10, waited for the next sync cycle and there it was, in Azure AD the computer's display name was:  NEW-PFEWIN10$ while in the Computer Name in the OS settings was without the “$”

Computer Name in OS Settings:


Display Name in Azure AD Devices list: 


Azure AD Connect was telling us about the update in its log as well as the audit log in for the device in the azure portal:


So, it shows the computer was renamed but what is up with that “$” character at the end of it?

After a couple of hours (and sometimes more), this was being ‘fixed' by itself.


We noticed the following logs in Azure AD once the display name was showing the correct value without the $ character and the Device Audit logs was showing us the change, notice the “Initiated by” Column


Aha! – So, the Device registration service is now renaming this back to the actual name in AD without the “$”, the question is why AAD connect was adding it in the first place?

Time to go to the Azure AD Connect Rules for Device Synchronization and look at the Devices Rule.

We found that there is an Inbound Rule (In from AD) that is calculating the value of the displayname Target attribute to Azure AD. This rule is called:  In from AD – Computer Join

It has the following function for the displayname rule: 


In English, the above rules provision the device displayname attribute in Azure AD to match the displayname attribute on-prem, BUT if displayname is empty then use the CN attribute from the computer object On-prem.

This explains it now – So when a computer is first joined to the domain , the displayname attribute in AD is usually  , hence in Azure AD , the device's display name is populated with the value of the CN attribute (as the rules mandates), this will not change until the actual displayname on-premises is populated on certain events.. like renaming a computer.   

In Domain Services when a computer is renamed,  the displayname  attribute is then populated with the name of the computer and appends a $ to the end (this is on-prem AD by design), since now displayname attribute is not NULL , AAD connect uses displayname on-prem instead of CN  to populate the display name value in the AAD object… still with me?

This rule logic is basically the culprit of having $ in the end of all devices that have been renamed.

This is great but now:  how are these getting renamed back by Device Registration Service (DRS)? The answer is simple , DRS does NOT uses displaymame  or CN  to populate the Display Name in Azure AD, DRS uses another attribute called: dNSHostName a.k.a. the FQDN of the computer,  DRS uses a function to only take a portion of this attribute , from the first dot to the left.  

i.e.: will be populated as abc123

Very Cool, so how do we fix it using AAD Connect?

The first thought was to remove the “IF” condition in the rule, so AAD connect will never use displayName as the attribute to project, instead always use CN (Direct Flow type instead of Expression). That would work for most organizations, except for those that have computer names larger than 15 characters since CN is basically the short name (NETBIOS) of the computer causing the display name in Azure to be truncated. 

For consistency, I suggested to create a custom rule that will be using the same logic to project the display name attribute in Azure AD, which is using the “left” side of  dNSHostName, Fortunately, Azure AD Connect Sync Rules Editor support some text manipulation functions too!

To accomplish this, a new custom Sync Rule in Azure AD Connect that overrides the default displayName attribute must be created.

Here's the function that would do the trick:

UCase(Left([dNSHostName],InStr([dNSHostName],”.”) – 1))

Function Explanation: “Find the position of the first dot on dNSHostName attribute, then take the left portion of this same attribute starting on that position minus 1 and change it to upper case.

*The UCase function (to uppercase) is for consistency only, not required.

STEP 1) Make sure the dNSHostName attribute is being synced to Azure AD from On-prem

NOTE: This attribute is not in the list of the “Directory Extensions” configuration through the AAD Connect console, hence this must be added directly on the connector in the Synchronization Service Console.

1. On your Azure AD Connect Server, Open Synchronization Service – Connectors Tab – and Select the connector type Domain Services. Click on Properties (This should be the connect for you on-prem domain).  


2. On the properties Screen, in the connector Designer section Click on Select Attributes  and make sure the dNSHostName attribute is checked, if it's not, then click on Show All checkbox at the top right – find the attribute, select it and click OK.


STEP 2) Create a Custom rule in AAD Connect

1. Create a New Rule with Higher precedence (Lower Number) in Azure AD connect Rules Editor that contains the function mentioned above.  Make sure the scheduler is disabled, this is to prevent the sync to run while changes are being made and to new rules before exporting any changes to Azure AD. To temporarily disable the scheduler, start PowerShell and run Set-ADSyncScheduler -SyncCycleEnabled $false.image010.png

2. On your Azure AD Connect Server – Open AAD Connect Synchronization Rules Editor and Click on “Add new rule” , make sure the Direction is set to “Inbound”



3. On the Description page, enter the following:


  • Name: Give the rule a descriptive name, try to keep the default naming convention if possible.
  • Description: Give some clarification so someone else can understand what the rule is for.
  • Connected System should be your on-prem AD domain name
  • Connected System Object Type should be set to Computer
  • Set Metaverse Object Type to device
  • Link type: Make sure you choose Join (In that way, this rule only overrides the attribute once the objects are already provisioned by the default rule)
  • Precedence: Provide a value that is unique in the system. A lower numeric value indicates higher precedence.
  • Leave Tag empty and make sure the Enable Password Sync and Disabled options are unchecked
  • Click Next

4. On the Scoping Filter screen, leave this empty and click Next

5. On the Join Rules page, Leave the field empty and click Next

6. On the Transformations page, Click Add transformation, then choose the following options: image014.png

  • Choose Expression as the Flow Type
  • Select displayName as the Target Attribute
  • in the Source field Type the Expression: UCase(Left([dNSHostName],InStr([dNSHostName],”.”) – 1))

Warning: Please do not copy-paste the above function since some characters like double quotes and commas from the web page formatting may not be the same that are needed in AAD connect functions (character-wise) and may cause sync errors.

  • Apply Once should be unchecked
  • Merge Type should set as Update
  • Click Add

7. The scheduler can now be enabled again, From PowerShell, run Set-ADSyncScheduler -SyncCycleEnabled $true.


STEP 3) Run a Full Sync

Running a Full Sync is needed after any Rule change in AAD Connect, otherwise this change won't take any effect.

On the Azure AD Connect Server, Open a PowerShell Window

  1. Type Start-ADSyncSyncCycle -PolicyType Initial


Warning: This will take from a few minutes to several hours depending on the size of your organization.

That's it!  Now all the Hybrid Azure AD Joined Devices' display names in Azure AD will always match on-prem Computer Names all the time,  those devices that already have the proper name will not be changed but all new computers that will be synced for the first time will now use the same provisioning logic to populate its display name.

If you followed along, hope you enjoyed!


This article was originally published by Microsoft's Azure Blog. You can find the original article here.