воскресенье, 28 апреля 2013 г.

Миграция почтовых объектов в другой лес

Очередная бизнес задача: есть два леса с настроенным доверием, в каждом из них настроен Exchange. Необходимо произвести миграцию объектов из одного леса в другой.

Есть достаточно много статей, но в основном они описывают подготовку к миграции только почтовых ящиков, возможно я не прав и ищу не по тем параметрам, но всё же. Я постараюсь описать и некоторые другие моменты, с которыми я столкнулся при планировании , тестировании и проведении самой миграции.

Сама статья и алгоритм достаточно сырые, так как всё делалось в относительной спешке и из-за разделения обязанностей по миграции на большое число тестовых кейсов при миграции не приходилось рассчитывать.

План миграции будет таков:

  • Добавление в целевом лесу internal relay почтовых доменов, настройка send коннекторов, смотрящих на исходный лес, настройка политик адресов.
  • Произведение аналогичных настроек в исходном лесу.
  • Удаление контактов в исходном и целевом лесах.
  • Миграция пользователей\групп\компьютеров из исходного леса при помощи ADMT. В качестве бонуса после миграции компьютера Outlook перенастраивается сам и использует старый ost, yay!
  • Подготовка почтовых ящиков к перемещению, "миграция" групп, контактов и mailusers.
  • Перемещение ящиков.
  • Изменение типов домена в целевом лесу на authorative, удаление send коннекторов.
  • Разрыв доверительных отношений и траблшутинг.

На всякий случай предупреждаю, что после миграции надо предупредить пользователей почистить список автоподстановки и автоматических адресов в Outlook, чтобы не было проблем с отправкой на несуществующие адреса. Возможно я зря сначала делаю mailuser, а потом prepare-moverequest т.к. prepare-moverequest по идее должен переносить legacyexchangedn и все proxyaddresses сам.

Миграция групп и контактов производится достаточно просто: включаем группы в целевом лесу после миграции и копируем аттрибуты из исходного леса. Для справки: у меня в customattribute1 хранится параметр\домен для политики адресов

$remotedc="dc.forest.remote"
$localdc="dc.forest.local"
$groups=Get-DistributionGroup -DomainController $remotedc | select Name,displayname,alias,customattribute1,RequireSenderAuthenticationEnabled,HiddenFromAddressListsEnabled,emailaddresses

foreach ($gr in $groups) {
    if (!$gr.customattribute1){
        $gr.customattribute1="remote.ru"
    }
    $attr=@{}
    $attr['extensionAttribute1']=$gr.customattribute1
    set-adgroup $gr.name -add $attr

    Enable-DistributionGroup $gr.name -displayname $gr.displayname -alias $gr.alias
    
    #мигрируем альтернативные адреса
    $current=(get-distributiongroup $gr.displayname).EmailAddresses
    foreach ($addr in $gr.emailaddresses) {
        if (!$current.contains($addr.ProxyAddressString)) {
            $current+=$addr.ProxyAddressString
        }
    }
    set-distributiongroup $gr.name -displayname $gr.displayname -alias $gr.alias -customattribute1 $gr.customattribute1 -RequireSenderAuthenticationEnabled $gr.RequireSenderAuthenticationEnabled -HiddenFromAddressListsEnabled $gr.HiddenFromAddressListsEnabled -EmailAddresses $current -EmailAddressPolicyEnabled $false
}

Побочным эффектом этого безобразия является добавление адреса, присваиваемого политикой адресов по умолчанию. Так как мне это не мешало, я банально забил. Аналогично необходимо поступить с mailuser'ами и контактами. Для них я код не писал, так как их не надо было мигрировать.

А теперь самая интересная часть: миграция почтовых ящиков. Данный момент стоит разделить на несколько этапов, особенно если в лесу несколько контроллеров. Я честно забил на миграцию grantsendonbehalfto и не проверял миграцию этого аттрибута, sendas мигрируется как security разрешение через ADMT, а вот forward надо мигрировать вручную, так как после переезда ящика она показывает непонятно куда.

Этапы миграции:

  • Миграция учетной записи через ADMT
  • enable-mailuser в целевом лесу
  • Prepare-MoveRequest для переноса аттрибутов
  • Сохранение форвардов
  • New-MoveRequest для переноса содержимого ящика. Кстати автоответ\правила являются скрытыми объектами в почтовом ящике и переносятся без проблем.
  • Remve-MoveRequest для завершения перемещения ящика. Превращает пользователя в целевом лесу в почтовый ящик, а в исходном в mailuser

Код:

$remotedc="dc.forest.remote"
$localdc="dc.forest.local"

function PrepareMigrateMailbox($sam, $mail,$cred1,$cred2) {
    #$user is SAM in both forests
    #cred1 is local credential (target)
    #cred2 is remote credential (source)

    #нет адреса - пропускаем
    if(!$mail) {continue}
    #move mailbox
    $alias=$mail.split("@")[0]
    $attr=$mail.split("@")[1]
    enable-mailuser $sam -ExternalEmailAddress $mail -DomainController $localdc -Alias $alias
    start-sleep 10
    Set-MailUser $sam -CustomAttribute1 $attr -alias $alias
    #алиасы мигрируются?
    & 'C:\Program Files\Microsoft\Exchange Server\V14\Scripts\Prepare-MoveRequest.ps1' -Identity $mail -LocalForestDomainController $localdc -RemoteForestDomainController $remotedc -LocalForestCredential $cred1 -RemoteForestCredential $cred2 -UseLocalObject -OverWriteLocalObject
}

#при миграции переадресация сбивается, сохраним
function SaveForward () {
    $users=get-mailbox -DomainController $remotedc | select PrimarySmtpAddress, ForwardingAddress, DeliverToMailboxAndForward
    foreach ($u in $users) {
        if ($u.ForwardingAddress) {
            $u.ForwardingAddress=$u.ForwardingAddress.name
        }
    }
    $users | export-csv -path 'c:\scripts\csv\forward.csv'
}

#это надо запустить после миграции (вручную)
function LoadForward () {
    $users=import-csv -path 'c:\scripts\csv\forward.csv'
    foreach ($u in $users) {
        if($u.ForwardingAddress) {
            $mbx=get-mailbox $u.PrimarySmtpAddress
        write-host ($u.PrimarySmtpAddress) -ForwardingAddress ($u.ForwardingAddress) -DeliverToMailboxAndForward ($u.DeliverToMailboxAndForward)
            if ($mbx) {
                if ($u.DeliverToMailboxAndForward -eq "False") { $fwd=$false } else {$fwd=$true}
                Set-Mailbox $u.PrimarySmtpAddress -ForwardingAddress $u.ForwardingAddress -DeliverToMailboxAndForward $fwd
            }
        }
    }
}

#local\target forest
$cred1=Get-Credential
#remote\source forest
$cred2=Get-Credential

#получаем пользователей для миграции из исходного леса
$users =get-aduser -filter * -searchbase "ou=accounts,dc=forest,dc=remote" -Server $remotedc -properties mail

SaveForward

foreach ($u in $users) {
    MigrateMailbox -sam $u.SamAccountName -mail $u.mail -cred1 $cred1 -cred2 $cred2
}

#желательно разделить подготовку и запуск перемещения ящика по времени для окончания репликации между контроллерами
start-sleep 30
foreach ($u in $users) {
    New-MoveRequest -Identity $u.mail -RemoteLegacy -TargetDatabase mdb01 -RemoteGlobalCatalog $remotedc -RemoteCredential $cred2 -TargetDeliveryDomain remote.ru
}

Пожалуй всё. По ходу миграции необходимо делать Remove-MoveRequest (у меня делается автоматов каждые 4 часа) и после окончания запустить вручную LoadForward. Не стоит надеяться, что всё будет сверхбыстро и без ошибок и проблем, после миграции надо будет еще недлю производить траблшутинг того, что было пропущено и не учтено. У меня в частности почему-то не переехали алиасы.

Еще одним пунктом при миграции является миграция Lync. О ней я напишу чуть позже

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

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