четверг, 17 мая 2012 г.

Синхронизация учетных записей\контактов в разных доменах\лесах

Итак ситуация - у нас есть два леса, между которыми установлены доверительные отношения (точнее можно подключиться к обоим доменам, но мне трудно представить топологию с VPN и без доверия). В обоих есть Exchange и Lync.

Проблема - наполнить адресные книги Exchange и Lync, заодно синхронизировать некоторые атрибуты. FIM покупать дорого, о других средствах синхронизации я не знаю (lol)

Для синхронизации в обоих доменах запускаем скрипт. Изначально скрипт использовал только командлеты Exchange, но после того, как я прочитал и испытал на себе, что Lync добавляет контакты с номерами таким образом, что на них нельзя написать (только позвонить), скрипт был доработан для синхронизации параметра msRTCSIP-PrimaryUserAddress. Скрипт создает контакты, заполняет атрибуты. При обновлении оригинальной учетной записи (проверка осуществляется по дате модификации контакта и учетной записи) поля синхронизируются повторно.

Для контроля актуальности записей используется атрибут customattribute1\extensionattribute1, который снимается с контакта при первом проходе, и устанавливается при нахождении контакта в удаленном AD. Минус - если каким-то образом скрипт не обновит контакт между синхронизациями, контакт останется неактуальным, плюс - меньше нагрузка на проверку актуальности контакта. Сама актуальность проверяется давности контакта\whenchanged

Для работы скрипта требуются права на OU в которой будут храниться контакты и права на чтения из донорской AD.

По не до конца понятной причине (в ранних версиях) при замене полной инициализации командлетов Exchange на импорт аддина (что происходт намного быстрее) контакты переставали обновляться и создаваться.


UPD: добавил удаление пустых полей перед set-adobject:

            $key_remove=@()
            foreach ($key in $info.keys) {if (!$info[$key]) {$key_remove+=$key} }
            foreach($key in $key_remove) {$info.remove($key)}

Код:

################################################
# Скачать с DC список пользователей, создать контакты
# для новых пользователей.
################################################

####################################
# vars
$extdc="dc01.remote"
$intdc="dc01.local"

$exattr="remote"

$ouoffices="OU=OFFICES,dc=remote"
$oucontacts="OU=SYNCONTACTS,dc=local"

$ouspecial="*DISCHARGE*","*OU=IT,OU=ACCOUNTS*","*OU=SPECIAL,OU=ACCOUNTS*"

$hidedays=3
$deletedays=31

function log($msg) {
  $date=get-date
  $data="[ "+$date+" ] "+ $msg
  echo $data >> C:\SheduledScripts\mailscripts\addrbook.log
  }

####################################
# ***         MAIN             *** #
####################################

####################################
# Excahnge connector
# Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010
####################################
# Excahnge connector
. 'C:\Program Files\Microsoft\Exchange Server\V14\bin\RemoteExchange.ps1'
Connect-ExchangeServer -auto
import-module activedirectory

log "Start..."
####################################
# flush attr
log "Flushing attributes"
Get-MailContact -resultsize unlimited -domaincontroller $intdc| ? {$_.customattribute1 -eq $exattr }  | set-mailcontact -CustomAttribute1 $null

####################################
log "Getting local contact list"
$contactlist = Get-adObject -Server $intdc -SearchBase $oucontacts -filter {objectclass -eq "contact"} -properties mail,whenchanged 
#form maillist for quick existance search
$emaillist=@{}
foreach($contact in $contactlist) {
    $emaillist[$contact.mail]=$contact.whenchanged
    }

#Get remote userlist
log "Getting userlist"
$extuserlist=Get-adUser -Server $extdc -SearchBase $ouoffices -filter * -properties mail,whenchanged ,"msRTCSIP-PrimaryUserAddress", givenname,sn,displayname, company,title,physicalDeliveryOfficeName,telephoneNumber,description
while (-not $extuserlist ) {
  log "Getting userlist failed. Retrying in 300s"
  start-sleep -s 300
  $extuserlist=Get-adUser -Server $extdc -SearchBase $ouoffices -filter * -properties mail,whenchanged ,"msRTCSIP-PrimaryUserAddress", givenname,sn,displayname, company,title,physicalDeliveryOfficeName,telephoneNumber,description
  }

Foreach ($account in $extuserlist) {
    ###########################
    #нет почты, пропускаем
    if(!$account.mail) {continue}
    ###########################
    # проверить на спец OU, из которых не синхронизируем
    $special=$fasle
    foreach($ou in $ouspecial) {
        if ($account.DistinguishedName -like $ou) {
            $special=$true
            }
        }
    if($special) {continue}
    
    #контакт уже заведен?
    if($emaillist[$account.mail]) {
        ##############################
        #контакт уже заведен, надо проверить, надо ли его обновить
        #сравниваем дату изменения контакта и оригинальной учетки в синхронизируемом домене
        if($emaillist[$account.mail] -lt $account.whenchanged) {
            #обновляем контакт
            $contact=Get-adObject -Server $intdc -SearchBase $oucontacts -filter {mail -eq $account.mail}
   #  -properties mail,whenchanged ,"msRTCSIP-PrimaryUserAddress", givenname,sn,displayname, company,title,physicalDeliveryOfficeName,telephoneNumber,description
            #$user=   Get-adUser   -Server $extdc -SearchBase $ouoffices  -filter {mail -eq $account.mail} -properties mail,whenchanged ,"msRTCSIP-PrimaryUserAddress", givenname,sn,displayname, company,title,physicalDeliveryOfficeName,telephoneNumber,description
            #$dn=[adsi]("LDAP://"+$contact.DistinguishedName)
            $info=@{}
            $info["msRTCSIP-PrimaryUserAddress"]=$account."msRTCSIP-PrimaryUserAddress"
            $info["givenname"]=                  $account.givenname
            $info["sn"]=                         $account.sn
            $info["displayname"]=                $account.displayname
            $info["description"]=                $account.description
            $info["company"]=                    $account.company
            $info["title"]=                      $account.title
            $info["physicalDeliveryOfficeName"]= $account.physicalDeliveryOfficeName
            $info["telephoneNumber"]=            $account.telephoneNumber
            $info["extensionAttribute1"]=        $exattr
            $key_remove=@()
            foreach ($key in $info.keys) {if (!$info[$key]) {$key_remove+=$key} }
            foreach($key in $key_remove) {$info.remove($key)}
            set-adobject ($contact.distinguishedName) -server $intdc -replace $info
            
            #$dn.CommitChanges()
            log("Mailcontact "+$account.mail+" updated")
            } else {
            ############################################
            #обновлять поля контакта не надо
            #проставляем контакту атрибут "обновляя" дату его модификации
            set-mailcontact ($account.mail) -CustomAttribute1 $exattr 
            }
        } else {
            ##############################
            # такого контакта еще не заведено - создаем
            
            #чистим старый контакт, если изменился email
            try {
                #remove-mailcontact $account.displayname -confirm:$false
            }
            catch {
                $error.clear()
            }
            #создаем новый контакт
            new-mailcontact -ExternalEmailAddress $account.mail -Name $account.displayname -DisplayName $account.displayname -OrganizationalUnit $oucontacts -domaincontroller $intdc
            #установить значения
            #обновляем контакт
            $contact=Get-adObject -Server $intdc -SearchBase $oucontacts -filter {mail -eq $account.mail}  -properties mail,whenchanged ,"msRTCSIP-PrimaryUserAddress", givenname,sn,displayname, company,title,physicalDeliveryOfficeName,telephoneNumber,description
            #$user=   Get-adUser   -Server $extdc -SearchBase $ouoffices  -filter {mail -eq $account.mail} -properties mail,whenchanged ,"msRTCSIP-PrimaryUserAddress", givenname,sn,displayname, company,title,physicalDeliveryOfficeName,telephoneNumber,description
            #$dn=[adsi]("LDAP://"+$contact.DistinguishedName)
            $info=@{}
            $info["msRTCSIP-PrimaryUserAddress"]=$account."msRTCSIP-PrimaryUserAddress"
            $info["givenname"]=                  $account.givenname
            $info["sn"]=                         $account.sn
            $info["displayname"]=                $account.displayname
            $info["description"]=                $account.description
            $info["company"]=                    $account.company
            $info["title"]=                      $account.title
            $info["physicalDeliveryOfficeName"]= $account.physicalDeliveryOfficeName
            $info["telephoneNumber"]=            $account.telephoneNumber
            $info["extensionAttribute1"]=        $exattr 
            $key_remove=@()
            foreach ($key in $info.keys) {if (!$info[$key]) {$key_remove+=$key} }
            foreach($key in $key_remove) {$info.remove($key)}

            set-adobject ($contact.distinguishedName) -server $intdc -replace $info
                
            log("Mailcontact "+$account.mail+" created")
        }
            
    }

$hidedate=(get-date).adddays(-$hidedays)
$deletedate=(get-date).adddays(-$deletedays)

#проходимся по всем контактам и удаляем\скрываем те, которые не обновлялись
foreach($contact in $contactlist) {
  if($contact.WhenChanged -le $hidedate) {
    set-mailcontact $contact.mail -HiddenFromAddressListsEnabled $true
    log ("Address "+$contact.mail+" hidden.")
    }
  if($contact.WhenChanged -le $deletedate) {
    remove-mailcontact $contact.mail -confirm:$false
    log ("Address "+$contact.mail+" removed")
    }

  }

#log "Updating Address Books..."
Get-GlobalAddressList|Update-GlobalAddressList
Get-OfflineAddressBook|Update-OfflineAddressBook

log "...Finish"

Комментариев нет:

Отправить комментарий