### --- 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.
#
# 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
#
### --- 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-ADObject to decide which users will have contacts.
$strSelectUsers = 'ObjectClass -eq "user" -and homeMDB -like "*" -and -not userAccountControl -bor 2 -and -not msExchHideFromAddressLists -eq $true -and -not displayName -eq "Administrator"'
### --- FUNCTION TO ADD, DELETE AND MODIFY CONTACTS IN TARGET DOMAIN BASED ON SOURCE USERS ---
function SyncContacts
{
PARAM($sourceDC, $sourceUser, $sourcePWFile, $targetDC, $targetUser, $targetPWFile, $targetOU)
END
{
$colUsers = @()
$colContacts = @()
$colAddContact = @()
$colDelContact = @()
$colUpdContact = @()
$arrUserMail = @()
$arrContactMail = @()
write-host "Enumerating..."
### ENUMERATE USERS
$password = get-content $sourcePWFile | convertto-securestring
$sourceCred = New-Object -Typename System.Management.Automation.PSCredential -Argumentlist $sourceUser,$password
$colUsers = Get-ADObject -Filter $strSelectUsers -Properties * -Server $sourceDC -Credential $sourceCred
if ($colUsers.Count -eq 0)
{
write-host "No users 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"' -searchbase $targetOU -Server $targetDC -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 ...."
### 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) }
}
New-ADObject -name $user.displayName -type contact -Path $targetOU -Description $user.description -server $targetDC -credential $targetCred -OtherAttributes $hashAttribs
}
### UPDATES
foreach ($user in $colUpdContact)
{
write-host "VERIFYING contact for " $user.mail
$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 galsync.log
if(@(get-module | where-object {$_.Name -eq "ActiveDirectory"} ).count -eq 0) {import-module ActiveDirectory}
write-host "DOMAIN1 Users --> DOMAIN2 Contacts"
SyncContacts -sourceDC $DOMAIN_1 -sourceUser $USER_1 -sourcePWFile $PWFILE_1 -targetDC $DOMAIN_2 -targetUser $USER_2 -targetPWFile $PWFILE_2 -targetOU $OU_CONTACTS_2
write-host ""
write-host "DOMAIN2 Users --> DOMAIN1 Contacts"
SyncContacts -sourceDC $DOMAIN_2 -sourceUser $USER_2 -sourcePWFile $PWFILE_2 -targetDC $DOMAIN_1 -targetUser $USER_1 -targetPWFile $PWFILE_1 -targetOU $OU_CONTACTS_1
Stop-Transcript
About this blog
This blog started out being about MIIS, but has extended to whatever I happen to be working on - particularly when I've had to struggle through incomplete documentation, blog and forum trawls, and good old trial and error to work through a problem. The posts reflect my own homegrown approach to problems I encountered and are entirely based on my own experiences - I will try to avoid theorising!Copyright Notice
All text in this blog is original and the copyright is owned by the author. You are welcome to use the code (without warranty) but please do not copy the articles without asking first.My social media policy
+ I will only accept facebook friend requests from people I know in person.
+ I will only accept linkedin requests from people I have worked with or had at least a few email exchanges with (remind me on the request if this is the case).
+ You are of course welcome to follow me on twitter (@miss_miis).RSS
AD ADAM ADFS Best Practice BPOS Cloud Conferences Email Template Excel Exchange 2003 Exchange 2007 Exchange 2010 FIM 2010 FIM 2010 R2 FIM Sync Service Groups ILM ILM "2" ILM 2007 Logs Lotus Notes MIIS 2003 MiisApp MPR newbie Novell Office 365 OpenLDAP Password Sync Performance Philosophising powershell Quest RCDC Reporting SAP Scripting Sets Sharepoint SQL Uncategorized Unify VB.NET VBScript Windows Server 2003 Windows Server 2008 Workflow
Popular Posts
- A GALSync powershell script
- Adding Exchange 2007 mailboxes to existing user accounts
- Exchange 2007 Cross-Forest Migration
- FIM Walkthroughs – Create the FIM MA
- FIM Walkthroughs – Planning and Installation
- Importing groups from AD to the FIM Portal using classic flow rules
- Password Sync from AD to BPOS
- Powershell Custom WF Activity
- Running Remote Powershell scripts from VB.NET
Pages
Archives
-
Blogroll
- Kim Cameron's Indentity Weblog
Close preview
Loading... - Jackson's Identity Management & Active Directory Reality Tour Travelblog
Close preview
Loading... - Tomek's DS World
Close preview
Loading... - IT Mum
Close preview
Loading... - 1dent1ty cHa0s
Close preview
Loading... - Clint Boessen
Close preview
Loading... - TechNet Flash Feed
Close preview
Loading... - You Had Me At EHLO
Close preview
Loading... - PuttyQ
Close preview
Loading... - Jorge 's Quest For Knowledge!
Close preview
Loading... - FIM / ILM Best Practices
Close preview
Loading... - IdM Crisis
Close preview
Loading... - ADdict
Close preview
Loading... - Anthony Ho
Close preview
Loading... - CShark
Close preview
Loading... - Darryl Russi's Blog
Close preview
Loading... - Gil's Blog
Close preview
Loading... - Identity Management Extensibility
Close preview
Loading... - Identity Underground
Close preview
Loading... - IdM for Real
Close preview
Loading... - Identity Trench
Close preview
Loading... - FIM 2010 Technet Wiki Articles
Close preview
Loading... - Identity Minded
Close preview
Loading...
- Kim Cameron's Indentity Weblog
