{"id":1364,"date":"2011-03-30T20:02:26","date_gmt":"2011-03-30T20:02:26","guid":{"rendered":"https:\/\/www.wapshere.com\/missmiis\/?page_id=1364"},"modified":"2011-04-23T13:56:32","modified_gmt":"2011-04-23T13:56:32","slug":"galsync-v2","status":"publish","type":"page","link":"https:\/\/www.wapshere.com\/missmiis\/galsync-v2","title":{"rendered":"GALSYNC v2"},"content":{"rendered":"<pre>### --- GALSYNC.PS1 ---\r\n#\r\n#  Written by Carol Wapshere\r\n#\r\n#  Manages contacts in two domains based on mail-enabled users in the other domain.\r\n#\t- Contacts are created for new users.\r\n#\t- Contacts are deleted if the source user no longer meets the filter requirements.\r\n#\t- Contacts are updated with changed information.\r\n#\r\n#  NOTES:\r\n#   - Requires RSAT roles and features installed. Ref http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2010\/01\/25\/hey-scripting-guy-january-25-2010.aspx\r\n#\t- Attribute deletions are not replicated - only attribute adds and changes.\r\n#   - A user account is needed in each domain with permission to create contacts.\r\n#\t- The passwords for these user accounts must be stored in secure files using the command:\r\n#\t\tread-host -assecurestring | convertfrom-securestring | out-file C:\\scripts\\filename.txt\r\n#\r\n#  EXCHANGE 2007:\r\n#   - The account running the script needs Recipient Administrator in the target forest.\r\n#   - The Exchange management tools must be installed on the computer where the script runs.\r\n#   - Depending on trust relationships, you may need to run the script seperately in each forest where contacts are to be created.\r\n#\r\n#  EXCHANGE 2010:\r\n#   - Some changes may be required to enable access to Exchange remote powershell:\r\n#     - Add the script account to the Recipient Management Role Group\r\n#     - Give the script account permission to use remote powershell:\r\n#           set-user -identity \u00e2\u20ac\u0153GALSYNC\u00e2\u20ac\u009d -RemotePowerShellEnabled $True\r\n#     - Enable \"Windows Authentication\" on the Powershell virtual directory in IIS on the CAS servers.\r\n#\r\n\r\n### --- GLOBAL DEFINITIONS ---\r\n\r\n$DOMAIN_1 = \"mydomain.local\"\r\n$DOMAIN_2 = \"myotherdomain.com\"\r\n\r\n$OU_CONTACTS_1 = \"OU=Domain2,OU=Contacts,DC=mydomain,DC=local\"\r\n$OU_CONTACTS_2 = \"OU=Domain1,OU=Contacts,DC=myotherdomain,DC=com\"\r\n\r\n$USER_1 = \"galsync@mydomain.local\"\r\n$USER_2 = \"galsync@myotherdomain.com\"\r\n\r\n$PWFILE_1 = \"C:\\scripts\\dom1cred.txt\"\r\n$PWFILE_2 = \"C:\\scripts\\dom2cred.txt\"\r\n\r\n# Exchange 2010 URIs if applicable\r\n$URI_1 = \"http:\/\/cas.mydomain.local\/powershell\"\r\n$URI_2 = \"http:\/\/cas.myotherdomain.com\/powershell\"\r\n\r\n## The following list of attributes will be copied from User to Contact\r\n$arrAttribs = 'displayName','company','givenName','mobile','postalAddress','postalCode','sn','st','streetAddress','telephoneNumber','title' ,'mail','c','co','l','facsimileTelephoneNumber','physicalDeliveryOfficeName'\r\n\r\n## The following filter is used by Get-ADObject to decide which users will have contacts.\r\n$strSelectUsers = 'ObjectClass -eq \"user\" -and homeMDB -like \"*\" -and -not userAccountControl -bor 2 -and -not msExchHideFromAddressLists -eq $true -and -not displayName -eq \"Administrator\"'\r\n\r\n### --- FUNCTION TO ADD, DELETE AND MODIFY CONTACTS IN TARGET DOMAIN BASED ON SOURCE USERS ---\r\n\r\nfunction SyncContacts\r\n{\r\n  PARAM($sourceDomain, $sourceUser, $sourcePWFile, $targetDomain, $targetUser, $targetPWFile, $targetOU, $targetExch, $targetURI)\r\n  END\r\n    {\r\n\t$colUsers = @()\r\n\t$colContacts = @()\r\n\t$colAddContact = @()\r\n\t$colDelContact = @()\r\n\t$colUpdContact = @()\r\n\r\n\t$arrUserMail = @()\r\n\t$arrContactMail = @()\r\n\r\n\t$objSourceDC = Get-ADDomainController -Discover -DomainName $sourceDomain\r\n\t$objTargetDC = Get-ADDomainController -Discover -DomainName $targetDomain \r\n\r\n\t$sourceDC = [string]$objSourceDC.HostName\r\n\t$targetDC = [string]$objTargetDC.HostName\r\n\r\n\twrite-host \"Enumerating\" $sourceDomain \"objects using DC\" $sourceDC\r\n\r\n\t### ENUMERATE USERS\r\n\r\n\t$password = get-content $sourcePWFile | convertto-securestring\r\n\t$sourceCred =  New-Object -Typename System.Management.Automation.PSCredential -Argumentlist $sourceUser,$password\r\n\r\n\t$colUsers = Get-ADObject -Filter $strSelectUsers -Properties * -Server $sourceDC -Credential $sourceCred\r\n\r\n\tif ($colUsers.Count -eq 0)\r\n    {\r\n        write-host \"No users found in source domain!\"\r\n        break\r\n    }\r\n\r\n\tforeach ($user in $colUsers)\r\n\t{\r\n\t\t$arrUserMail += $user.mail\r\n\t}\r\n\r\n\t### ENUMERATE CONTACTS\r\n\r\n\t$password = get-content $targetPWFile | convertto-securestring\r\n\t$targetCred =  New-Object -Typename System.Management.Automation.PSCredential -Argumentlist $targetUser,$password\r\n\r\n\t$colContacts = Get-ADObject -Filter 'objectClass -eq \"contact\"' -Server $targetDC -SearchBase $targetOU -Credential $targetCred -Properties targetAddress\r\n\r\n\tforeach ($contact in $colContacts)\r\n\t{\r\n\t\t$strAddress = $contact.targetAddress -replace \"SMTP:\",\"\"\r\n\t\t$arrContactMail += $strAddress\r\n\t}\r\n\r\n\t### FIND CONTACTS TO ADD AND UPDATE\r\n\r\n\tforeach ($user in $colUsers)\r\n\t{\r\n\t\tif ($arrContactMail -contains $user.mail)\r\n\t\t{\r\n\t\t\twrite-host \"Contact found for \" $user.mail\r\n\t\t\t$colUpdContact += $user\r\n\t\t}\r\n\t\telse\r\n\t\t{\r\n\t\t\twrite-host \"No contact found for \" $user.mail\r\n\t\t\t$colAddContact += $user\r\n\t\t}\r\n\t}\r\n\r\n\t### FIND CONTACTS TO DELETE\r\n\r\n\tforeach ($address in $arrContactMail)\r\n\t{\r\n\t\tif ($arrUserMail -notcontains $address)\r\n\t\t{\r\n\t\t\t$colDelContact += $address\r\n\t\t\twrite-host \"Contact will be deleted for\" $address\r\n\t\t}\r\n\t}\r\n\r\n\twrite-host \"\"\r\n\twrite-host \"Updating\" $targetDomain \"using DC\" $targetDC\r\n\r\n\t### ADDS\r\n\r\n\tforeach ($user in $colAddContact)\r\n\t{\r\n\t\twrite-host \"ADDING contact for \" $user.mail\r\n\r\n \t\t$targetAddress = \"SMTP:\" + $user.mail\r\n\t\t$alias = \"c-\" + $user.mail.split(\"@\")[0]\r\n\r\n\t\t$hashAttribs = @{'targetAddress' = $targetAddress}\r\n\t        $hashAttribs.add(\"mailNickname\", $alias)\r\n\r\n\t\tforeach ($attrib in $arrAttribs)\r\n\t\t{\r\n\t\t\tif ($user.$attrib -ne $null) { $hashAttribs.add($attrib, $user.$attrib) }\r\n\t\t}\r\n\r\n\t\t# Create Contact Object\r\n\t\tNew-ADObject -name $user.displayName -type contact -Path $targetOU -Description $user.description -server $targetDC -credential $targetCred -OtherAttributes $hashAttribs\r\n\r\n\t\t# Exchange 2007\/2010 - Run update-recipient to ensure contact is Exchange-enabled\r\n\t\tswitch ($targetExch)\r\n\t\t{\r\n\t\t\t\"2007\"\r\n\t\t\t{\r\n\t\t\t\tif(@(get-pssnapin | where-object {$_.Name -eq \"Microsoft.Exchange.Management.PowerShell.Admin\"} ).count -eq 0) {add-pssnapin Microsoft.Exchange.Management.PowerShell.Admin}\r\n\t\t\t\tUpdate-Recipient -Identity $alias -DomainController $targetDC -Credential $targetCred\r\n\t\t\t}\r\n\t\t\t\"2010\"\r\n\t\t\t{\r\n\t\t\t\t$SO = New-PSSessionOption -SkipCACheck -SkipCNCheck \u00e2\u20ac\u201cSkipRevocationCheck \u00e2\u20ac\u201cProxyAccessType None\r\n\t\t\t\tif ($PSSession -eq $null) {$PSSession = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $targetURI -Credential $targetCred -SessionOption $SO}\r\n\t\t\t\tInvoke-Command -Session $PSSession -ScriptBlock{param ($alias,$targetDC) Update-Recipient -Identity $alias -DomainController $targetDC} -ArgumentList $alias,$targetDC\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\t### UPDATES\r\n\r\n\tforeach ($user in $colUpdContact)\r\n\t{\r\n\t\twrite-host \"VERIFYING contact for \" $user.mail\r\n\r\n \t\t$targetAddress = \"SMTP:\" + $user.mail\r\n\t\t$alias = \"c-\" + $user.mail.split(\"@\")[0]\r\n\r\n\t\t$strFilter = \"targetAddress -eq \"\"SMTP:\" + $user.mail + \"\"\"\"\r\n\t\t$colContacts = Get-ADObject -Filter $strFilter -searchbase $targetOU -server $targetDC -credential $targetCred -Properties *\r\n\t\tforeach ($contact in $colContacts)\r\n\t\t{\r\n\t\t\t$hashAttribs = @{}\r\n\t\t\tforeach ($attrib in $arrAttribs)\r\n\t\t\t{\r\n\t\t\t\tif ($user.$attrib -ne $null -and $user.$attrib -ne $contact.$attrib)\r\n\t\t\t\t{\r\n\t\t\t\t\twrite-host \"\tChanging \" $attrib\r\n\t\t\t\t\twrite-host \"\t\tBefore: \" $contact.$attrib\r\n\t\t\t\t\twrite-host \"\t\tAfter: \" $user.$attrib\r\n\t\t\t\t\t$hashAttribs.add($attrib, $user.$attrib)\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t\tif ($hashAttribs.Count -gt 0)\r\n\t\t\t{\r\n\t\t\t\tSet-ADObject -identity $contact -server $targetDC -credential $targetCred -Replace $hashAttribs\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t}\r\n\r\n\t### DELETES\r\n\r\n\tforeach ($contact in $colDelContact)\r\n\t{\r\n\t\twrite-host \"DELETING contact for \" $contact\r\n\t\t$strFilter = \"targetAddress -eq \"\"SMTP:\" + $contact + \"\"\"\"\r\n\t\tGet-ADObject -Filter $strFilter -searchbase $targetOU -server $targetDC -credential $targetCred | Remove-ADObject -server $targetDC -credential $targetCred -Confirm:$false\r\n\t}\r\n\r\n\t}\r\n}\r\n\r\n### --- MAIN ---\r\n\r\nStart-Transcript C:\\scripts\\galsync\\galsync.log\r\n\r\nif(@(get-module | where-object {$_.Name -eq \"ActiveDirectory\"} ).count -eq 0) {import-module ActiveDirectory}\r\n\r\n# EXAMPLE - Exchange 2010 target forest\r\nwrite-host \"Domain1 Users --&gt; Domain2 Contacts\"\r\nSyncContacts -sourceDomain $DOMAIN_1 -sourceUser $USER_1 -sourcePWFile $PWFILE_1 `\r\n             -targetDomain $DOMAIN_2 -targetUser $USER_2 -targetPWFile $PWFILE_2 `\r\n\t\t\t -targetOU $OU_CONTACTS_2 -targetExch \"2010\" -targetURI $URI_2\r\n\r\n# EXAMPLE - Exchange 2007 target forest\r\nwrite-host \"Domain2 Users --&gt; Domain1 Contacts\"\r\nSyncContacts -sourceDomain $DOMAIN_2 -sourceUser $USER_2 -sourcePWFile $PWFILE_2 `\r\n             -targetDomain $DOMAIN_1 -targetUser $USER_1 -targetPWFile $PWFILE_1 `\r\n\t\t\t -targetOU $OU_CONTACTS_1 -targetExch \"2007\"\r\n\r\n# EXAMPLE - Exchange 2003 target forest\r\nwrite-host \"Domain2 Users --&gt; Domain1 Contacts\"\r\nSyncContacts -sourceDomain $DOMAIN_2 -sourceUser $USER_2 -sourcePWFile $PWFILE_2 `\r\n             -targetDomain $DOMAIN_1 -targetUser $USER_1 -targetPWFile $PWFILE_1 `\r\n\t\t\t -targetOU $OU_CONTACTS_1             \r\n\r\nStop-Transcript<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>### &#8212; GALSYNC.PS1 &#8212; # # Written by Carol Wapshere # # Manages contacts in two domains based on mail-enabled users in the other domain. # &#8211; Contacts are created for new users. # &#8211; Contacts are deleted if the source user no longer meets the filter requirements. # &#8211; Contacts are updated with changed&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"open","ping_status":"closed","template":"","meta":{"jetpack_post_was_ever_published":false,"footnotes":""},"class_list":["post-1364","page","type-page","status-publish","hentry"],"jetpack_shortlink":"https:\/\/wp.me\/Pkp1o-m0","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/pages\/1364","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/comments?post=1364"}],"version-history":[{"count":3,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/pages\/1364\/revisions"}],"predecessor-version":[{"id":1385,"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/pages\/1364\/revisions\/1385"}],"wp:attachment":[{"href":"https:\/\/www.wapshere.com\/missmiis\/wp-json\/wp\/v2\/media?parent=1364"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}