How to Use Search-Mailbox to Remove Items from Multiple Mailboxes

Using Search-Mailbox with Variable Search Queries

Note: Search-Mailbox is due for deprecation on July 1, 2020. See this post for more information.

A reader query asked how to run the Search-Mailbox cmdlet against a set of mailboxes when you need to execute a different search against each mailbox. It’s easy to run a search against multiple mailboxes with the same search query, but things get complicated when you try to change the query each time. The Search-Mailbox cmdlet is a powerful way to search and remove items from multiple mailboxes, but many people seemed to encounter problems when using a variable with searches (see the comments on this post).

Invoking Script Blocks

The Invoke-Command cmdlet gives us a solution. This example reads in a set of mailboxes to process from a CSV file with two columns holding the alias for each mailbox and the search query to use. The code builds a search query from a word or phrase found in the subject (enclosed in double quotes to allow spaces to be included) and a start and end date (if included in the input file). This information is used to create a variable holding the complete search command.

After the search query is prepared, we call Invoke-Command to process the Search-Mailbox command including the variable in a script block.

$Users = import-csv "C:\temp\people.csv"
CLS
ForEach ($i in $Users) {
   $Search = 'Subject: "' + $i.Subject + '"'
   If ($i.StartDate -ne $Null -and $i.EndDate -ne $Null) {
      $Search = $Search + ' Received:"' + $i.Startdate + '..'+ $i.Enddate + '"'}
   $Command = { Search-Mailbox -Identity $i.Name -SearchQuery $Search -TargetFolder Search -TargetMailbox CServices -LogLevel Full }
   Write-Host "Searching" $i.Name "using query" $Search
   Invoke-Command -ScriptBlock $Command 
} #End ForEach

The search query can obviously be much more complex than a simple text phrase. The key thing is to build the query up with whatever values are needed before sending it to Invoke-Command. Obviously you can end up with a complex script with many if then else blocks to test for different conditions, but it shouldn’t take too much time to create.

Removing Content

To remove the found content, simply add the DeleteContent switch to the command. Be careful because it is terrifically easy to make a mistake with a search query and end up removing far more information than you expect.

Tested Online

I’ve tested the code above with Exchange Online. I did not test it with an on-premises server. However, the Search-Mailbox cmdlet hasn’t changed all that much since Exchange 2010, so the code should work for on-premises organizations.


For more information about using the Search-Mailbox cmdlet, read Chapter 6 of the Office 365 for IT Pros eBook.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.