Move folder content from a source mailbox to a target mailbox, in Exchange Online (EWS Managed API 2.2)

As a result of many customer inquiries, I have decided to write the script below that moves mailbox data from a source mailbox to a target mailbox. Use this script when the source and the target mailboxes are created in mirror, with the same folders/subfolders on each side. In case there are folders existing only on the source side, you will get notified and you can use the upgraded version of the script.

 

Prerequisites:

  • Grant full access rights on the source and target mailboxes to a third Exchange Online mailbox whose credentials you provide within the script (#Provide the credentials of the Exchange Online mailbox...).
  • In order to run the script, you have to copy paste its content into a Notepad file and save it with the extension ".ps1". Then, you have to connect to Exchange Online with PowerShell and run it: https://technet.microsoft.com/en-us/library/jj984289(v=exchg.160).aspx.

 

 

 DISCLAIMER: This application is a sample application. The sample is provided "as is" without warranty of any kind. Microsoft further disclaims all implied warranties including without limitation any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the samples remains with you. in no event shall Microsoft or its suppliers be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss arising out of the use of or inability to use the samples, even if Microsoft has been advised of the possibility of such damages). Because some states do not allow the exclusion or limitation of liability for consequential or incidental damages, the above limitation may not apply to you.



# The script requires EWS Managed API 2.2, which can be downloaded here: https://www.microsoft.com/en-gb/download/details.aspx?id=42951
# Make sure the Import-Module command matches the Microsoft.Exchange.WebServices.dll location of EWS Managed API, chosen during the installation



$SourceMailbox = Read-Host -Prompt "Source mailbox"
$TargetMailbox = Read-Host -Prompt "Target mailbox"

Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"

$service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList Exchange2013_SP1

#Provide the credentials 
$credential = Get-Credential -Message "Provide the credentials of the Exchange Online mailbox that has full access permissions on the source and on the target mailboxes"
$service.Credentials = new-object Microsoft.Exchange.WebServices.Data.WebCredentials -ArgumentList $credential.UserName, $credential.GetNetworkCredential().Password

#Exchange Online URL
$service.Url= new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx")



function MoveFolderItems ($Source, $Target)
{

$ItemView = new-object Microsoft.Exchange.WebServices.Data.ItemView(1000)

$FindItemResults = $service.FindItems($Source,$ItemView)

if($FindItemResults.TotalCount)

{

write-host "$($FindItemResults.TotalCount) item(s) have been found in the Source mailbox folder and will be moved to the Target mailbox folder. If they are not, then, their item class is out of the scope of the current operation." -ForegroundColor White

do
{
foreach ($Item in $FindItemResults.Items)
{

if ($Item.ItemClass -match "IPM.Note" -or $Item.ItemClass -match "IPM.StickyNote" -or $Item.ItemClass -match "IPM.Activity" -or $Item.ItemClass -match "IPM.File")
 { $Message = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service,$Item.Id); $Message.Move($Target); continue; }

if ($Item.ItemClass -match "IPM.Appointment")
 { $Message = [Microsoft.Exchange.WebServices.Data.Appointment]::Bind($service,$Item.Id); $Message.Move($Target); continue; }

if ($Item.ItemClass -match "IPM.Contact")
 { $Message = [Microsoft.Exchange.WebServices.Data.Contact]::Bind($service,$Item.Id); $Message.Move($Target); continue; }

if ($Item.ItemClass -match "IPM.Task")
 { $Message = [Microsoft.Exchange.WebServices.Data.Task]::Bind($service,$Item.Id); $Message.Move($Target); continue; }
 }

$ItemView.offset += $FindItemResults.Items.Count

}while($FindItemResults.MoreAvailable -eq $true)

}
 else { Write-Host "Source folder empty!" -ForegroundColor Yellow }

}


function ConvertFolderId ($OwaId, $EmailAddress)
{

$OwaId = $OwaId.Replace('+','%2b')

$aiItem = New-Object Microsoft.Exchange.WebServices.Data.AlternateId

$aiItem.Mailbox = $EmailAddress

$aiItem.UniqueId = $OwaId

$aiItem.Format = [Microsoft.Exchange.WebServices.Data.IdFormat]::OwaId

$convertedId = $service.ConvertId($aiItem, [Microsoft.Exchange.WebServices.Data.IdFormat]::EwsId)

$folderid = new-object Microsoft.Exchange.WebServices.Data.FolderId($convertedId.UniqueId)

return $folderid;

}


foreach ($Folder in Get-MailboxFolderStatistics $SourceMailbox )
{

$i=0;

if($Folder.ContainerClass) {
 foreach ($Folder2 in Get-MailboxFolderStatistics $TargetMailbox ) {

if($Folder2.ContainerClass -and $Folder.FolderPath.ToString() -eq $Folder2.FolderPath.ToString())

{

$SourceFolderId = ConvertFolderId $Folder.FolderId $SourceMailbox

$TargetFolderId = ConvertFolderId $Folder2.FolderId $TargetMailbox

Write-Host "Source Folder: $($Folder.Name)" -ForegroundColor White

MoveFolderItems $SourceFolderId $TargetFolderId

$i++;

break;

}

}

if(!$i) {write-host "Please create a corresponding folder with the Folder Path $($Folder.FolderPath) in the Target mailbox!" -ForegroundColor Red; continue; }

}
 }

 

Note: In case you want to copy the items from the source mailbox to the target mailbox, you just need to modify the operation from $Message.Move($Target) to $Message.Copy($Target).