PowerShell: Script to move items from one folder to another in a user’s mailbox


Note: A completely rewritten and enhanced version of this script can be found here.

Manipulation of mailbox items is not something that is really available using Exchange cmdlets - understandably, as Exchange PowerShell is for administration of the Exchange environment rather than manipulation of mailboxes themselves.  Of course, PowerShell itself offers all the features needed to be able to write a script to anything that is possible using EWS, so with a little EWS and PowerShell knowledge we can manipulate pretty much anything.

In a migration scenario recently, a customer found that due to the legacy system being migrated, items were not in the expected folder once a mailbox had been moved to Exchange 2010.  In this case, the sent items were actually in a subfolder of the Sent Items folder.  So, the question was asked whether we can give a sample script that shows how to move all these items from the subfolder into the Sent Items folder.

Attached is a script that does exactly this.  In fact, it will work for any folder, and can optionally delete the source folder on completion.  If delete is requested, the folder will only actually be deleted if it is empty, so in the event that an item failed to move, nothing will be lost.  The script accepts parameters so can be combined with other PowerShell features to process many mailboxes in a batch job.  It was tested against Office 365 and on-premises Exchange.  The script is attached, and the parameters are detailed below:

MoveItems -Mailbox <string>
    -SourceFolder <string>
    -TargetFolder <string>
      [-ProcessSubfolders <bool>]
      [-DeleteSourceFolder <bool>]
      [-Username <string> -Password <string> [-Domain <string>]]
      [-Impersonate <bool>]
      [-EwsUrl <string>]
      [-IgnoreSSLCertificate <bool>]
      [-EWSManagedApiPath <string>]
      [-LogVerbose <bool>]

Required:
 -Mailbox : Mailbox SMTP email address
 -SourceFolder : Full path to source folder in the mailbox (items are moved from this folder)
 -TargetFolder : Full path to target folder in the mailbox (items are moved to this folder)

Optional:
 -ProcessSubfolders : If true, subfolders of the source folder will also be processed (default is false)
 -DeleteSourceFolder : If true, the source folder will be deleted once items moved (so long as it is empty)
 -Username : Username for the account being used to connect to EWS (if not specified, current user is assumed)
 -Password : Password for the specified user (required if username specified)
 -Domain : If specified, used for authentication (not required even if username specified)
 -Impersonate : Set to $true to use impersonation.
 -EwsUrl : Forces a particular EWS URl (otherwise autodiscover is used, which is recommended)
 -IgnoreSSLCertificate : If $true, then any SSL errors will be ignored
 -EWSManagedApiDLLFilePath : Full and path to the DLL for EWS Managed API (if not specified, default path for v1.2 is used)
 -LogVerbose: Show detailed output

 

 

Example:

PS C:\powershell> .\moveitems.ps1 -Mailbox Administrator@exch2k10sp2.local -SourceFolder "Inbox\Test" -TargetFolder "\" -ignoresslcertificate $true -processsubfolders $true

The above will copy items from the folder Inbox\Test into the root folder, and process subfolders (e.g. Inbox\Test\Inbox items will be moved into the user's main inbox).

MoveItems.zip

Comments (59)

  1. Thanks! Exactly what I was looking for! says:

    Thank you very much!  I'm in the same boat as your client; migration and items ended up in a subfolder.  Contacts, Calendar, Inbox, everything ended up in this subfolder instead of the root folder.  

    This looks like it will do exactly what I need, but I'm having a bit of trouble with it.  I've input:

    . .MoveItems.ps1 -mailbox (username@domain.com) -sourcefolder SubFolderInPrimary* -targetfolder *

    For an output I get "Failed to find"

    I'm guessing that my formatting for the folders is incorrect?  How should I phrase the locations to move from this subfolder to root?

    Thanks again!

    (I tried to post once before, but I don't think it went through. Please ignore if you have received it.)

  2. I haven't tested your particular scenario – and it may be that there is an unexpected issue if you are moving from a subfolder back up to the root folder.  I'll have to test this and I'll post back once done (which will be on Monday).

  3. ST says:

    Hi Dave,

    Thanks again for posting the script.  I ended up moving the files for each user manually since it needed to get done before a deadline.  In case I find myself in this situation in the future, have you had a chance to test this scenario?  

    If not, is there any chance you could post a sample input for me to compare in the future?

    Thanks again!

  4. Sorry for the delay.  I had to make quite a few modifications to the script for it to handle your scenario, but now it will so updated script and details are as above.  A significant change is that the script will now process subfolders.

  5. ST says:

    No worries about the delay–thank you for doing this at all!  I'm putting this in my tools folder–it'll definitely come in handy again someday.

  6. hi

    if i run that script on our Exchange Mailboxserver "Rollup 1 SP2 then we have the following error:

    [PS] C:>.MoveItems.ps1 -Mailbox chjournalingmbx-0001@domain.ch -SourceFolder "" -TargetFolder "test" -ignoresslcert ificate $true -processsubfolders $true

    WARNING: Ignoring any SSL certificate errors

    Performing autodiscover for chjournalingmbx-0001@domain.ch

    Exception calling "Bind" with "2" argument(s): "The request failed. The underlying connection was closed: An unexpected  error occurred on a send."

    At C:MoveItems.ps1:256 char:66

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($service, [Microsoft.Exchange.WebServices.Dat a.WellKnownFolderName]::MsgFolderRoot);

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

  7. Hi Dave

    I downloadet you script and i have still the same error as "ST" had.

    Failed to find …. Inbox

    Requested folder path: Inbox

    PS:

    [PS] C:>.MoveItems.ps1 -Mailbox chjournalingmbx-0001@mydomain.ch -SourceFolder "Inbox" -TargetFolder "export_pst" -ignoresslcertificate $true -processsubfolders $true

    The error is:

    WARNING: Ignoring any SSL certificate errors

    Performing autodiscover for chjournalingmbx-0001@mydomain.ch

    Exception calling "Bind" with "2" argument(s): "The request failed. The underlying connection was closed: An unexpected error occurred on a send."

    At C:MoveItems.ps1:256 char:66

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($service, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRo

    ot);

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.

    At C:MoveItems.ps1:169 char:41

    +                 $FolderResults = $Folder.FindFolders <<<< ($SearchFilter, $View);

       + CategoryInfo          : InvalidOperation: (FindFolders:String) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

  8. This is most likely an authentication issue.  I started getting this when I updated to using EWS Managed API 1.2 (from 1.1), and I think to get around it I had to specify the domain in the EWS credentials.  In your case, it looks like you are using default credentials – could you try specifying the EWS credentials instead to see if this works?

  9. An authentication issue can not be true then i have full access on all Mailboxes like DomainAdmin. I'm logged in on the Mailboxserver as a DomainAdmin. When i try with the EWS credentional like:

    [PS] C:>.MoveItems.ps1 -Mailbox a-sboehler@mydomain.ch -SourceFolder "InboxTest" -TargetFolder "" -Username USERNAME – Password PASSWORD -EwsUrl https://CAS/HUBSERVER/ews/Exchange.asmx -ignoresslcertificate $true -processsubfolders $true

    comes the same error:

    WARNING: Ignoring any SSL certificate errors

    Exception calling "Bind" with "2" argument(s): "The request failed. The underlying connection was closed: An unexpected  error occurred on a send."

    At C:MoveItems.ps1:256 char:66

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($service, [Microsoft.Exchange.WebServices.Dat

    a.WellKnownFolderName]::MsgFolderRoot);

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.

    At C:MoveItems.ps1:169 char:41

    +                 $FolderResults = $Folder.FindFolders <<<< ($SearchFilter, $View);

       + CategoryInfo          : InvalidOperation: (FindFolders:String) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

    Failed to find  Inbox

    Requested folder path:  InboxTest

  10. Please can you try with the -Domain parameter specified as well, as it is specifically that parameter that I have seen cause the issue before (i.e. domain must be specified).

  11. Jayhawks says:

    Can the source folder be in the primary mailbox and the target folder reside in the archive mailbox?

  12. Jason says:

    I added the following lines to make the target the archive:

    # Check we can bind to the source folder (if not, stop now)

    $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot);

    $ArchiveRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::ArchiveMsgFolderRoot);

    $SourceFolderObject = GetFolder($MailboxRoot, $SourceFolder);

    if ($SourceFolderObject)

    {

    # We have the source folder, now check we can get the target folder

    if ($LogVerbose) { Write-Host "Source folder located: " $SourceFolderObject.DisplayName; }

    $TargetFolderObject = GetFolder($ArchiveRoot, $TargetFolder);

  13. Reid says:

    I'd like to move all messages contained in subfolders to the Target folder. (But not move the underlying subfolder structure – just the messages themselves)  What modification would be made to accommodate that?

  14. Exchange 2007 says:

    Hi,

    Is there a equivalent exchange 2007 script to do what the above achieves?

    Thanks

    Paresh

  15. The script should work with Exchange 2007, you just need to change line 206 to use the Exchange 2007 schema (::Exchange2007_SP1).

    With regards to updating the script to move items to a single folder, you shold be able to do this by changing line 143 to:

    MoveItems($SourceSubFolderObject, $TargetFolderObject, $SourceFolderPath, $TargetFolderPath);

    Note I haven't tested the above modification – it is possible that there may be something else that needs changing.  Please test and remember that using this code is at your own risk!

  16. Exchange 2007 says:

    thanks for the quick reply, i had already tried change schema to use Exchange2007_sp1 but get the following:

    Exception calling "Bind" with "2" argument(s): "Exchange Server doesn't support

    the requested version."

    At C:MoveItems.ps1:256 char:66

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($serv

    ice, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot);

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.

    At C:MoveItems.ps1:169 char:41

    +                 $FolderResults = $Folder.FindFolders <<<< ($SearchFilter, $Vi

    ew);

       + CategoryInfo          : InvalidOperation: (FindFolders:String) [], Runti

      meException

       + FullyQualifiedErrorId : InvokeMethodOnNull

  17. Exchange 2007 says:

    now i get the following error

    Exception calling "Bind" with "2" argument(s): "The request failed. The remote server returned an error: (503) Server Una

    vailable."

    this seems to be the problem line

    $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot);

    any help would be appreicated

    Thanks

    Paresh

  18. Dan G says:

    Hi Dave,

    Not sure if this thread is still active,

    I am trying to use the script ( which would solve a problem I have perfectly ) but I am getting the error below. I saw in previous posts that you mentioned that it was an authentication issue and to specify the -Domain parameter ( which I have done ) but I still get the error. I have also made the modification to line 143 to put ALL the items into the inbox rather than preserving the folder structure. Any help would be greatly appreciated.

    Here is the command I ran and the output

    .MoveItems.ps1 -Mailbox "email@domain.com" -SourceFolder "InboxImport" -TargetFolder "" -ProcessSubfolders $true -IgnoreSSLCertificate $true -EwsUrl "ewsurl.domain.com/…/exchange.asmx" -Username "Username" -Password "Password" -Domain "Domain Name"

    WARNING: Ignoring any SSL certificate errors

    Exception calling "Bind" with "2" argument(s): "The request failed. The underlying connection was closed: An unexpected

    error occurred on a send."

    At MoveItems.ps1:256 char:66

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($service, [Microsoft.Exchange.WebServices.Dat

    a.WellKnownFolderName]::MsgFolderRoot);

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.

    At MoveItems.ps1:170 char:41

    +                 $FolderResults = $Folder.FindFolders <<<< ($SearchFilter, $View);

       + CategoryInfo          : InvalidOperation: (FindFolders:String) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

    Failed to find  Inbox

    Requested folder path:  InboxImport

    Thanks again !!

  19. Which version of the managed API are you using?  Can you try accessing the mailbox with EWSEditor (and the same log-on details) to see if the problem also occurs using that?

  20. Dan G says:

    Not sure if my last post went through. Using version 1.2 of API ( I have also tired 2.0 ) I just tested with EWSEditor and that works with no issue. However you bind to MsgFolderRoot on line 256. In EWSEditor Inbox is not directly below MsgFolerRoot. In my EWSEditor tree I see Inbox below Top of Information Store.

    Thank you.

  21. For those still experiencing issues try the explanation and solution given by Glen Scales.

    This solved my problem that occured when using the IgnoreSSLCertificate parameter.

    [quote]

    Remove the following line

    [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}

    Add this block in its place

    ## Code From http://poshcode.org/624

    ## Create a compilation environment

    $Provider=New-Object Microsoft.CSharp.CSharpCodeProvider

    $Compiler=$Provider.CreateCompiler()

    $Params=New-Object System.CodeDom.Compiler.CompilerParameters

    $Params.GenerateExecutable=$False

    $Params.GenerateInMemory=$True

    $Params.IncludeDebugInformation=$False

    $Params.ReferencedAssemblies.Add("System.DLL") | Out-Null

    $TASource=@'

    namespace Local.ToolkitExtensions.Net.CertificatePolicy{

    public class TrustAll : System.Net.ICertificatePolicy {

    public TrustAll() {

    }

    public bool CheckValidationResult(System.Net.ServicePoint sp,

    System.Security.Cryptography.X509Certificates.X509Certificate cert,

    System.Net.WebRequest req, int problem) {

    return true;

    }

    }

    }

    '@

    $TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)

    $TAAssembly=$TAResults.CompiledAssembly

    ## We now create an instance of the TrustAll and attach it to the ServicePointManager

    $TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")

    [System.Net.ServicePointManager]::CertificatePolicy=$TrustAll

    ## end code from http://poshcode.org/624

    [/quote]

    Source: gsexdev.blogspot.nl/…/ews-managed-api-and-powershell-how-to.html

  22. Awesome script! It saved me a lot of work trying to write my own from scratch! One minor modification though, at least in my environment. It looks like the logic for $DeleteSourceFolder will always fail for a parent folder with subfolders. If you move this logic to the MoveItems function section that checks for $ProcessSubFolders it will recursively delete the subfolders. You will also need to add a check for the final $DeleteSourceFolder section to run only if $ProcessSubFolders is false as well (since the root will be deleted in MoveItems function now). There is probably a more elegant way to implement it but it's the best I could do at my skill level.

  23. Hello Community,

    with some modifactions the script runs lovely. This is only a part of my need. So what i want to do is

    Read the subject ==> if "<new user> " = true then read email body and create the user with information from the body.

    I have searched the whole day to find a solution, but it seems that everyone in the world just only want to send emails and not to read them with powershell.

    So i tried to change:

    $View.PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties);

    replaced IDOnly with FirstClassProperties

    So now i get the subject but not the body information.

    Searching for the methods and objects let me find the suggested source code, methods and objects. but iam not so familar to use them right. Can someone give me a hint?

    thanks

    CHN

  24. Stuart says:

    This is fantastic and I've finally been able to get it working with our Office-365D environment. I have no experience with EWS so this may not even be possible… But… Would it be possible to use this type of script to move items from one user's mailbox to another user's mailbox? We have to migrate some employees to new contractor mailboxes and are looking for a way to copy the contents of their old mailboxes over to their new mailboxes. Thank you.

  25. A few things I noticed while running it in my environment for a folder migration project:

    1. If the folder has more than double the number of items then the current page size, you will run into an issue where the Offset is above the current item count and it will view the source folder as empty when it actually has items remaining. I resolved this by always setting the Offset to 0

    2. I ran into a few instances where users had multiple source folders of the same name and the script was designed to ignore those issues. By adding a few more ElseIF statements to return 1 or more objects and then changing the main part of the script to walk through each folder returned by the GetFolder() function I was able to work around the issue

  26. Ben Warner says:

    Hi,

    Is it possible to move a user mailbox folder to a public folder using Powershell?

    Thanks,

    Ben Warner

    jbw@cinci.rr.com

  27. Chris Low says:

    I'm actually looking for something similar that can be run server sided moving/copying folders between mailboxes.

    right now I have to open outlook and then do a move which ties up my outlook in the interim.

    i'm basically consolidating/splitting journal archives (between old/new exchange systems). dealing in about 160gb of emails per year.

  28. Daryl Schneider says:

    I am having issue with this line of code: $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot);

    It says the request failed. The underlying connection was closed.

    Then the next line tries to execute a method on that variable which after the previous line is null and fails stating cant call a method on a null valued expression. Can someone explain why the first line of code fails to bind to the mailbox? Im calling it with valid credentials

  29. Joe Reinheimer says:

    I love this script and can see it being very useful. How would I go about only moving subfolders? For example, I want to only move subfolders and items under the inbox but not touch the inbox itself.

  30. Kumar says:

    Hi,

    I still get the below error, any advice?

    WARNING: Ignoring any SSL certificate errors

    Exception calling "Bind" with "2" argument(s): "The request failed. The underlying connection was closed: An unexpected

    error occurred on a send."

    At C:tempScriptsMoveItems.ps1:257 char:66

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($service, [Microsoft.Exchange.WebServices.Dat

    a.WellKnownFolderName]::MsgFolderRoot);

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.

    At C:tempScriptsMoveItems.ps1:169 char:41

    +                 $FolderResults = $Folder.FindFolders <<<< ($SearchFilter, $View);

       + CategoryInfo          : InvalidOperation: (FindFolders:String) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

    Failed to find  Inbox

    Requested folder path:  Inbox

  31. The "Unexpected error occurred on a send" is due to an issue with PowerShell, the EWS Managed API and self-signed certificates, as far as I am aware.  Unfortunately, I do not know of a workaround at present (except to used fully trusted certificates, OR use the Managed API 1.1 which appears not to have this issue).  I have also encountered the issue sporadically in my lab environment.

    Also, Glen Scales' solution as outlined in a previous comment can work – though in my tests it can also be hit and miss (it worked the first time I encountered the problem, but subsequently didn't help).  In my lab environment, if I hit the issue (which is sporadic) then I usually use the managed API 1.1 until the problem disappears again (often after a server restart).

  32. >> How would I go about only moving subfolders?

    Just ensure that the folder parameters are specified correctly.  They take a full path, so you can specify a nested folder and all folders above it will be left alone.  Best idea would be to experiment on a test mailbox.

  33. ManojP says:

    Can we modify script to move mails from Inbox to sent folder for same user

  34. Alex says:

    Very interesting script.. I wish I had better PS skills to modify it to my needs.

    Our issue is related to retention in Ex 2013 — subfolders in Inbox/Sent are inheriting the retention of these folders — so really I want a script that will take all subfolders of the inbox and sent and move them to the root (and subfolders of those subfolders follow).

    This script looks like the beginning of what I need… any idea of what changes or tool could be used to do what I'm trying to accomplish?  I don't relish the though of trying to recommend to a user to do this manually when they have 200+ subfolders within their inbox.

  35. Don Tarczy says:

    We have need to copy all the subfolders of the inbox and their content to a new folder structure but leave the emails in the inbox root intact,, We don't know the names or how many folders  are under the inbox so we can't put in an individual path for each of the subs.

  36. Ricky says:

    Hi David,

    Great script – I'm trying to move items from Folder1Folder2<items & folders>

    The script moved them from Folder1Folder2 perfectly fine.

    -SourceFolder "folder1" -TargetFolder ""

    So now the structure is

    Folder2<items & folders>

    But if I do move the <items & folders> to

    If I do

    -SourceFolder "Folder" -TargetFolder ""

    The script does;

    Moving from Folder2<folder> to  Folder2<folder>

    Any ideas what I'm doing wrong?

    Cheers.

  37. Ricky says:

    Worked it out – it was due to the naming of the folder – the export tool I used orignally named things "Top of Information Store".

    I had to use -SourceFolder "Top of Information Store" rather than just "Top of Information Store"

  38. Dan J says:

    David, could you clarify the permissions needed when moving folders in O365. Do I need to grant full mailbox access if I'm using admin type account to move folders in other users mailboxes

    Thanks

  39. Jerry Cote says:

    You rock!  Thank you for this excellent script

  40. Spiro R. says:

    As someone requested. What would be the script to move a folder from one mailbox to another mailbox?

    I know it can be done with Public Folder but what about normal maibox folder?

    Tx in advance

  41. ekummel says:

    Two questions.

    1) can this script be embedded in a import-csv command? I want to act upon a bunch of mailboxes. I'm trying to manage a bunch of journaled folders.

    2) on line 36, you state [string]$EWSManagedApiPath = "C:Program FilesMicrosoftExchangeWeb Services1.2Microsoft.Exchange.WebServices.dll",

    I cannot seem to find this path on any of my Exchange servers. I'm running Exchange 2010 SP3.

    Any idea where this DLL resides?

  42. Ed says:

    I am looking at this script as a means to manage the 100,000 item limit for folders in Exchange 2010. I want to move messages out of the inbox into subfolders broken down by month.

    Looking at the script you created I see on line 36, there is a reference to a DLL, Microsoft.Exchange.WebServices.dll. You show this DLL to be in the "C:Program FilesMicrosoftExchangeWeb Services1.2 folder.

    I am running Exchange 2010 and I cannot find this folder on either my CAS or my Mailbox servers. Can you tell me where this file exists? And on what server?

    Thanks

  43. The dll is the EWS Managed API, which is a separate download.  Search the download site for Exchange Web Services Managed API (the current version is 2.2).

    You can use Import-CSV and then pipe parameters to this script, details are on another blog post here (not sure which one).

    When I get a chance to post it, I have a new script that replaces this one and has enhanced functionality – I'll try to get it posted this month.

  44. SimonPewPew says:

    Hi there,

    Ran a mail import, dropped into InboxSubFolderInPrimary (Because im retarded). I can't seem to get the script going for Exchange 2013.  Should it work?

  45. Erwin says:

    For some reason the script only takes well known folders as source input. If I try to move messages from custom made folders the script says the folder cannot be found. If I try a well known folder, like Journal or Inbox it works. Any idea why this is?

  46. This script should work with Exchange 2013, yes.  What error are you hitting?

    For custom folders, you'll need to specify the full path of the folder (e.g. InboxFolder1, Folder2).

  47. Erwin says:

    I have a custom folder called 'test' in the root, next to Inbox,Journal, etc.. With EWSEditor I can see this folder under

    MsgFolderRootTop of Information Storetest. When I try your script even with full path "test", the script says:

    Failed to find  test

    Requested folder path:  test

    I'm very sure this folder exists. When I try a well known folder it is able to find it.

  48. andrew says:

    Two questions.

    1) I get this error

    Exception calling "Bind" with "2" argument(s): "The response received from the

    service didn't contain valid XML."

    At C:usersalindzondownloadsmoveitemsMoveItems.ps1:320 char:66

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($serv

    ice, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot);

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.

    At C:usersalindzondownloadsmoveitemsMoveItems.ps1:238 char:41

    +                 $FolderResults = $Folder.FindFolders <<<< ($SearchFilter, $Vi

    ew);

       + CategoryInfo          : InvalidOperation: (FindFolders:String) [], Runti

      meException

       + FullyQualifiedErrorId : InvokeMethodOnNull

    Failed to find  Inbox

    Requested folder path:  InboxCustomers

    I am using these paramters  -SourceFolder "InboxCustomers" -TargetFolder "InboxCust"

    I am just trying to do a simple test, before i figure out how to do the real job i intend.

    2)  How hard would it be to add a date range filter?  My objective is to move messages in a specific range from one folder in Office365 online archive to another

  49. Kyle says:

    I am trying to run this on some Office 365 mailboxes and am having some issues. Any thoughts here.

    The command I enter: > .MoveItems.ps1 -Mailbox test@contoso.com -SourceFolder "Deleted Items" -TargetFolder "" -EWSUrl "outlook.office365.com/…/exchange.amsx" -ignoresslcertificate $true

    I receive the following errors:

    WARNING: Ignoring any SSL certificate errors

    Exception calling "Bind" with "2" argument(s): "The request failed. The remote server returned an error: (401)

    Unauthorized."

    At C:UserskrajcirDesktopMoveItemsMoveItems.ps1:320 char:1

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, [Mic …

    + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : ServiceRequestException

    You cannot call a method on a null-valued expression.

    At C:UserskrajcirDesktopMoveItemsMoveItems.ps1:238 char:5

    +                 $FolderResults = $Folder.FindFolders($SearchFilter, $View);

    +                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

       + CategoryInfo          : InvalidOperation: (:) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

    Failed to find  Deleted Items

    Requested folder path:  Deleted Items

  50. Ed K says:

    I am trying to test this script and have additional questions:

    When using impersonation. Can you give an example of when impersonation would be necessary?

    When using the -Domain flag, would this be in the format of "domain.com" or just "domain"? (note: my domain is a .gov domain"

    Additionally, I am attempting to run this script against disabled accounts (these are Journalled mailboxes, so don't want anybody logging onto them). I have given my username full permissions to the account in question. Would that be sufficient to run this script against?

    I am getting several errors when running this script using the following format:

    .MoveItems.ps1 -Mailbox Journaled_mailbox@domain.com -SourceFolder "Inbox" -TargetFolder "Inboxtest1" -ignoresslcertificate $true -Username "UserWithFUllPermissions" -Password "SomePassword" -LogVerbose $true -EwsURL "outlook.domain.com/…/exchange.asmx" -Domain "domain.com

    These are the errors I'm getting:

    WARNING: Ignoring any SSL certificate errors

    Exception calling "Bind" with "2" argument(s): "The request failed. The remote server returned an error: (401) Unauthor

    ized."

    At C:ScriptMoveItems2MoveItems.ps1:324 char:66

    + $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind <<<< ($service, [Microsoft.Exchange.WebServices.Dat

    a.WellKnownFolderName]::MsgFolderRoot);

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    You cannot call a method on a null-valued expression.

    At C:ScriptMoveItems2MoveItems.ps1:242 char:41

    +                 $FolderResults = $Folder.FindFolders <<<< ($SearchFilter, $View);

       + CategoryInfo          : InvalidOperation: (FindFolders:String) [], RuntimeException

       + FullyQualifiedErrorId : InvokeMethodOnNull

  51. I'd suggest using the updated script (blogs.msdn.com/…/powershell-merge-mailbox-folders.aspx) as it has been optimised significantly and supports multiple folders.  Domain should be whatever the domain used to authenticate with OWA is, but this isn't something I can really answer without knowing the environment.  One point I've noticed with E15, though, is that it seems to prefer the domain as part of the username (domainusername) instead of separately in the credentials – it may be worth trying that also.  Try logging on to your mailbox using EWSEditor – whatever credentials work there should work in this script.

  52. Curibe says:

    How can i do this for Archive Mailbox?

  53. Curibe: use the updated script linked at the top of the article, it supports archive mailboxes.

  54. Dimitri Goossens says:

    Hi,

    First of all, thanks a lot for the script!!

    I've made some changes so I'm able to move items from a specific folder called "archived emails" towards the root of the archive mailbox.

    It's working correctly, but running very very slow. (not even 1 item per second).

    Is there a way to throttle the moves?

    PS : I'm using impersonation with the EWS managed API 2.2

  55. This script is slow because it moves items one at a time.  Take a look at the new one linked at the beginning of the article – it sends the move request in batches of 500, which is significantly faster.

  56. Robert Winterton says:

    Hi David,

    I am trying to do something a little different, namely moving items from a public folder to a mailbox folder.

    So far I can get the public folder items like so:

    $Outlook=new-object -comobject "Outlook.Application";

    $mapi=$Outlook.getnamespace("mapi");

    $Messages = $mapi.Folders.Item("Public Folders – name").Folders.Item("All Public Folders").Folders.Item("folder1").Folders.Item("folder2").Folders.Item("folder3").items

    then I can get the destination mailbox folder using a greatly boiled down version of your script like so:

    TrustAllCerts

    [string]$EWSManagedApiPath = "C:Program Files (x86)MicrosoftExchangeWeb Services2.1Microsoft.Exchange.WebServices.dll"

    Add-Type -Path $EWSManagedApiPath

    $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService([Microsoft.Exchange.WebServices.Data.ExchangeVersion]::Exchange2010_SP1)

    $service.UseDefaultCredentials = $true;

    $service.AutodiscoverUrl("email-address", {$True})

    $MailboxRoot = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($service, [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot);

    $TargetFolder = "exchangetest"

    $TargetFolderObject = GetFolder($MailboxRoot, $TargetFolder)

    when I try to move the message like this:

    $messages.item(1).move($targetfolderobject.id)

    I get an error:

    move : Exception calling "Move" with "1" argument(s): "The operation failed."

    At line:1 char:23

    + $messages.item(1).move <<<< ($targetfolderobject)

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : ComMethodTargetInvocation

    Not sure if what I am trying is possible.  Any suggestions?

  57. Milan Gajic says:

    Great script. Took only a little change to adapt it for a export-preparation script for removing items of a certain ItemClass ("IPM.Note.EnterpriseVault.Shortcut" in this case).  

    A filtering option (by search), with an option not to create the target folder if there are no results would really make it complete.

  58. Thomas says:

    Great Script. Thanks.- Got one Question. I have to move about 60 Subfolders with about 40.000 Mails per Folder. When i start script it finishd well but not all moved from one Subfolder to Inbox. When i start again it moves the messages. It looks i have to start 5 Times for on Subfolder. Is there an Limit for moved Items? When yes can i disable it? Thanks.

  59. Jacques Venter says:

    This script looks like precisely what I need but when I run it the following error is produced,

    Exception calling “Bind” with “2” argument(s): “Exchange Server doesn’t support the requested version.”

    The version of Exchange in use is Exchange 2007 SP3

    Please advise how this could resolved?

Skip to main content