I had recently been given the task to search all mailboxes in an Exchange 2013 on premises organization for a specific keyword phrase. Naturally I attempted to use the eDiscovery and Litigation hold feature of the EAC but was severely limited by the number of mailboxes I could search at one time. As always I’m looking for a way to automate time consuming tasks. The PowerShell cmdlet New-MailboxSearch also didn’t help much either. After submitting a new search I attempted to view the status and I get a Watson error.
Enter the older but tried and true Search-Mailbox cmdlet. It took me a while to figure out how to use the -SearchQuery switch though. I had checked through the documentation on how to do Exchange Search using the Advanced Query Syntax (AQS) but nothing was very clear on my problem.
I had attempted to search using a three letter phrase similar to this:
-SearchQuery "Your Bank Account"
When I used that search query in quotes I was getting email messages that contained any of the three words in any combination anywhere in the particular message. The secret sauce is to put the quoted phrase into single quotes. Then you will be only returning the exact phrase:
-SearchQuery '"Your Bank Account"'
With that settled I was running into a problem where PowerShell was getting overloaded from piping 10,000+ mailbox objects to the Search-Mailbox cmdlet. The query eventually failed. To get around that problem I decided to batch the mailboxes for search using an index range.
The trick is to set the start and end numbers of the index and then increment them by 999 as part of a Do Until loop. Finally, the Until loop ends things when the end range is greater that all the mailboxes held in the $MbxCount variable. I’ve added 1000 to the count just to be sure that the script doesn’t miss any mailbox objects.
It’s a short and sweet script that should be in your tool belt and will get the job done in an automated fashion. Just be prepared to deal with a bunch of incoming emails to your target folder.
# Get all mailboxes in organization.
$AllMbxs = Get-Mailbox -ResultSize unlimited
# Store the total count of mailboxs to ultimately limite the search.
$MbxCount = ($AllMbxs | measure).count
# Set the start and end range search in the array.
$StartRange = 0
$EndRange = 999
# Use a Do Until loop to chunk searches into 999 segments. Use search mailbox to query data.
## The quoted phrase must exist within single quotes to make an exact phrase match.
$AllMbxs[$StartRange .. $EndRange] | Search-Mailbox -SearchQuery '"health insurance marketplace"' `
-TargetMailbox firstname.lastname@example.org -targetfolder "Search" -LogLevel full -LogOnly
$StartRange = $StartRange + 1000
$EndRange = $EndRange + 1000
} Until ($EndRange -gt ($MbxCount + 1000))
Dealing With the Output
How do you deal with all the .csv files now in the target mailbox? Here is a really crafty trick that will save you a bunch of time. The more files you have accumulated the more time you’ll save. Save all the SearchResults.csv file to a new folder on your desktop or some other location. Open up the command prompt and navigate to the new folder and run this command:
copy *.csv AllSearches.csv
Now all the returned data is in one single .csv file and ready for import to Excel for all sorts of filtering.