Monday, August 3, 2020

Remove that mail from the mail server ASAP !

From time to time something happens in your Exchange environment that require a quick response on your part to remove Emails from user mailboxes.
This can be some sort of phishing Email that slipped in, or even a case where a user or a manager sends something by mistake to a large group or the entire organization with in a careless "Reply to all".

Those cases require you to remove that Email FAST !

The best way I know to respond to those deletion requests is by using Exchange's
Search-Mailbox Powershell cmdlet with a search query that match the item I want to locate and remove.
This command can be run with either the EstimateOnly switch which will generate a items count report of the objects found in a mailbox that match the query, or the DeleteContent switch that will actually delete the item(s). (Other options are also available when using this cmdlet)

This article is intended to assist you in two ways.
  1. Help you organize and test your item-to-delete search query.
  2. Help you locate and delete those mail items FAST in an environment containing multiple Exchange servers holding multiple databases by centrally creating a separate search and delete  Powershell job for every database.
Note!
If the distribution of the mail you want to remove is limited to a group of people you can use the search and remove commands to go over only and specific members of the group with a simple "foreach" on the group's members without searching every mailbox in the Exchange organization.

Permissions, Permissions, Permissions

In order to be able to use the search-mailbox cmdlet your user account will need to assigned the "Mailbox Import Export" role.
For more information about adding roles to role groups, see Add a role to a role group (https://docs.microsoft.com/Exchange/permissions/role-groups#add-a-role-to-a-role-group).

Getting the right command for the task

You will need to gather as much information as possible about the item you want to remove in order to create your search query to find the specific item and not delete anythings else.
Is it a mail item? a meeting? What is the exact subject? does it have a specific body content? what is the from email address? does it have an attachment? what is the attachment name? when was it sent?

You don't actually need all the information, but you need to have enough information to pinpoint the exact items using the search query.
I recommend you also ask for a specific mailbox which has a copy of the item you want to locate and remove so you can do a test run on it.

Here are some examples you can use:

This example will search a specific mailbox for the specific subject, from address and between date range and will provide a result on how many objects were found without deleting the items.

Search-Mailbox <USERNAME> -SearchQuery {Subject:"You Paypal account"},{sent:07/13/2020..07/15/2020},{from:scam@yahoo.com} -EstimateResultOnly

This example will search and delete the items in a specific mailbox which will match the query.
Search-Mailbox <USERNAME> -SearchQuery {subject:"Spam"},{body:"your credit card number"},{sent:07/14/2020..07/14/2020},{hassattachment:true} -Deletecontent -force   

Always try to use the "sent" option to limit the date range of the query it will save run time.

The following article can help you build your search query with more options:
https://www.codetwo.com/admins-blog/search-mailbox-exchange-2013-2016-online-attributes/

After a successful test run you can move on to running the command using your own foreach loop on a limited list of mailboxes or to using the following method to run the command on all mailboxes in all the mailbox databases.

Running the delete command on all mailbox databases

First I suggest to run this from your own admin desktop and not from the Exchange server.
Open regular Poweshell console as admin, replace the server name in the Uri with one of your Exchange server names in order to establish a remote session,
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri http://ExchangeServerName/PowerShell/
Import-PSSession $Session -DisableNameChecking

Get all mailbox database names and which server holds the copy.
(use a filter to remove databases you don't want to search)

$databases = get-mailboxdatabase | select Name,Server

*** Update the following command with your own SearchQuery

foreach ($d in $databases) {
start-job -Name "$($d.Name)" -ArgumentList ($D.Name),($d.Server) -ScriptBlock {
$Remoteserver = $Args[1]
$curi = "http://$($Remoteserver)/PowerShell/"
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $curi
Import-PSSession $Session -DisableNameChecking
$mbx = get-mailbox -Database $Args[0] -ResultSize Unlimited | select samaccountname
                # UPDATE THE NEXT COMMAND WITH YOUR OWN SEARCHQUERY
foreach ($m in $mbx) {
 Search-Mailbox $m.samaccountname -SearchQuery {subject:"Spam"},{sent:07/14/2020..07/14/2020},{from:spammer@yo.com} -Deletecontent -force
}
Remove-PSSession $Session
}
}


The above loop will create a "Job" for each database which will establish a remote session to the mailbox server where the database is located, will enumerate the mailboxes in the database, run the search and delete process on each mailbox and when finished will move the remote session.

On your admin console you can run the following Powershell command to see the remote job status
Get-Job

After a job completes you can see a specific job output with the following command:
Receive-Job <JobName>

After all jobs complete you can remove them with the following command:
Get-Job | Remove-Job