PrepareMoveRequest powershell script supports 2 scenarios

1. Creating a brand new user in the local forest where the MBX will be moved to.

2.  A local recipient, either a Mail Enabled User (MEU) or Mail Enabled Contact (MEC) already exists, created by an external agent such as ILM - If the local forest object is a mail contact, the script will convert the mail contact to a mail user while persisting the contact's existing exchange-related attributes. If the local forest object is a MEU, the script will reuse this mail user and stamp the essential attributes on the local mail user object.The administrator must specify the -UserLocalObject switch in order to tell the script to use this scenario.

You can read more about PrepareMoveRequest.ps1 on the "Exchange 2010 Cross-Forest Mailbox Moves" article on our Exchange Team Blog.

However, the PrepareMoveRequest.ps1 does not detect and merge already existing contacts in a multi domain scenario.

Example -

There is a new Exchange 2010 forest created which has a parent root domain and 5 child domains. FIM is used as a GALSync tool to sync the GAL of the source forests into the new target Exchange 2010 forest. FIM creates Mail Enabled Contacts (MEC) in a FIM Sync OU which is in the parent root domain.

A Mail Enabled User (MEU) is created in the new target forest by PrepareMoveRequest.ps1 script. This MEU is created in the child domain of the forest. The -UseLocalObject parameter is used with the PrepareMoveRequest.ps1 so that any already existing mail enabled contact created earlier in the forest is merged into the MEU created by the PrepareMoveRequest.ps1 script. However the already existing MEC is not found and hence not merged as the contact exists in a different domain (forest root) than the MEU.

NOTE:

-UseLocalObject parameter finds a local matching object, merges the LegacyExchangeDN attribute into the MEU created by the script and deletes the Object.

 

Below is the powershell script that will have to be run after the PrepareMoveRequest.Ps1 script which will detect the contact from the parent root domain , merge the LegacyExchangeDN into the MEU object created by the PrepareMoveRequest script and delete the contact.

NOTE:

Remove-MailContact cannot be used to delete the contact objects that are created by FIM and throws the error that the contact is a "MailForestContact and can't be deleted" , hence it needs to be deleted from the powershell with a LDAP connection to ADSI.

 

 


 

Script Funtionality:

a) Search for an existing contact in the FIM Sync OU.

b) If a contact already exists then merge the LegacyExchangeDN value of the Mail Contact in the existing MEU created by PrepareMoveRequest.ps1 and delete the contact.

c)  Log the progress in a log file.


 

 

How to run the script:

Step 1 -  Copy the below script text starting with BEGIN till END and save it in a text file. You can name the text file with whatever name you like. MergeContact.txt in this case.

Step 2 – Copy MergeContact.txt on any Exchange 2010 Server in the target forest.

Step 3 – Rename MergeContact.txt to MergeContact.ps1

Step 4 -  Create a folder named Logs in the same location where the script resides.

Step 5 –  Copy the Aliases of the users to be merged into a CSV file named Mailbox.csv. Copy Mailbox.csv in the location "C:\Migration". The column name of the Aliases in the CSV file should be "Identity".

Note: The path "C:\Migration" is not a compulsion and you can choose your own path for placing the Malbox.csv file. But if you change the path then make sure to the change the path in the script in the below shown line of the script.

import-csv -path "C:\Migration\Mailbox.csv" | foreach-object {

Step 6 –  Replace the $DirectoryServer1 value as the domain controller of the domain where the FIM syncs the contacts. <root domain in this case>

Replace the $DirectoryServer2 value as the domain controller of the domain where the PrepareMoveRequest.ps1 creates the MEU. <child domain in this case>

Step 7 -  Start Exchange Management Shell.

Step 8 – Browse to the location of the script

Step 9 – Run MergeContact.ps1


 

 

MergeContact.ps1

#########################################################################################################################################################################
#########################################################################################################################################################################
##
##     Merge Contact Script
##     ============================================
##
##
##      Purpose:
##
##      Merging the <FIM contacts> contact into the MEU created by PrepareMoveRequest.PS1 script
##
##
##     Funtionality Overview:
##
##     a) Search for an existing contact in the <target Exchange 2010> forest in the FIM Sync OU.
##     b) If a contact already exists then merge the LegacyExchangeDN value of the Mail Contact in the existing MEU created by PrepareMoveRequest.ps1 and delete the contact.
##
###########################################################################################################################################################################
###########################################################################################################################################################################

$Date=Get-Date
$Logfilepath= "logs\ProgressLog_{0}{1:d2}{2:d2}-{3:d2}{4:d2}{5:d2}" -f $date.year,$date.month,$date.day,$date.hour,$date.minute,$date.second + ".log"
$DirectoryServer1= "Root Domain DC name"
$DirectoryServer2= "Child Domain DC"
$FIMSyncOU= "OU Name"

################################################################################################################################
#
#        Function: Logging
#                 =======
#
#        Input Parameters:
#        $logtext: The text string to be written to the console or to a log file
#        $logtype: The type of message to be written: normal, error, or debug
#
#        Purpose:
#        - Writes a text string to the console and/or to log files depending on the type.
#  type=cINFO: output goes to console and the normal log file
#  type=cERROR: Output goes to Console, normal log file, and error log file
#
#
###############################################################################################################################

function logger( $logtext, $logtype )
{

switch($logtype)
{
  cINFO
  {
   write-host $logtext -b black -f green
   $logtext | Out-file $Logfilepath -append
  } 
 
  cERROR
  {
  
   write-host "ERROR: " $logtext -b black -f red
   "ERROR: " + $logtext | Out-file $logfilepath -append
  
  }
  csv
  {
   write-host $logtext -b black -f green
   $logtext | Out-file $csvfilepath -append
  }
}
}

## ----------------------------------------- End of Function "Logging" ---------------------------------------------------------

#########################################################################################################################
#
#        Function: UpdateSMTPforMailbox
#          ===========================
#
#        Input Parameters:
#       
#
#        Purpose:
#        - Adds LegacyExchangeDN of the contact as X500 addresses of the Mail User
#
#
#########################################################################################################################

function UpdateSMTPforMailbox($LDN, $useralias)
{

                 Get-MailUser -identity:$useralias -domaincontroller:$DirectoryServer2 | foreach-object {

   $MailboxID = $_."Identity"
                        }   
                        $newx500= "X500:" + $LDN
                        $error.clear()
   Set-MailUser -domaincontroller:$DirectoryServer2 -Identity:$MailboxID -EmailAddresses:((Get-MailUser -domaincontroller:$DirectoryServer2 -Identity:$MailboxID).EmailAddresses + $newx500 )
   if($error.count -gt 0)
   {
    logger ( "The LegacyExchangeDN Addresses couldn't be added : " + $newx500 + " : " + $error + " : " + "$useralias" ) cERROR
   
   }
   else
   {
    logger (" The LegacyExchangeDN has been added successfully : " + $newx500 + ": " + "$useralias")  CINFO
                              
   }
 
               }

}
## ----------------------------- End of Function "UpdateSMTPforMailbox"----------------------------------##

##################### Script Start ###################################

import-csv -path "C:\Migration\Mailbox.csv" | foreach-object {
     $useralias=$_."Identity"
     $error.clear()
     Get-MailContact -identity:$useralias -DomainController:$DirectoryServer1 -OrganizationalUnit:$FIMSyncOU | Foreach-object {
     $LDN = $_.LegacyExchangeDN
     $DN = $_.distinguishedName
     $name = $_.name
     Write-host "LegacyExchangeDN :" $LDN
     Write-host "Distinguished Name :" $DN
     Write-host "Name :" $name
     $newname = "CN=" + $name
     Write-host "Updated Display Name :" $newname
     }  
     if($error.count -gt 0)
     {
       logger ( "ERROR GETTING THE MAIL CONTACT: " + $useralias + " : " + $error ) cERROR
     }
     else
     {
      
        logger (" MAIL CONTACT DN OBTAINED SUCCESSFULLY: " + $useralias + " : " +  $LDN) CINFO
        $error.clear()
       
        ## Remove mail contact by LDAP connection as it is created by FIM ##
        
        $Class = “Contact”
        $strUsrName = “$newname”

        $objADSI = [ADSI]“LDAP://$FIMSyncOU”
        $objUser = $objADSI.Delete($Class, $strUsrName)
      
        #$objUser.setInfo                                                                              

        if($error.count -gt 0)
        {
       logger ( "ERROR REMOVING MAIL CONTACT : " + $useralias + " : " + $error ) cERROR
        }
        else
        {
          logger (" MAIL CONTACT REMOVED SUCCESSFULLY " + $useralias + " : " +  $LDN) CINFO
          Start-Sleep -s 60
          UpdateSMTPforMailbox ($LDN) ($useralias)
        }
           
         Logger ("_____________________________________________________________________________________________________") CINFO
}

}
##################### Script End ######################################


 

 

 

MergeContact.txt is also available for download in this post.

 


 

For any question you can reach out to me on the below information

Fahad Shaikh [MSFT] - fashaik@microsoft.com

 

Disclaimer: The information on this site is provided "AS IS" with no warranties, confers no rights, and is not supported by the authors or Microsoft Corporation. Use of included script samples are subject to the terms specified in the Terms of Use.