Saturday, September 1, 2018

Exchange 2016 Recover Deleted Items To Original Folder Script

I recently had a huge issue in my Exchange environment where a retention policy went haywire and wiped mail from all User Mailboxes in the organization.

Backstory: We migrated from Notes last year, and the legal department wanted to institute retention policies moving to Exchange. I (stupidly) let another admin tag those migrated messages with an EWS script (which BTW, I said from the beginning isn't the best way to do it, and of course no one listens me) but they did it anyway. Fast-forward a year later, and the tag from that script got removed because it was named "test" and Exchange never threw a warning saying that it was applied to any mailboxes, which un-tagged all mailboxes, which deleted years worth of mail. Yippee.

So I desperately needed a way to get those messages back; preferably to their original folders, in bulk, without manually going to each mailbox to recover items from the Recoverable Items folder (aka the dumpster).

Exchange on-prem doesn't have this capability (it should, Microsoft are you listening?) so I scoured the webs and finally found a solution! An EWS script that moves items from the Recoverable Items folder back to the original folder they were deleted from.

***Starting with Exchange 2016 CU1, items are stamped with a LastActiveParentEntryID (LAPEID) attribute, but it couldn't be utilized until CU6; and it can only be accessed from OWA, not from Outlook, not from PowerShell.

Credit goes to Scott at flobee.net, who wrote an AMAZING script that ports the Restore-RecoverableItems from O365 to on-prem (again, this should be available in the first place, not everyone wants to, or even can move to O365, Microsoft).

The original script can be found here

The problem is: it did not work all the way; running with more than one parameter, caused the script to result in no output.

What I mean is: if I ran the script with the "-FilterStartTime" and "-FilterEndTime" or "-FilterStartTime" and "-FilterItemType" it wouldn't do anything...I could only use one of those parameters.

So, I edited the script to use AQS (Advanced Query Syntax) and hardcoded a date range so it will run successfully.

Saving The Script:

Grab the RecoverableItemsAQS.psm1 from my Google Drive here.

**Note** It's a .psm1 file. That's a PowerShell module that you need to import into your PowerShell session, which I'll show you later.

Open the script in Notepad and search for AQS and change the date range in the following block; you'll need to do this in both the Get-MailboxRecoverableItems and Restore-RecoverableItems sections:

  $AQS = 'received:4/22/2015..6/7/2017'

Edit the date range to fit your needs.

Also, change the page size in both sections to 1000; the default is 50.

Search for:

$pageSize = 50

You will also need the EWS API 2.2 installed on the machine where you'll be running the script from. Best is to install this on a non-Exchange server as it can cause some serious performance issues on Exchange - see my previous post for those issues.

Running The Script:

After you've made the above changes, save the script somewhere like C:\Scripts

There are two functions of the script: Get Recoverable Items, and Restore Recoverable Items.

**Note** You cannot pipe the Get function into the Recover Function, it is only for reporting.

Get Recoverable Items:

**We're going to be using Impersonation to run against mailboxes. This is easier and more secure than setting Full Access on a bunch of mailboxes. You'll need to pass the credentials into the script for the account that has impersonate rights to run both Get and Recover.

To set up impersonation follow this TechNet guide.

In the EMS, run:

Import-Module "C:\Scripts\RecoverableItemsAQS.psm1"

Then to get a list of items in the dumpster output to a txt file, run:

Get-MailboxRecoverableItems -Identity staceybranham@exchangeitup.com -UseImpersonation -Credential (Get-Credential) | Out-File c:\temp\staceydeletions.txt

**Note** The -UseImpersonation and -Credential (Get-Credential) parameters are for your impersonation account you set up earlier. You'll be prompted with a Widows cred prompt.

Restore Recoverable Items For A Single User:

In the EMS, run:

Import-Module "C:\Scripts\RecoverableItemsAQS.psm1"

Next run the following to recover on a single mailbox:

Restore-MailboxRecoverableItems -Identity staceybranham@exchangeitup.com -UseImpersonation  -Credential (Get-Credential)

Restore Recoverable Items In Bulk:

To run the recovery on a multiple mailboxes, we'll pipe in a CSV list of email addresses, and run the script against each of those.

Create your CSV where the heading is SMTPAddress, then each user's email address on each row like so:


Save it as MailboxImport.csv somewhere like C:\Scripts.

Next in the EMS, run:

$cred = get-credential

**Note** These creds will be the account you're using that has Impersonation Rights

Then, run:

$mailboxes = Import-CSV "C:\Script\MailboxImport.csv"; $mailboxes | foreach {Restore-MailboxRecoverableItems -Identity $_.SMTPAddress -UseImpersonation -Credential $cred}

Use caution when running the script on a bunch of mailboxes at one time, because it generates transaction logs, just as regular mail-flow does.

Test with groups of mailboxes to see how big your log volumes are growing before you run the script on a large batch. In my experience, recovering ~9GB of deleted items generated 1 to 1.5GB of logs.

My advice is to split up your Import CSVs into 10-20 mailboxes per day (or per backup cycle) so the logs will truncate in between runs -or- stagger the groups of mailboxes which are homed on different DB's...say 2 or 3 mailboxes per DB in each list.


  1. Hi,

    is it possible to use RecoverableItems cmdlet with Archive mailboxes in Exchange Online to Restore to Original Locations

    1. The native Restore-RecoverableItems doesn't support Archive Mailboxes, but the module in this post does. However, because of the way EWS works, it can only restore items to the user's Primary Mailbox.

  2. This script is excellent to recover archive dumpster to primary. Any tips to speed up this process for bulk mailboxes around 2000+ in O365? I see that 1 mailbox with 2GB archive dumpster takes around 5 hours to recover. Thanks.

    1. You might play around with the EWS throttling and see if you can bump it up...I'm not entirely sure, as I had to split my restores into batches - mainly for log growth since mine is on-prem.

  3. Thanks Stacey. Disabled EWS throttling in EXO and running batches of ~50 in different powershell sessions. Hopefully it makes things faster.