GALSYNC.ps1 for Distribution Lists

Here’s a version sent to me by a reader which will sync Distribution Lists to contacts in the other forest. Note the formatting may have got a bit messed up in the copy from email. And thanks to Rick!

Hey there,

Just in case it’s of use to you, I’ve done a quick butcher of your code so that it will create contacts in one forest for distribution lists in another. I haven’t filtered against mail enabled distro lists, and I haven’t adjusted the attributes
that it attempts to copy, so while errors will appear, it should get through the process successfully. I’ve highlighted the major changes in red.

—————————————————————————————————

### — GALSYNC.PS1 —

# Written by Carol Wapshere

# Manages contacts in two domains based on mail-enabled users in the other domain.

# – Contacts are created for new users.

# – Contacts are deleted if the source user no longer meets the filter requirements.

# – Contacts are updated with changed information.

# – Edited by Rick McQuinlan

# – – Adjusted the script to cater for distribution groups, rather than users.

#NOTES:

# – Requires RSAT roles and features installed. Ref http://blogs.technet.com/heyscriptingguy/archive/2010/01/25/hey-scripting-guy-january-25-2010.aspx

# – Attribute deletions are not replicated – only attribute adds and changes.

# – A user account is needed in each domain with permission to create contacts.

# – The passwords for these user accounts must be stored in secure files using the command:

# read-host -assecurestring | convertfrom-securestring | out-file C:\scripts\filename.txt

#

# EXCHANGE 2007:

# – The account running the script needs Recipient Administrator in the target forest.

# – The Exchange management tools must be installed on the computer where the script runs.

# – Depending on trust relationships, you may need to run the script seperately in each forest where contacts are to be created.

#

# EXCHANGE 2010:

# – Some changes may be required to enable access to Exchange remote powershell:

# – Add the script account to the Recipient Management Role Group

# – Give the script account permission to use remote powershell:

# set-user -identity “GALSYNC” -RemotePowerShellEnabled $True

# – Enable “Windows Authentication” on the Powershell virtual directory in IIS on the CAS servers.

#

### — GLOBAL DEFINITIONS —

$DOMAIN_1 = “mydomain.local”

$DOMAIN_2 = “myotherdomain.com”

$OU_CONTACTS_1 = “OU=Domain2,OU=Contacts,DC=mydomain,DC=local”

$OU_CONTACTS_2 = “OU=Domain1,OU=Contacts,DC=myotherdomain,DC=com”

$USER_1 = “galsync@mydomain.local”

$USER_2 = “galsync@myotherdomain.com”

$PWFILE_1 = “C:\scripts\dom1cred.txt”

$PWFILE_2 = “C:\scripts\dom2cred.txt”

## The following list of attributes will be copied from User to Contact

$arrAttribs = ‘displayName’,’company’,’givenName’,’mobile’,’postalAddress’,’postalCode’,’sn’,’st’,’streetAddress’,’telephoneNumber’,’title’ ,’mail’,’c’,’co’,’l’,’facsimileTelephoneNumber’,’physicalDeliveryOfficeName’

## The following filter is used by Get-ADGroup to decide which groups will have contacts.

$strSelectGroups = ‘GroupCategory -eq “distribution”‘

### — FUNCTION TO ADD, DELETE AND MODIFY CONTACTS IN TARGET DOMAIN BASED ON SOURCE USERS —

function SyncContacts

{

PARAM($sourceDomain, $sourceUser, $sourcePWFile, $targetDomain, $targetUser, $targetPWFile, $targetOU, $targetExch, $targetURI)

END

{

$colUsers = @()

$colContacts = @()

$colAddContact = @()

$colDelContact = @()

$colUpdContact = @()

$arrUserMail = @()

$arrContactMail = @()

$objSourceDC = Get-ADDomainController -Discover -DomainName $sourceDomain

$objTargetDC = Get-ADDomainController -Discover -DomainName $targetDomain

$sourceDC = [string]$objSourceDC.HostName

$targetDC = [string]$objTargetDC.HostName


write-host “Enumerating” $sourceDomain “objects using DC” $sourceDC

### ENUMERATE USERS

$password =
get-content $sourcePWFile | convertto-securestring

$sourceCred =
New-Object -Typename System.Management.Automation.PSCredential -Argumentlist $sourceUser,$password

$colUsers = Get-ADgroup -Filter $strSelectGroups -Properties * -Server $sourceDC -Credential $sourceCred

if ($colUsers.Count -eq 0)

{


write-host “No groups found in source domain!”

break

}

foreach ($user in $colUsers)

{

$arrUserMail += $user..mail

}

### ENUMERATE CONTACTS

$password =
get-content $targetPWFile | convertto-securestring

$targetCred =
New-Object -Typename System.Management.Automation.PSCredential -Argumentlist $targetUser,$password

$colContacts = Get-ADObject -Filter ‘objectClass -eq “contact”‘ -Server $targetDC -SearchBase $targetOU -Credential $targetCred -Properties targetAddress

foreach ($contact in $colContacts)

{

$strAddress = $contact.targetAddress -replace “SMTP:”,””

$arrContactMail += $strAddress

}

### FIND CONTACTS TO ADD AND UPDATE

foreach ($user in $colUsers)

{

if ($arrContactMail -contains $user.mail)

{


write-host “Contact found for ” $user.mail

$colUpdContact += $user

}

else

{


write-host “No contact found for ” $user.mail

$colAddContact += $user

}

}

### FIND CONTACTS TO DELETE

foreach ($address in $arrContactMail)

{

if ($arrUserMail -notcontains $address)

{

$colDelContact += $address


write-host “Contact will be deleted for” $address

}

}


write-host “”


write-host “Updating” $targetDomain “using DC” $targetDC

### ADDS

foreach ($user in $colAddContact)

{


write-host “ADDING contact for ” $user.mail

$targetAddress = “SMTP:” + $user.mail

$alias = “c-” + $user.mail.split(“@”)[0]

$hashAttribs = @{‘targetAddress’ = $targetAddress}

$hashAttribs.add(“mailNickname”, $alias)

foreach ($attrib in $arrAttribs)

{

if ($user.$attrib -ne $null) { $hashAttribs.add($attrib, $user.$attrib) }

}

# Create Contact Object

New-ADObject -name $user.displayName -type contact -Path $targetOU -Description $user.description -server $targetDC -credential $targetCred -OtherAttributes
$hashAttribs

# Exchange 2007/2010 – Run update-recipient to ensure contact is Exchange-enabled

switch ($targetExch)

{

“2007”

{

if(@(get-pssnapin |
where-object {$_.Name -eq “Microsoft.Exchange.Management.PowerShell.Admin”} ).count -eq 0) {add-pssnapin Microsoft.Exchange.Management.PowerShell.Admin}

Update-Recipient -Identity $alias -DomainController $targetDC -Credential $targetCred

}

“2010”

{

$SO =
New-PSSessionOption -SkipCACheck -SkipCNCheck –SkipRevocationCheck
–ProxyAccessType None

if ($PSSession -eq $null) {$PSSession =
New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $targetURI
-Credential $targetCred -SessionOption $SO}


Invoke-Command -Session $PSSession -ScriptBlock{param ($alias,$targetDC) Update-Recipient -Identity $alias -DomainController $targetDC}
-ArgumentList $alias,$targetDC

}

}

}

### UPDATES

foreach ($user in $colUpdContact)

{


write-host “VERIFYING contact for ” $user.mail

$targetAddress = “SMTP:” + $user.mail

$alias = “c-” + $user.mail.split(“@”)[0]

$strFilter = “targetAddress -eq “”SMTP:” + $user.mail + “”””

$colContacts = Get-ADObject -Filter $strFilter -searchbase $targetOU -server $targetDC -credential $targetCred -Properties *

foreach ($contact in $colContacts)

{

$hashAttribs = @{}

foreach ($attrib in $arrAttribs)

{

if ($user.$attrib -ne $null -and $user.$attrib -ne $contact.$attrib)

{


write-host ” Changing ” $attrib


write-host ” Before: ” $contact.$attrib


write-host ” After: ” $user.$attrib

$hashAttribs.add($attrib, $user.$attrib)

}

}

if ($hashAttribs.Count -gt 0)

{

Set-ADObject -identity $contact -server $targetDC -credential $targetCred -Replace $hashAttribs

}

}

}

### DELETES

foreach ($contact in $colDelContact)

{


write-host “DELETING contact for ” $contact

$strFilter = “targetAddress -eq “”SMTP:” + $contact + “”””

Get-ADObject -Filter $strFilter -searchbase $targetOU -server $targetDC -credential $targetCred | Remove-ADObject -server $targetDC -credential $targetCred
-Confirm:$false

}

}

}

### — MAIN —

Start-Transcript C:\scripts\galsync\galsync.log

if(@(get-module |
where-object {$_.Name -eq “ActiveDirectory”} ).count -eq 0) {import-module ActiveDirectory}

# EXAMPLE – Exchange 2010 target forest

write-host “Domain1 Groups –> Domain2 Contacts”

SyncContacts -sourceDomain $DOMAIN_1 -sourceUser $USER_1 -sourcePWFile $PWFILE_1
`

-targetDomain $DOMAIN_2 -targetUser $USER_2 -targetPWFile $PWFILE_2
`

-targetOU $OU_CONTACTS_2 -targetExch “2010” -targetURI $URI_2

# EXAMPLE – Exchange 2007 target forest

write-host “Domain2 Groups –> Domain1 Contacts”

SyncContacts -sourceDomain $DOMAIN_2 -sourceUser $USER_2 -sourcePWFile $PWFILE_2
`

-targetDomain $DOMAIN_1 -targetUser $USER_1 -targetPWFile $PWFILE_1
`

-targetOU $OU_CONTACTS_1 -targetExch “2007”

# EXAMPLE – Exchange 2003 target forest

write-host “Domain2 Groups –> Domain1 Contacts”

SyncContacts -sourceDomain $DOMAIN_2 -sourceUser $USER_2 -sourcePWFile $PWFILE_2
`

-targetDomain $DOMAIN_1 -targetUser $USER_1 -targetPWFile $PWFILE_1
`

-targetOU $OU_CONTACTS_1

Stop-Transcript

—————————————————————————–


Leave a Reply

Your email address will not be published. Required fields are marked *


*