Moving Mailboxes Cross Organizations in Exchange 2007
I've seen a number of posts on other blogs talking about the new features of Exchange 2007 and the ability now to move mailboxes across organizations. I currently have a customer engaged in a major consolidation of multiple Exchange 2003 organizations into a single forest, single Exchange 2007 organization. The design for this customer calls for the following:
- Users will continue to log onto and operate from their current domains for their primary job functions.
- Users will all have new accounts in the consolidated forest. These accounts could be used as primary logons (where trust relationships exist), but that will be determined on a per-department basis.
- If possible, users should get a single sign-on experience when accessing their new mailbox.
- Outside of the requirement to flip the Outlook profile (for earlier versions of Outlook), users should experience minimal interruption.
Upon looking at the documentation for the move-mailbox cmdlet (note that cross-organization moves cannot be done in the GUI), it appears the the -AllowMerge parameter would best meet our needs. The AllowMerge is documented by Microsoft at http://technet.microsoft.com/en-us/library/aa997599.aspx:
"The AllowMerge parameter specifies the merging of mailboxes if one mailbox already exists. You can use this parameter to move a mailbox between different organizations even if a target mailbox already exists. The contents of the mailbox are merged at the target. This parameter cannot be used if the NTAccountOU parameter is used."
The process calls for first moving the mailbox into the target domain, keeping the source domain mailbox open to users. This can be done with the following cmd-let (simplified here):
Get-Mailbox -DomainController "[FQDN of Source DC]" -Credential $s -Identity "[email address]" | move-mailbox -TargetDatabase "Exch01\First Storage Group\Mailbox Database" -SourceForestGlobalCatalog "[FQDN of Source DC]" -GlobalCatalog "[FQDN of Target DC]" -DomainController "[FQDN of Target DC]" -SourceMailboxCleanupOptions none -SourceForestCredential $s -TargetForestCredential $t -Confirm:$false
This Powershell script will give us what we want, provided we have an existing user in the target forest with a matching SID. Because we need the SID match for a mailbox move to work properly, we turn to ADMT v3. For most organizations, this is already a no-brainer. My particular customer, however, had already created a separate identity solution in the target forest, so we had to use ADMT to ensure that the source SIDs got matched to target accounts that were not necessarily the same person (from AD's perspective). In order for ADMT to work as desired, we did need basically a perfect match on the sAMAccountName attribute. Once the SIDs were matched, we had no problems moving mailboxes between organizations.
The other thing missing from the documentation is that Get-Mailbox doesn't work across forest trusts with a single account. That is why we need two different variables for the source and target credentials. This does appear to be a bug with the Exchange 2007 release. No news on whether it will be updated in SP1.
After the mailboxes have all been moved, it was pretty straight forward to merge the mailboxes. The mailbox merge takes all the changes since the first move, and incorporates them into the target mailbox. One thing I noticed, however, is that items deleted from the source inbox were not replicated as deleted to the target mailbox (although the target mailbox contained the items both in the inbox and deleted items folders). However, if large scale deployments want to "flip the switch" overnight, the allowMerge functionality seems to get the job done. The code we used to accomplish this, looked similar to the following:
Get-Mailbox -DomainController "[FQDN of Source DC]" -Credential $s -Identity "[email address]" | move-mailbox -TargetDatabase "Exch01\First Storage Group\Mailbox Database" -SourceForestGlobalCatalog "[FQDN of Source DC]" -GlobalCatalog "[FQDN of Target DC]" -DomainController "[FQDN of Target DC]" -AllowMerge -SourceForestCredential $s -TargetForestCredential $t -Confirm:$false
The end result is that the move-mailbox function brought over all the user's content, updated the attributes in the target domain for each user so that reply-ability was preserved, and generally made for a pretty cool solution to a historically difficult problem. The drawback, however, of the tool is that the objects in the source domain are not treated. In other words, if only half the users are migrated to the new environment, mail-flow between the two organizations becomes broken in the source domain. This is further complicated by the fact that Exchange 2003 doesn't respect the disable-mailbox and enable-mailuser cmdlets that could have been used to create proxies in the source domain. Your mileage may vary on this specific problem, but in the case of our consolidation project, the source and target had different administrators.
We simply ran out of options for PowerShell and had to turn back to ADSI+VBScript to get the job done. The Script is pretty simple, and pretty straight-forward. It can be run by either the administrators of the source domain or target domain, so long as it was run on an Exchange Server in the source domain. In our actual production implementation, we used a single CSV file to pipe in the users for both the powershell and vbscript functions. To preserve the anonymity of the customer, however, I am just sharing below the code we actually used to disable the source mailbox for a user, followed by re-mail-enabling the user as a "contact" (actually, a mail-enabled user pointing to the target forest).
DIM strUserDN '*** This is the distinguished name of the user (string)
DIM objUser '*** Object variable for containing the user
DIM strEmailAddr '*** Populate with the external email address of the mail-enabled user
'*** Set variables
strUserDN = "[Distinguished Name of Account]"
strEmailAddr = "[email address]"
'*** Get user object
wscript.echo "Connecting to user " & strUserDN
Set objUser = GetObject("LDAP://" & strUserDN)
'*** Wipe out the existing Mailbox
wscript.echo "Removing mailbox"
'*** Okay, now let's mail-enable it
wscript.echo "mail-enabling the user with address: " & strEmailAddr