PowerShell Script: Bulk move Mailboxes using a CSV Input File (HMC 4.0)

This script can be used to move mailboxes, specified within a CSV input file, between mailbox servers. It will also update the MPS Resource Manager database.

 # Author: Johan Vosloo
 # Date: 12/10/2009
 # Purpose: Bulk move mailboxes from a CSV input file.
 # Disclaimer: This script is provided as-is without any support. The script was tested against HMC 4.0, Exchange Server 2007 SP1 and Powershell 1.0. Please test in a test environment prior to production use.      
 # Process:      
 # 1. Use the Exchange Management Shell to get the source server name with Get-ExchangeServer | Select Name      
 # 2. Use the Exchange Management Shell to populate the input CSV file with Get-MailboxDatabase | where {$_.ServerName.Contains("sourceservername") -eq "true"} | Get-Mailbox | Select Alias,Database | Export-Csv C:\Temp\MbxsToBeMoved.csv –NoTypeInformation      
 # 3. Change ‘Database’ field header to ‘TargetDB’      
 # 4. Modify database/targetdb field entries as required in the CSV     
 # 5. Change preferredDomainController in mailbox move script     
 # 6. Run mailbox move script:     
 # CSV Example:     
 # Alias,TargetDB     
 # bloggsj,mytargetservername 
 $path = "C:\jv\MoveMailbox\MbxsToBeMoved.csv";
 Write-Host;
 Write-Host "*******************";
 Write-Host "Move Mailbox Script" -Foregroundcolor Blue -Backgroundcolor White;
 Write-Host "*******************";
 Write-Host;
 Write-Host "A CSV is required (i.e. $path)"
 $Ver1 = Read-Host "CONTINUE script execution? [Y] to continue or [ANY OTHER KEY] to exit"
   if ($Ver1 -ne "Y")
   {exit;
   } 
 Write-Host; 
 Write-Host "Valid entries in CSV:" -Foregroundcolor Blue -Backgroundcolor White;
 # Note: Checks are not performed to avoid scenarios where sourcedb = targetdb in this version of the script. This is the administrators responsibility.
 Write-Host;
 Write-Host "Alias,TargetDB";
 Import-csv -path $path | 
 foreach `
 { 
                $TDBs = Get-MailboxDatabase $_.TargetDB -ErrorVariable MyError -ErrorAction SilentlyContinue;
 # Note: Checks are not performed to avoid scenarios where the Alias is invalid in this version of the script. This is the administrators responsibility.
     $A = $_.Alias
                Write-Host "$A,$TDBS";
 }
 If ($MyError -ne $null)`
 { 
                Write-Host;
     Write-Host "*******";
                Write-Host "Error" -Foregroundcolor Red -Backgroundcolor White;
     Write-Host "*******";
     Write-Host "Invalid TargetDB in CSV. Script terminating..." -Foregroundcolor Blue -Backgroundcolor White;
     Write-Host "Error Description:" -Foregroundcolor Blue -Backgroundcolor White;
     $MyError;
     Write-Host;
                exit;
 } 
 $Ver2 = Read-Host "CONTINUE moving ALL mailboxes in CSV? [Y] to continue or [ANY OTHER KEY] to exit"
   if ($Ver2 -ne "Y")
   {exit;
   }
 Function SendMPSRequest([string]$xmlRequestStr)
 {
   $oMpf = new-object -comobject "Provisioning.ProvEngineClient"
   $xmlResponseStr = $oMPF.SubmitTrustedRequest($xmlRequest.get_InnerXml());
   $xmlResponse = new-object "System.Xml.XmlDocument";
   $xmlResponse.LoadXml($xmlResponseStr);
   $xmlResponse;
 }
 [string]$xmlRequestStr = @"
 <?xml version="1.0" encoding="utf-8"?>
 <request>
   <data>
     <preferredDomainController>ad01.fabrikam.com</preferredDomainController>
     <user>CSVPopulated</user>
     <targetDatabase>CSVPopulated</targetDatabase>
   </data>
   <procedure>
     <execute namespace="Hosted Email 2007" procedure="MoveMailbox" impersonate="1">
       <before source="data" destination="executeData" mode="merge" />
       <after source="executeData" destination="data" mode="merge" />
     </execute>
   </procedure>
 </request>
 "@
 [string]$excXmlStr = @"
 <?xml version="1.0" encoding="utf-8"?>
 "@
 Write-Host
 Write-Host "Starting procedure..." -Foregroundcolor Blue -Backgroundcolor White;
 Write-Host
 $CSV = Import-csv -path $path
 Foreach ($line in $CSV)`
   {
     $mailbox = Get-Mailbox $line.Alias | Select Alias, DistinguishedName; 
     $userName = $mailbox.Alias;
     $userDN = $mailbox.DistinguishedName;
     $TDB = $line.TargetDB
     Write-Host "Moving $userName to $TDB..." -ForegroundColor White
     Write-Host 
     $xmlRequest = new-object "System.Xml.XmlDocument";
     $xmlRequest.LoadXml($xmlRequestStr);  
     $xmlRequest.request.data.user = "LDAP://" + $userDN;
     $xmlRequest.request.data.targetDatabase = $TDB;
     $xmlResponse = $null;
     $xmlResponse = SendMPSRequest($xmlRequestStr.ToString());
         if ($xmlResponse.Response.Data.User -ne $null)`
         {
             $MPSUser = New-Object System.Object;
             $MPSUser | Add-Member -Type NoteProperty -Name "DistinguishedName" -Value $userDN;
             $MPSUser | Add-Member -Type NoteProperty -Name "User" -Value $xmlResponse.Response.Data.user;
             $MPSUser | Add-Member -Type NoteProperty -Name "TargetDB" -Value $xmlResponse.Response.Data.targetDatabase;
             $MPSUser | FL;
         }
   }            
 Write-Host;
 Write-Host "********************************************************************************************************************************************************************************************";
 Write-Host "Script execution complete. In pre-HMC4.0 Hosted Exchange Update Rollup 5 environments, please remember to run the Managed Email 2007::RepairExchangeObject procedure on all mailboxes moved." -Foregroundcolor Blue -Backgroundcolor White;
 Write-Host "********************************************************************************************************************************************************************************************";
 Write-Host;