0

Exchange 5.5 to Exchange 2010 – Is such a thing even possible?

Haven’t been able to get any updates posted for a little while now, been busy with that whole day job thing. I know promised more Lync tools, they’re coming and soon I hope. If I can scratch out the time to put the finishing touches on them and do the finalized testing; I’d like to get the Topology Documenter and Topology Mapper posted by this weekend. I’ve had other things on my plate and figure it might make an interesting post. So… onto other things.

Officially, there is no Microsoft supported migration from Exchange 5.5 to Exchange 2010. The oldest supported environment you can upgrade to Exchange 2010 is Exchange 2003. So that normally leaves you with a two step method, 5.5 to 2003 and then 2003 to 2010. And if you’re lucky, Exchange 5.5 will be running on Server 2000 so you at least get Active Directory to make the process easier. No such luck for me. Mine was Exchange 5.5 on NT 4.0 to Exchange 2010 SP1 on Server 2008 R2 SP1. I know what you’re thinking, “Sounds like fun!” Luckily we were moving from one NT domain, OldDom, to another 2003 AD domain, NewDom, so that made it a little easier.

I know most people won’t get any use out of this as there are not a lot of organizations left running Exchange 5.5, but maybe someone can reuse the code or learn something from it. I built the Exchange 2010 servers in the new domain and configured them to operate with the domains as a shared address space. Inbound mail flow from the outside world comes into Exchange 2010. First it checks to see if the mailbox exists in 2010 and if it does the mail is placed in the mailbox, if it doesn’t exist it’s forwarded along to the Exchange 5.5 environment for final delivery. The process is basically the same for users whose mailboxes have been moved to 2010 when they email a non-migrated user. Where it gets tricky is when non-migrated users need to email migrated users whose mailbox resides on Exchange 2010. If you were to just configured 5.5 to forward mail for unknown addresses to Exchange 2010 delivery, you could end up with routing loops when someone mistypes an email address and it doesn’t exist on either server. Exchange 5.5 was also configured to send all outbound mail through Exchange 2010 which acts as a Smart-Host.

To solve this problem I had to do a couple of things. First I added an additional email domain for all users in Exchange 2010, we’ll call it e2010.domain.com, with domain.com being the primary SMTP namespace for the organization. Next I created an external mail contact in Exchange 5.5 for users who had been moved to Exchange 2010 that contained the newly created email domain, so it points to username@e2010.domain.com. Then I forwarded their Exchange 5.5 mailbox to the mail contact so that any mail sent via Exchange 5.5 addresses to test_user@domain.com (their original email address) gets forwarded on to test_user@e2010.domain.com. Exchange 5.5 then routes this as outbound mail to the Internet and sends it out through Exchange 2010. Exchange 2010 sees that it has the SMTP address attached to the users account as an alternate address and it drops the mail in their mailbox. I’ve included a flow chart below to help explain the process.

Now that we have all that laid out, we can talk about the real problem I found. Creating those mail contacts and forwarding the mailboxes one-by-one is a very time consuming and tedious process, especially when you have 500+ mailboxes to move. Anyone who knows me knows that I like these kinds of tasks because they can be scripted and the time to completion can usually be reduced. So that’s that I set out to do, and the result is posted below. This definitely took some work and a little thinking to work through the solution. Luckily I was able to leverage a Server 2003 R2 domain controller that was used with ADMT to move the accounts over after setting up a trust relationship between the domains. This let me be able to use both VBScript and Powershell 2.0 to talk with both Exchange 5.5 and Exchange 2010 respectively at the same time. I identified the steps for migration as follows:

  • Create Mail Forward Contact in Exchange 5.5
  • Grab any email aliases that may have been created for the user
  • Create mailbox for user in Exchange 2010
  • Apply aliases to users Exchange 2010 mailbox
  • Forward users Exchange 5.5 mailbox to the Mail Forward Contact
To be able to have this process work in unity between Exchange 5.5 and Exchange 2010 I had to wrap the VBScripts inside the main Powershell script. This provided a great learning opportunity for me to be able to learn about the Microsoft ScriptControl object and using it to pass information between scripting languages. Below is the Powershell script followed by the three VBScript functions I had to create to complete the moves.

migrate-mailbox.ps1

<span class="Apple-style-span" style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;">#Display InputBox requesting Username to migrate.</span>
<pre>$objVBScript = new-object -comobject MSScriptControl.ScriptControl
$objVBScript.language = "vbscript"
$objVBScript.addcode("function getInput() getInput = inputbox(`"Please enter the Username you wish to migrate:`",`"Enter Username to Migrate`") end function" )
$Username = $objVBScript.eval("getInput")

# Create function to run VBS code inside Powershell.
function Load-VbsCode {
    param($vbsCode = $(throw "No VBS code specified."))

    $vbs = New-Object -ComObject MSScriptControl.ScriptControl
    $vbs.Language = "VBScript"
    $vbs.AddCode([string]::Join("`n", $vbsCode))
    $vbs.CodeObject
}

# Create function for adding additional alias to mailboxes
Function Add-EmailAddress {
    param($Identity, $EmailAddress)

    begin {
        $mb = Get-Mailbox $Identity
        if($mb.EmailAddressPolicyEnabled) {
            Set-Mailbox $Identity -EmailAddressPolicyEnabled $false
            $policy += 1
        }
        $addresses = $mb.EmailAddresses += $EmailAddress
    }

    process {
        Set-Mailbox $Identity -EmailAddresses $addresses
    }

    end {
        if($policy) {Set-Mailbox $Identity -EmailAddressPolicyEnabled $true}
    }
}

# Establish connection to Exchange 2010
$Exch2010Server = "EXMB01.FQDN.LOCAL"
$Exch2010Credentials = Get-Credential
$ExchSession = New-PSSession -Configurationname Microsoft.Exchange –ConnectionUri http://$Exch2010Server/powershell -Credential $Exch2010Credentials
Import-PSSession $ExchSession

CLS

# Grab user information
$User = Get-User $Username
$DisplayName = [string]$User.DisplayName
$FirstName = [string]$User.FirstName
$LastName = [string]$User.LastName
$ContactDisplayName = [string]$DisplayName + " MCT"

# Create mail contact in Exchange 5.5
Write-Host "Creating mail forwarder contact in Exchange 5.5 named $ContactDisplayName"
$CreateMailContact = Get-Content .\Create-MailContact.vbs
$CreateMailContact = Load-VbsCode($CreateMailContact)
$CreateMailContact.CreateMailContact($FirstName.ToString(),$LastName.ToString(),$Username.ToString())
Write-Host "Done!"

# Create corresponding account in Exchange 2010 environment with correct alternate SMTP addresses
# Check to see if mailbox exists, if not create it.
Write-Host "Creating mailbox for $DisplayName in Exchange 2010."
if(![bool](Get-Mailbox -Identity $DisplayName -ErrorAction SilentlyContinue)){Enable-Mailbox -Identity $Username | Out-Null}
Write-Host "Done!"

# Get alternate email alias from Exchange 5.5 account
Write-Host "Getting all alternate email alias assigned to user in Exchange 5.5."
$GetMailboxAlias = Get-Content .\Get-MailboxAlias.vbs
$GetMailboxAlias = Load-VbsCode($GetMailboxAlias)
$EmailAddresses = $GetMailboxAlias.GetMailboxAlias($UserName.ToString())
$EmailAddressesArray = $EmailAddresses.Split("|")
Write-Host "Applying alternate email alias from Exchange 5.5."
foreach($Address in $EmailAddressesArray){if($Address.StartsWith("smtp$")){Add-EmailAddress $Username $Address.SubString(5)}}
Remove-PSSession $ExchSession
Write-Host "Done!"

# Forward users Exchange 5.5 account to previously created forwarder
Write-Host "Forwarding mailbox in Exchange 5.5 to Exchange 2010."
$ForwardMailbox = Get-Content .\Forward-Mailbox.vbs
$ForwardMailbox = Load-VbsCode($ForwardMailbox)
$ForwardMailbox.ForwardMailbox($DisplayName.ToString(),$Username.ToString(),$ContactDisplayName.ToString())
Write-Host "Done!"

Write-Host "DONE: Configuration for user: $DisplayName has been completed!"
Write-Host "Press any key to Exit..."
# Wait for Key Press to close script window
$x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
<span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px; white-space: normal;">

Create-MailContact.vbs

<span class="Apple-style-span" style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;">Function CreateMailContact(strFirstName, strLastName, strEmailAlias)</span>
<pre>   strDisplayName = strFirstName &amp; " " &amp; strLastName
    strFirstInitialLastName = Left(strFirstName,1) &amp; strLastName
    strEmailAddress = strEmailAlias &amp; "@subdomain.smtpdomain.com"
    strServerName = "Exch55Serv01"
    strOUPath = "CN=Recipients,OU=Site Name,o=Organization Name"
    Set objContainer = GetObject("LDAP://" &amp; strServerName &amp; "/" &amp; strOUPath)
    Set objMailbox = objContainer.create("Remote-Address", "cn=" &amp; strDisplayName &amp; " MCT")
    objMailbox.Put "cn", strDisplayName &amp; " MCT"
    objMailbox.Put "uid", strFirstInitialLastName
    objMailbox.Put "Target-Address", "SMTP$" &amp; strEmailAddress
    objMailbox.PutEx 3, "othermailbox", Array("SMTP$" &amp; strEmailAddress)
    objMailbox.SetInfo
End Function
<span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px; white-space: normal;">

Get-MailboxAlias.vbs

<span class="Apple-style-span" style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;">Function GetMailboxAlias(strUserName)</span>

strServerName = "Exch55Serv01"
strOUPath = "CN=Recipients,OU=Site Name,o=Organization Name"
Set objMailbox = GetObject("LDAP://" &amp; strServerName &amp; "/CN=" &amp; strUserName &amp; "," &amp; strOUPath)
For Each EmailAddress in objMailbox.othermailbox
strEmailAddresses = strEmailAddresses &amp; "|" &amp; EmailAddress
Next
GetMailboxAlias = strEmailAddresses
End Function

Forward-Mailbox.vbs

<span class="Apple-style-span" style="font-family: Consolas, Monaco, monospace; font-size: 12px; line-height: 18px; white-space: pre;">Function ForwardMailbox(strDisplayName, strUsername, strContactDisplayName)</span>
<pre>   strServerName = "Exch55Serv01"
    strOUPath = "CN=Recipients,OU=Site Name,o=Organization Name"
    Set objMailbox = GetObject("LDAP://" &amp; strServerName &amp; "/CN=" &amp; strUserName &amp; "," &amp; strOUPath)
    strContactPath = "cn=" &amp; strContactDisplayName &amp; "," &amp; strOUPath
    objMailbox.Put("Alt-Recipient"),strContactPath
    objMailbox.Put("Deliver-And-Redirect"),True
    objMailbox.SetInfo
End Function
<span class="Apple-style-span" style="font-family: Georgia, 'Times New Roman', 'Bitstream Charter', Times, serif; font-size: 13px; line-height: 19px; white-space: normal;">

As always, I'm open to questions, comments, concerns, etc...

Leave a Reply

Your email address will not be published. Required fields are marked *