Advanced AAD Connect Permissions Configuration

Updated with additional requirements and scenarios , 2017-10-26.

I recently worked with a customer that needed assistance in configuring the additional permissions required for AAD Connect delegation.  After chasing down an incredible number of prerequisite information, I decided it would be more helpful to my customer to put together a tool that would help them configure the various permissions delegations.

AAD Connect supports several different write-back scenarios to the on-premises environment:

In addition, the tool supports configuration of the special permissions required to enable Password Hash Sync.

While many organizations have previously configured AAD Connect to use an account that is a member of Domain Admins or Enterprise Admins, it's not a best security practice.  However, for enabling password hash sync to the cloud or write data back to the on-premises environment, the AAD Connect service account needs to have the ability to extract the necessary information from the on-premises directory and update on-premises attributes.

Enter the tool.

With this tool, you can:

  • Grant the AAD Connect service account delegate permissions over objects in specific OUs for writeback
  • Initialize the environment for device writeback
  • Grant the AAD Connect service account  'Replicating Directory Changes' and 'Replicating Directory Changes All' permissions for password hash sync

Some organizations also require additional write permissions for the adminSDHolder container (for example, if they have objects currently or previously protected by adminSDHolder that are being synchronized to Office 365) and the ms-DS-ConsistencyGuid property, so those can also be updated/modified using this script.

Running the tool

After you've downloaded the tool, launch an elevated PowerShell prompt on your AAD Connect server.  For most organizations, you'll run this from your AAD Connect server, which should have the AAD Connect modules installed (shocker, I know) and the MSOnline module.


  • Device WriteBack     If you are using this tool to configure DeviceWriteback, the MSOnline module is required.
  • Password WriteBack     If you are using this tool to configure Password Reset (password writeback), the ADSync module (installed with AAD Connect) is recommended, as it is used to determine the Azure AD Connect connector and update it.
  • Exchange Hybrid WriteBack, Password WriteBack, Groups WriteBack, msDS-ConsistencyGuid updating, adminSDholder modification, Password Hash Sync     For any of these features, you must have the Active Directory Remote Server Administration Tools (RSAT) installed--the script primarily relies on DSACLS.  You can install it by running Install-WindowsFeature RSAT-ADDS from an elevated PowerShell prompt.

Note about Multiple Domain Support

In the past few weeks, I've talked with several people attempting to use this tool in a mutli-domain (parent/child) environment.

You can run it one of two ways:

  • All from the AAD Connect server and using the parameters -ExchangeHybridWriteBackOUs, -PasswordWriteBackOUs, and -GroupWriteBackOU (optionally, using -Domain and -User to specify the service accounts you'll use for each AD connector, if you're not using the default AAD Connect service account).
  • From a DC in the child OU that you're attempting to configure permissions on

If you are running the -PasswordWriteBack in a child domain on a server that DOES NOT have AAD Connect, you will get a warning that you need to update the AAD Connector manually.

Use this parameter to configure Device Write Back. Using this parameter will require use of the AAD Connect modules, so AAD Connect must already be installed.  DeviceWriteBack also requires a particular version of the MSOnline cmdlets.  If you don't have them installed, it will attempt to go download them.

In order to make this work correctly across multiple platforms, I decided to use PowerShellGet to support the installation.  The latest Windows Azure AD v1 cmdlets are available as a download that way, so it seemed to make sense to try to use it.  Also, I tried to find the URL from the page, but we apparently now generate a token of some sort, rendering any download link invalid after a short period of time.  So, there's that, too.

This option will download and install the Microsoft Online Services Sign-In Assistant first (since it's a requirement), then proceed to install PowerShellGet and NuGet, and then finally, use PowerShellGet to download and install the MSOnline Module.  I go through a tremendous amount of effort to install stuff you should already have.

 If (!(Get-Module -ListAvailable MSOnline -ea silentlycontinue))
    Write-Host -ForegroundColor Yellow "This requires the Microsoft Online Services Module. Attempting to download and install."
    wget -OutFile $env:TEMP\msoidcli_64.msi
    If (!(Get-Command Install-Module))
        wget -OutFile $env:TEMP\PackageManagement_x64.msi
    msiexec /i $env:TEMP\msoidcli_64.msi /quiet /passive
    msiexec /i $env:TEMP\PackageManagement_x64.msi /qn
    Install-PackageProvider -Name Nuget -MinimumVersion -Force -Confirm:$false
    Install-Module MSOnline -Confirm:$false -Force
    If (!(Get-Module -ListAvailable MSOnline))
        Write-Host -ForegroundColor Red "This Configuration requires the MSOnline Module. Please download from and try again."

Whew! That was painful.

Used to specify the NetBIOS domain name for the AAD Connect service account.  If this parameter is omitted, the current NetBIOS domain name is used.

I found I needed this parameter when I encountered a testing scenario where I had deployed AAD Connect on a DC--since I could validate the user using Get-ADUser, I had no need to look elsewhere.  Except for those other 99% of the use cases where AAD Connect is deployed on a member server.  If you don't specify the user account, this parameter is ignored.

Use this switch parameter to set the permissions for Exchange Hybrid WriteBack.  Using my good friend DSACLS, I trudge through whatever OUs have been specified in ExchangeHybridWriteBackOUs.  Depending on your Exchange Schema version, you may have different attributes updated.  Exchange 2016 introduced the usage of msDS-ExternalDirectoryObjectID, so write permissions are given to that property as well.

The Exchange schema version is determined through this wizardry:

 $Schema = (Get-ADRootDSE).SchemaNamingContext
$Value = "CN=ms-Exch-Schema-Version-Pt," + $Schema
$ExchangeSchemaVersion = (Get-ADObject $Value -pr rangeUpper).rangeUpper

There are three potential ranges that we need to be concerned with, where $ExchangeSchemaVersion is:

  • less than 14734     This indicates that the environment's schema is less than Exchange 2010 SP3.  If an Exchange Schema less than 14734 is detected, the script will exit.
  • greater than 15316    This schema version indicates Exchange 2016 or later.
  • anything else     Any version of Exchange 2013 or any version of Exchange 2010 later than SP3

Use this parameter to specify target OUs to enable the service account writeback permissions. If this parameter is omitted, access is granted at the domain root.  The parameter is typed as an array, so you can enter one or more OUs in the standard array formats -- @('obj1','obj2') or 'obj1','obj2'.

OUs must be specified in the "OU=Child,OU=Parent,DC=domain,DC=com."  The format is validated using the following regular expression:

 '^(?i)(ou=)[a-zA-Z\d\=\, \-]*(,dc\=\S*,dc=\S*)'

I was previously using '^(ou=)[a-zA-Z\d\=\, ]*(,dc\=\w*,dc=\w*)' , but a colleague pointed out that it was failing on domains that had hyphens, so I modified the filter with the 2017-10-19 update.

That's the best that I could come up with--if you have a better one, I'd love to try it out.

OUs are also validated for whether or not the domain is valid.  The method that I use to do it is:

     Foreach ($OUPath in $OUs)
        [array]$OUSplit = $OUPath.Split(",")
        foreach ($obj in $OUSplit)
            If ($obj -like "DC=*")
                $OUVer += $obj + ","
        $OUVer = $OUVer.TrimEnd(",").ToString()
        If (!(Test-Path "AD:\$OUVer" -ErrorAction SilentlyContinue))
            $BadPaths += $OUVer
        $OUVer = $null

That way, I can verify if the DC=domain,DC=tld actually exists in your environment and then tell you otherwise.

I haven't put anything in to check if they're actually a valid OU structure yet.  It's not that I can't--just that I didn't put it in yet.  Gotta save something for the updates, right?

If you have more than one forest in your AAD Connect topology, you can use the Forests parameter to specify them for device writeback.  You must be logged on with an account that has enterprise admin privileges in the target forests.  Nuff said.

Use this switch parameter to configure Office 365 Group writeback permissions.  It uses GroupWriteBackOU if the parameter is specified; otherwise, it defaults to the value in AD connector.  If no container is specified and Office 365 group writeback has not been configured in AAD Connect, the script will exit.

Use this parameter to specify the Office 365 Groups writeback container.  If the container exists, the account specified will be granted access.  If the GroupWriteBackOU is specified and does not exist, it will be created (as long as the DN is formatted correctly and references a valid domain).

While the checking part was pretty easy, the process of creating a nested OU was not.  At least, not until I stumbled upon the [array]::Reverse method.  Using that, I was able to iteratively march through the array elements.

 [array]$OuPath = $GroupWriteBackOU.Split(",")
            $OuDepthCount = 1
            foreach ($obj in $OuPath)
                If ($OuDepthCount -eq 1)
                    $Ou = $obj
                    # Do nothing else, since Test-Path will return a referral error when querying the very top level
                    Write-Host Current item is $obj
                    $Ou = $obj + "," + $Ou
                    If (!(Test-Path AD:\$Ou))
                        Write-Host -ForegroundColor Green "     Creating OU ($($Ou)) in path."
                        New-Item "AD:\$Ou" -ItemType OrganizationalUnit

What's happening here:

  1. The value that's passed to $GroupWriteBackOU is in the form "OU=abc,OU=def,DC=domain,dc=com."  Using the Split method, I separate each of those elements into a new array element inside the array, so it ends up looking like this:

  2. Then, the magic of [array]::Reverse comes into play, and switches the order of the elements around, so that it now looks like this:


    No, I didn't lie. It's exactly reversed.

  3. In the next section, I start creating an DN path that I can validate using Test-Path AD:\$OU.  The sticky wicket is that if you try to do Test-Path "AD:\DC=com", you get this lovely error:

     test-path : A referral was returned from the server
     At line:1 char:1
     + test-path "AD:\DC=com"
     + ~~~~~~~~~~~~~~~~~~~~~~
     + CategoryInfo : ResourceUnavailable: (DC=com:String) [Test-Path], ADReferralException
     + FullyQualifiedErrorId : ADProvider:ItemExists::ADError,Microsoft.PowerShell.Commands.TestPathCommand

    Helpful, right? So, I put a counter in there for each iteration of the array, and if it's the first pass, we skip the Test-Path command.

  4. Finally, if the path tests as $False, then I create a new OU and continue the iteration until the end of the array.

I discovered some *really* interesting things about checking for the presence of certain paths.  For example, Get-ADObject and Get-ADOrganizationalUnit return hard errors when the target object isn't found.  You can't hide them inside a variable ($obj=Get-ADOrganizationalUnit $OU).  It ignores both -ErrorAction SilentlyContinue AND piping to Out-Null, which makes for an ugly script.

Test-Path AD:\$Ou was the answer to this problem.  However, if you just walk through the tree attempting to query for DC=com, you get the referral error I mentioned previously.  So you have to skip that one.  Can't ever be easy.

I'll move the OU checking code into the ExchangeHybridWriteBackOUs validation and return an error if the OU(s) specified don't exist.


Use this parameter to grant the service account user write permissions for msDS-ConsistencyGuid.  Yes, it's spelled differently depending on which interface you use.  Don't shoot the messenger.

Use this parameter to set 'Replicating Directory Changes' and 'Replicating Directory Changes All' permissions.  This is actually the easiest bit of code to implement, since it's only two DSACLS commands for configuring the permissions:

 If ($PasswordHashSync)
    $RootDSE = Get-ADRootDSE
    $DefaultNamingContext = $RootDSE.defaultNamingContext
    $ConfigurationNamingContext = $RootDSE.configurationNamingContext
    $cmd = "dsacls '$DefaultNamingContext' /G '`"$User`":CA;`"Replicating Directory Changes`";'`n"
    $cmd += "dsacls '$DefaultNamingContext' /G '`"$User`":CA;`"Replicating Directory Changes All`";'`n"
    Invoke-Expression $cmd | Out-Null

Use this parameter to enable password writeback.  It can read values from various places--the ExchangeHybridWriteBackOUs or PasswordWriteBackOUs parameters if specified.  The PasswordWriteBackOUs parameter takes precedence (so the ExchangeHybridWriteBackOUs parameter will be ignored).  Otherwise, it sets permissions at domain root.

Use this parameter to specify target OUs to enable the service account writeback permissions. If this parameter is specified in conjunction with the parameter ExchangeHybridWriteBackOUs, this parameter will take effect.  If this parameter is omitted but the ExchangeHybridWriteBackOUs parameter is specified, PasswordWriteBack will use the ExchangeHybridWriteBackOUs values.  If neither parameter is supplied, then permissions will be delegated at the domain root.

Use this parameter to specify the tenant credential used when returning domains from Office 365 for Device WriteBack.  If DeviceWriteBack is not selected, this parameter is not used.

Use this parameter to specify the tenant GUID used when configuring Device WriteBack.  If the DeviceWriteBack parameter is not specified, this parameter is not used.

If you have objects protected by adminSDHolder, you can use this switch to allow write-back delegation for those objects. If an object is a member of a group protected by adminSDHolder and the AAD Connect service account is not a member of Domain Admins or Enterprise Admins, Exchange Hybrid WriteBack and Password WriteBack may not work.  When you use this switch, the container calculated by "CN=AdminSDHolder,CN=System," + ((Get-ADDomain).DistinguishedName) is added to the WriteBackOUs array and then processed with the DSACLS command.

Specify the AAD account that will be granted permissions.  If no account is specified, attempt to locate the account through the connector properties.  If for some reason it can't figure out the account, it will exit (since you can't grant permissions to an account that doesn't exist). Duh.

Extracting the data from AAD Connect was actually a little more involved than I would have thought.  The user account information for the connector is not actually stored in the connector properties.  Why?  Ask the product group.

Instead, you can find the information located inside a backup of the AAD Connect configuration.  But where do you get that?  I'm so glad you asked.

You can use Get-ADSyncServerConfiguration to dump the configuration.  Then, you have to grab the connector ID for the on-premises AD connector, find the XML file related to that connector, and then look in following node:

 [xml]$ConnectorXMLData = gc <xmlfile.xml>

If you don't specify the Domain parameter, the script will also examine the XML to find the NetBIOS domain of the user (stored in ma-data.private-configuration.adma-configuration.forest-login-domain).

Specify a verfied domain for your AAD tenant instead of discovering a domain automatically.  This is only valid for configuring device writeback.  If you don't specify this parameter for configuring device writeback, the script will connect to AAD and return the first valid verified domain.  If the DeviceWriteBack parameter isn't specified, this parameter will be ignored.

I think that's all the bells and whistles for now.

If you didn't already see the link, it's on the TechNet Gallery at