Migration Manager

Migration Preparation script

Migration Preparation script

This script idea came up after being involved in a migration project.

Published: 2013-05-22
Updated: 2013-05-24
Version: 1.1

It’s purpose with this script is for getting Quest Migration Manager (QMM) being able to match objects between domains. In a scenario with one-way trust and not being able to use Quest Migration Manager AD or any other tool for providing the SIDHistory into the AD objects. Users, mailboxes and mail contacts are already created, where the contacts are used for having a global address list (GAL) object they can send emails to.

Using QMM you can match by Username, Mailaddress or SIDHistory. In my case the username differs and the SIDHistory is not available (not allowed being copied into the target AD).

I created four different functions within this script, one called “Export-SourceInformation”, which should be used in the source environment. It will export the information from the source regarding Name, DisplayName, PrimarySmtpAddress, RecipientTypeDetails and save it into a CSV file called “users.csv”.

Then bring the CSV file into the target environment. This CSV file should be used as a control file if you don’t want to run all users at the same time (run some tests before running all of them in one batch).
I would recommend a couple of smaller batches for testing the functions before deploying it in full scale.

There is a function called “Verify-TargetInformation”, which uses the CSV file called “users.csv” and retrieves the Name and PrimarySmtpAddress for each object in the CSV file.

Another function is called “Set-SourceAddress”, this part takes care of the target account.
It uses the file called “users.csv” and checks whether there are any contacts for these mailboxes, if there are the mail contact will be deleted and the mailbox forward settings will be removed together with making sure that the mailbox is showed in the GAL. But before any changes are done, the current configuration for both the mail contact and the mailbox object are being saved into a CSV file called “targetinformation.csv”.

Last but not least, the function called “Rollback-TargetInformation” is used for putting back the PrimarySmtpAddress to the value that it was prior to the change, this by using the CSV file “targetinformation.csv”. When the Directory Synchronization have successfully matched the mailboxes this function should be runned for having back the correct information.

You can use this for free, without any guarantee or warranty and at your own risk.
Feel free to post about it, just make sure to link my blog and blogpost.

Download the script

##################################################################################### 
# Filename: Migration-Preparation-testlabs.ps1  
# Description: 
# This PowerShell script exports information, configures objects and prepares for 
# Quest Migration Manager EX Directory Synchronization 
# 
# Usage: Import-Module Migration-Preparation-testlabs.ps1 
# Start with importing the module, then Starting function: Export-SourceInformation; 
# Set-SourceAddress; Rollback-TargetInformation; Verify-TargetInformation 
# 
# Version: 1.1
#
# Changelog:
# v1.1 - Introduced LegacyExchangeDN - X500 preparation
#
# Jonas Andersson, MCC 2011 & 2012 
# http://www.testlabs.se/blog 
# Twitter @jonand82 
#####################################################################################

Add-PSSnapin Microsoft.Exchange.Management.PowerShell.E2010 -ErrorAction SilentlyContinue
Add-PSSnapin Microsoft.Exchange.Management.PowerShell.Admin -ErrorAction SilentlyContinue

## Exporting the SMTP information from Source mailboxes 
Function Export-SourceInformation(){ 

    $filename = "users.csv" 

    $users = Get-Mailbox -resultsize unlimited | Select Name,DisplayName,PrimarySmtpAddress,RecipientTypeDetails,LegacyExchangeDN
    $users | Export-CSV $filename -notype -Encoding Unicode 

}

## Changing Target mailboxes to Source PrimarySmtpAddress for QMM to match on it 
Function Set-SourceAddress(){ 

    $data = Import-CSV .\users.csv 
    $filename = "targetinformation.csv" 

    ## Saving Target Information into CSV file before changing 
    $MasterList = @() 
    Foreach($t in $data) 
    { 
        $str = $t.displayname 
        $MyObject = New-Object PSObject -Property @{ 

        Name = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").Name 
        DisplayName = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").DisplayName 
        PrimarySmtpAddress = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").PrimarySmtpAddress 
        RecipientTypeDetails = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").RecipientTypeDetails 
        Email = ((Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").EmailAddresses -Join ";") 
        DeliverToMailboxAndForward = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").DeliverToMailboxAndForward 
        ForwardingAddress = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").ForwardingAddress 
        ForwardingSmtpAddress = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").ForwardingSmtpAddress 
        HiddenFromAddressListsEnabled = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").HiddenFromAddressListsEnabled 
        LegacyExchangeDN = (Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'").LegacyExchangeDN
        ContactName = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").Name 
        ContactDisplayName = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").DisplayName 
        ContactPrimarySmtpAddress = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").PrimarySmtpAddress 
        ContactEmail = ((Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").EmailAddresses -Join ";") 
        ContactExternalEmailAddress = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").ExternalEmailAddress 
        ContactHiddenFromAddressListsEnabled = (Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'").HiddenFromAddressListsEnabled

        } 

        $MasterList += $MyObject 
    } 

    $MasterList | Export-Csv $filename -NoTypeInformation -Encoding Unicode 
    Write-Host "Information is saved into the CSV file: $filename" -ForegroundColor White 

    Foreach($i in $data) 
    { 
        $str = $i.displayname 

        ## Removing mail contacts for Source users 
        $c = Get-MailContact -resultsize unlimited -Filter "DisplayName -like '*$str*'" 
        Write-Host $c -ForegroundColor Yellow 

        ## Multiple matching, no changes will be done 
        if ($c.count -ge 1) 
        { 
            Write-Host "ERROR: Multiple matching" 
            Write-Host "Matches: $c.count" 
            return 
        } 

        ## Unique contact found, removing it 
        if ($c.count -eq $null) 
        { 
            Write-Host "Unique matching: $c" 
            Write-Host "Removing the mail contact object for: $c" 

            Remove-MailContact -Identity $c -Confirm:$false 

        } 

        ## Starting the configuration for Target Mailboxes 
        $u = Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'" 

        Write-Host $u -ForegroundColor Yellow 

        ## Multiple matching, no changes made 
        if ($u.count -ge 1) 
        { 
            Write-Host "ERROR: Multiple matching" 
            Write-Host "Matches: $u.count" 
            return 
        } 

        ## Setting the Source PrimarySmtpAddress on the Target Mailboxes 
        if ($u.count -eq $null) 
        { 
            Write-Host "Unique matching: $u" 
            Write-Host "Setting Source SMTP as PrimaryAddress for matching using QMM" 
            Write-Host "Configuring the mailbox for showing up in GAL and remove the forwarding configuration"
            Write-Host "Adding the LegacyExchangeDN as X500 for Outlook auto-complete cache"
 

            $email = $i.PrimarySmtpAddress
            $x500 = $i.LegacyExchangeDN

            Set-Mailbox -Identity $u -ForwardingAddress $null -DeliverToMailboxAndForward:$false -HiddenFromAddressListsEnabled:$false -PrimarySmtpAddress $email -EmailAddressPolicyEnabled:$false 

            $ProxyAddresses = (Get-Mailbox -Identity $u).EmailAddresses
            $ProxyAddresses += [Microsoft.Exchange.Data.CustomProxyAddress]("X500:$x500")
            Set-Mailbox -Identity $u -EmailAddresses $ProxyAddresses
        } 

        else 
        { 
            Write-Host "No match" 
            return 
        } 

    } 

    Write-Host "" 
    Write-Host "#################################################################" -ForegroundColor White 
    Write-Host "# First run the Verify-TargetInformation..                        #" -ForegroundColor White 
    Write-Host "# Start the QMM Synchronization for matching Source <-> Target  #" -ForegroundColor White 
    Write-Host "# Finally run the Rollback-TargetInformation when sync is done  #" -ForegroundColor White 
    Write-Host "#################################################################" -ForegroundColor White 
    Write-Host "" 
}

## Rollback of Target PrimarySmtpAddress 
Function Rollback-TargetInformation(){ 

    $data = Import-CSV .\targetinformation.csv 

    $MasterList = @() 
    Foreach($i in $data) 
    { 

        $str = $i.displayname 
        $user = Get-Mailbox -resultsize unlimited -Filter "DisplayName -like '*$str*'" 

        ## Predicts there is only one @testlabs.se address 
        $pri = Get-Mailbox -Identity $user | Select-Object -ExpandProperty EmailAddresses | Where-Object {$_.SmtpAddress -like '*@testlabs.se'} | Select-Object SmtpAddress 
        $adr = $pri.SmtpAddress 

        Write-Host "Configuring mailbox: $user with adress: $adr" -ForegroundColor White 
        Set-Mailbox -Identity $user -PrimarySmtpAddress $adr -EmailAddressPolicyEnabled:$False 

    } 

}

## Verifying the Target PrimarySmtpAddress 
Function Verify-TargetInformation(){

    $data = Import-CSV .\users.csv 

    $filetime = (get-date -format yyyyMMddhhmm) 
    $filename = "verify-$filetime.csv" 
    $MasterList = @() 

    ## Verifying the PrimarySmtpAddress 
    Foreach($i in $data) 
    { 

        $MyObject = New-Object PSObject -Property @{ 

            Name = (Get-Mailbox -Identity $i.PrimarySmtpAddress).Name 
            PrimarySmtpAddress = (Get-Mailbox -Identity $i.PrimarySmtpAddress).PrimarySmtpAddress 
            Database = (Get-Mailbox -Identity $i.PrimarySmtpAddress).Database
            EmailAddresses = ((Get-Mailbox -Identity $i.PrimarySmtpAddress).EmailAddresses -Join ";") 
        } 

        $MasterList += $MyObject 

    } 

    $MasterList | Export-Csv $filename -NoTypeInformation -Encoding Unicode 
    Import-CSV $filename 

    Write-Host "" 
    Write-Host "SMTP Verification is saved into the CSV file: $filename" -ForegroundColor White 
    Write-Host "" 
}
Part 1: Migrations – overview

Part 1: Migrations – overview

This will be a collection of posts, regarding migrations in general in the first post will digging deeper in the following posts.

Published: 2013-05-09
Updated: 2013-05-15
Version: 1.1

Thanks for the great input and feedback: Hakim Taoussi and Magnus Göransson

Part 1: Overview

I will try to keep the first post not technical since this is more common sense then anything else.
In short I want to summarize some key takeaways and recommendation to stick with, explaining them a bit more in detail below.

  • Planning
  • Information & communication
  • Pilot migrations
  • End-user training
  • Experience
  • Minimize the coexistence time
Planning

Some of you might think that… well of course we are planning. But sometimes I hear people that spend like 10-15% of their total project time for planning. I would recommend you to rethink if that’s the case, and suggest that you maybe should spend at least 50% of the time for it, maybe even more (in large projects).

What I mean with planning is to create a detailed migration plan, this should of course include estimations regarding how many users can be migrated per hour, how much data can be transferred per hour.
Basically what this means is that the planning phase should be used for planning and verifying that everything is in place and works like it’s expected to do.

For example, in the official guide from Quest Software when migrating from Domino to Exchange they calculate of 5GB/hour/migration server during good conditions. In the real world I’ve seen throughput of 20GB/h/server. With this said, it all depends… (the consultants favorite phrase) This is one of those things that needs to be tested and verified before creating a detailed migration plan, for doing a good estimation.

Don’t forget to verify that the target environment have enough capacity, servers and storage.

Other questions that needs clear answers can be;
How is users and mailboxes provisioned?
During the migration, where should new mailboxes be created?
Is there information in the user attributes that needs to be migrated from Domino into AD?
How will the migration process work?
What requirements are there?

So for the planning, think about all steps.

Information & Communication

With information I mean to inform everybody that’s involved in the project in one or another way.
This would include the helpdesk and support, since these are the projects closest friends for helping and taking care of incidents.

On the other hand we have the users themselves, here I’m talking about the end-users. If the migration will impact the users in a way they are not used to, remind to inform them a couple of weeks before they are going to be migrated, with a reminding notification a couple of days when the migration will take place.
During a transition from for example, Exchange 2007 to Exchange 2010, there won’t be much impact on the users, it’s more a data transfer and updating a couple of attributes in the directory so the impact is very small. In those transition projects (it depends on the customer requirements) the needs for user reminders is not that big as the migration projects. But keep in mind, it’s better they get too much information than too little.

In large projects it’s a recommendation to place the information on public places like the restroom and the lunch room. Also inform the people on every place that’s possible, intranet, mail, letter, meeting and so on.

In short I want to say the obvious, if the information is lacking or poor, the experience from the end-user perspective will be poor. In the end this give the result of a failed project, at least from a user perspective.

Pilot migrations

From the projects I’ve been a part of I’ve learnt lots of things and gained experience. One of these things is to have a good pilot, I would recommend to divide the pilot into 3 parts.

Part 1 is the “Technical Pilot”, this would include the closest project members and/or only technical people that can handle issues and problems when they occur.
Part 2 is the “Pilot 1” and this would include at least 10 users, spread throughout the organization, the more spread they are the better value would the pilot have.
Part 3 is called “Pilot 2”, this is started when the “Pilot 1” phase is completed and the evaluations are done. Maybe some tweaking needs to be done before starting this stage (if there were issues and errors).
In “Pilot 2” should at least 50 people be included throughout the organization, this last Pilot phase is used for solving any issues that occurred in previous stages, this for minimizing the impact when the real migration phase will take place.

The numbers above is just examples, but might be good examples for a environment with a couple of thousand users.

Before starting with “Pilot 2” the whole migration process, how object get provisioned should be well documented. It would be a recommendation to have it documented even in the “Technical Pre-Pilot”, but my experience tells me that things are changing and somewhere during “Pilot 1” the processes are getting tested and documented.

End-user training

As this is mentioned, in some cases it might not be needed, for instance if the moved users still keeps the same Outlook client version and the impact is very low. As we all know things are changing over time with new versions and if the user used for example Outlook 2003 with Windows XP and will be upgraded to Windows 7 and Outlook 2013, there might be a reason for giving the users a training session and some documents with instructions on how things work in the new version.

If the users are migrated for example from Domino/Notes to Exchange/Outlook I would strongly recommend having training sessions were the users can attend and also bringing instructions on how things differs between Notes and Outlook, and how Outlook should be used for booking a meeting, sending a mail etc.

This for making sure that the users gets a good experience and can handle the new tools.

Minimize the coexistence time

I’m not writing this because of lack due to products out there or the functions of them.

But I’m writing this bullet for having a smoother and easier understanding, mostly for the helpdesk and the end-users. During a coexistence (freebusy/mail flow/directory synchronization) time it can be hard to troubleshoot and isolate incidents and problems. Another good reason for minimizing the coexistence time is regarding all shared resources, by minimizing the coexistence time you will reduce the impact for the end-users. So for minimizing these hours spent on troubleshooting and the work effort everyone need to put in, I would recommend to keep the coexistence time as short as it can be, without impacting the experience or business in a bad way.

In short I would say, if things are working. Keep up a good pace for having a short coexistence time!

Experience

Last but not least, I would recommend you to select careful what project members are selected or which company that runs these kind of projects. It’s very important that they have the full understanding of what needs to be done and what impact it has for everyone involved but also the business itself.

If using Quest Software, they have a requirement of using certified people for designing, installing and configuring their products. This for making sure that the result will be good and that everyone should be satisfied with it. I’m not sure about other vendors but I think they have something similar to this model.

Read more
Part 2: Prerequisites for Domino/Notes migrations
Part 3: Migrating Domino/Notes to Exchange 2013 On-premise
Part 4: Migrating User Mailboxes from Domino/Notes to Office 365
Part 5: Migrating Resources Mailboxes, Mail-In databases and Groups
Part 6: Prerequisites for Coexistence between Domino and Exchange 2013/Office 365
Part 7: Configuring Coexistence Manager for Notes with Exchange 2013 On-Premise
Part 8: Configuring Coexistence Manager for Notes with Office 365
Part 9: Prerequisites for Migration Manager
Part 10: Migrating User Mailboxes from Exchange 2003 to Exchange 2013 using Migration Manager
Part 11: Migrating User Mailboxes from Exchange On-Premise to Office 365

I hope these key takeaways gave you some good insight and some things to think about.
I would be happy to hear your comments/feedback this post.

The plan is to post a new article every second week, keep your eyes open

Regards,
Jonas