Synchronizing users between two AD Domains without trust

AD LDS SyncRecently I had an interesting job at a customer, who used a web application with an address book. The web application used LDAP queries to Active Directory to get all users addresses and phone numbers. This information was then searchable on a public web site located in DMZ.

The problem here is that we had an internet facing server. We could not allow it to make queries directly to the internal Active Directory. We decided to install a new AD LDS (Lightweight Directory Services) partition in the DMZ where we could ask our queries.

Next problem: We have to populate our new LDS partition with users. Normally this would be done with a system designed for it, like Forefront Identity Manager. Here we needed a quick-and-dirty solution to get started, and I therefore wrote a PowerShell script that copied the attributes we needed from our Active Directory.

One of the first things to solve was to find who and what to sync. With ten thousands of users in Active Directory we needed a solution to select users, even though they were spread across several OUs. Also, Swedish laws regulate what information to publish, so we had to filter sensitive information.

We ended up with a solution where only users in a specific OU were synced, but they also needed to be member of a specific group. We also filtered disabled users.

$ADUsers = Get-ADGroupMember -Identity "grp_ADSyncUsers" -Recursive | Get-ADUser -Properties `
     SamAccountName,GivenName,Surname,DisplayName,Title,Office,Department,Company,EmailAddress,Mobile,OfficePhone,Modified,Enabled | `
     Where-Object { $_.Enabled -eq $true -and $_.DistinguishedName -like "*$sourceou" }

We now have too much data. Our sync will be too slow, so we need to filter again.

There is no need to process accounts that haven’t been changed recently. We simply checked the Modified attribute in active directory and skipped these.

if ((get-date $modified) -ge ($(get-date).AddDays(-1.5))) {
    ...
}

We also needed a method to detect deleted accounts. Here we simply got all users in AD LDS and compared it with the users in AD DS. Any extra users were removed.

Compare-Object $PhoneBookUsers.Name $ADUserNames | Where-Object { $_.SideIndicator -eq "<=" } | ForEach-Object {
    $id="cn=$($_.InputObject),$destou"
    Remove-ADUser -Identity $id -Server $destserver -Credential $cred -Partition $destpartition -Confirm:$false
}

Below is the entire script, but as I wrote, it is a quick-and-dirty solution just to get started.

$destserver = "10.10.10.5"
$destpartition = "dc=cloud,dc=net"
$destou = "ou=PhoneBook,dc=cloud,dc=net"
$sourceou = "ou=MyBusiness,dc=contoso,dc=com"

$cred = Get-Credential
$i = 0

Import-Module ActiveDirectory

# Define users to process

    Write-Host "Collecting user information..."

    $ADUsers = Get-ADGroupMember -Identity "grp_ADSyncUsers" -Recursive | Get-ADUser -Properties `
            SamAccountName,GivenName,Surname,DisplayName,Title,Office,Department,Company,EmailAddress,Mobile,OfficePhone,Modified,Enabled | `
            Where-Object { $_.Enabled -eq $true -and $_.DistinguishedName -like "*$sourceou" }

    Write-Host "$($ADUsers.Count) user(s) found in Active Directory."

# Create/update users

    $ADUsers | ForEach-Object {

        $sam = $_.Name
        $givenname = $_.GivenName
        $surname = $_.Surname
        $displayname = $_.DisplayName
        $email = $_.EmailAddress
        $department = $_.Department
        $office = $_.Office
        $title = $_.Title
        $company = $_.Company
        $tele = $_.OfficePhone
        $mobil = $_.Mobile
        $modified = $_.Modified

        if ((get-date $modified) -ge ($(get-date).AddDays(-1.5))) {
            # Process user accounts modified the last 36 hours

            $i++;

            try {
                # Create new account in AD LDS
                New-ADUser -SamAccountName $sam -Name $sam -DisplayName $displayname -GivenName $givenname `
                    -SurName $surname -EmailAddress $email -Title $title -Office $office -Department $department `
                    -Company $company -OfficePhone $tele -MobilePhone $mobil `
                    -Enabled $false -Path $destou –Type iNetOrgPerson `
                    -Server $destserver `
                    -Credential $cred

                Write-Host "Creating user $sam"

            } catch [System.Exception] {
                switch($_.Exception.GetType().FullName) {
                    'Microsoft.ActiveDirectory.Management.ADException' {
                        # User already exists. Update existing account
                        Set-ADUser -Identity "cn=$sam,$destou" -DisplayName $displayname -GivenName $givenname -SurName $surname `
                            -EmailAddress $email -Title $title -Office $office -Department $department `
                            -Company $company -OfficePhone $tele -MobilePhone $mobil `
                            -Server $destserver `
                            -Credential $cred `
                            -Partition $destpartition
                        Write-Host "Updating user $sam"
                    }
                }
            }
        }
    }

# Remove deleted accounts

Write-Host "$i user(s) processed."
Write-Host "Searching for users to delete..."
$i=0

    $PhoneBookUsers = Get-ADUser -Server $destserver -SearchBase $destou -Filter * -Credential $cred | Select -Property Name
    $ADUserNames += $ADUsers.Name

    Compare-Object $PhoneBookUsers.Name $ADUserNames | Where-Object { $_.SideIndicator -eq "<=" } | ForEach-Object {
        $id="cn=$($_.InputObject),$destou"
        Remove-ADUser -Identity $id -Server $destserver -Credential $cred -Partition $destpartition -Confirm:$false
        Write-Host "Deleting user $($_.InputObject)"
        $i++
    }

Write-Host "$i user(s) deleted."
Write-Host "Done!"

/ Andreas

Advertisement

8 thoughts on “Synchronizing users between two AD Domains without trust

  1. Roger

    Hi Andreas,
    the script syncronize username and password?

    Can i use it to import user in another domain?
    Best Regards

    1. Andreas Lindahl Post author

      Hi. This script is perfect for importing users to another domain, but if you need password syncronization this is not the way to go. Then I suggest using FIM instead.

      1. Roger

        Thanks,
        but i need a solution that have zero o low cost, because FIM is more expensive.
        You know other software, olso open sorce, that done this kind of syncronization?

        Best Regards

      2. Andreas Lindahl Post author

        Well, synchronizing passwords is not a simple task. You probably have to look into third party tools, I don’t have any knowledge of open source tools that will provide the functionality you are looking for.

  2. Roger

    Thanks,
    you have any idea of costs of FIM?
    The licensing is per user?
    Best Regards

    1. Andreas Lindahl Post author

      There are too many options to give a short answer, I suggest that you contact your local Microsoft reseller for consultation.

  3. Leo

    Andreas, I’m new to scripting, but would this be a task you would create? And would this go on the DMZ server?

    1. Andreas Lindahl Post author

      Without using a dedicated sync server the firewall has to allow LDAP communication between Active Directory and DMZ. We implemented this solution to avoid that.

Comments are closed.