[Update]: This blog post was updated on April 24 2024.
Applies to: Exchange Online (New-ComplianceSearch, since Search-Mailbox has been effectively retired from Microsoft 365), Exchange 2019, Exchange 2016, Exchange 2013. Some information may also apply to Exchange 2010. However, if you’re really using Exchange 2010 right now, it’s high time to migrate.
The -SearchQuery
parameter available in the Search-Mailbox allows you to filter items stored in Exchange mailboxes using a set of item attributes and properties. The -ContentMatchQuery
parameter in the New-ComplianceSearch command allows you to filter items stored in Exchange mailboxes, SharePoint and public folders.
Since it’s quite hard to find any documentation regarding attributes that can be used with the -SearchQuery
and -ContentMatchQuery
parameters, I decided to create my own list.
Note: In Exchange Online, the Search-Mailbox
cmdlet was deprecated in favor of *ComplianceSearch cmdlets. Learn how to use the new version of Search-Mailbox to search and delete mailbox content in Exchange Online, Exchange 2019 and Exchange 2016
Unfortunately, not all properties indexed by Exchange search are available (but there are a few extra ones that may come in handy).
Queryable attributes and values
Attribute | Value type | Description | Example |
---|---|---|---|
subject | String | Exact phrases or keywords in subjects of items. | subject:”invoice for” |
body | String | Any item property that contains the specified string value. | body:microsoft |
attachment | String | Exact phrases or keywords in attachment filenames. | attachment:specialoffer.zip |
to | String | SMTP address, display name, or alias of user in TO field. | to:”George Kaplan” |
from | String | As above for the FROM field. | from:[email protected] |
cc | String | As above for the CC field. | cc:kowalski +codetwo.com |
bcc | String | As above for the BCC field. | bcc:harry lime |
participants | String | As above for all people fields. | participants:administrator |
category | String | Names or parts of names of default Outlook categories. | category:category -green |
importance | String | Available values: normal, high, low. Default is “normal”. | importance: high OR low |
kind | Item type | Available values: – contacts – docs – faxes – im – journals – meetings – notes – posts – rssfeeds – tasks – voicemail | kind:email OR contacts |
sent | Date | Specific date or time range in which the item was sent. Format: MM/dd/yyyy or date interval (today, yesterday, this week, this month, last month, this year, last year) | sent:9/1/2014..9/1/2016 sent:”last month” |
received | Date | As above for when the item was received. | received>=1/1/2015 |
hasattachment | Boolean | True if item has at least 1 attachment. (only Exchange 2016 and Online) | hassattachment:true |
isflagged | Boolean | True if item is flagged. (only Exchange 2016 and Online) | isflagged:true |
isread | Boolean | True if item is read. (only Exchange 2016 and Online) | isread:false |
size | Number | Size of item (including attachments) in bytes. | size>1000000 |
Operations on multiple attributes and values
Search-Mailbox
and New-ComplianceSearch
queries are performed using a slightly simplified version of Microsoft’s Keyword Query Language (KQL).
All attributes and their values listed in the table above can be combined using logical operators AND, OR and NOT (case sensitive).
Note: + / – can also be used as substitutes for AND/NOT.
For example:
Search-Mailbox -SearchQuery '(subject:"invoice for" -codetwo) AND (from:sales OR accounting)' ...
translates to: Search for items sent by people with “sales” or “accounting” in names or addresses, and the phrase “invoice for” in the Subject field, excluding those with the string “codetwo” in the Subject.
Numerical values (and date intervals!) can be compared using the following operators:
Operator | Attribute value … |
---|---|
: | … contains specified value (accepts numerical and text values). |
= | … is equal to specified value (accepts numerical and text values). |
> | … is larger than specified value. |
< | … is smaller than specified value. |
>= | … is larger than or equal to specified value. |
<= | … is smaller than or equal to specified value. |
<> | … is not equal to specified value. |
.. | … falls in the range of specified values (does not accept date intervals). |
Note: On Exchange 2010 you may have to precede comparison operators with a colon (:).
As I mentioned, date intervals (today, yesterday, this week, this month, last month, this year, last year) are interpreted as numerical values, but cannot be used with the ..
operator.
Dates can be provided in more than one format and seem to be region specific. While MM/dd/yyyy
format does seem to work fine, you can’t go wrong with YYYY-MM-DD.
Dates provided as MM/dd
are interpreted as MM/dd/current_year
.
For example:
Search-Mailbox -SearchQuery 'received="last month" AND received>03/10/2024' ...
translates to: items received between the 03/10/2024 and 03/31/2024 (since at the time of writing, last month was March).
Search-Mailbox -SearchQuery 'size:1000..900000' ...
translates to: items with size falling between 1000 and 900000 bytes.
If you have questions or comments about any of the above information, post them in the comments section. I will try to respond as soon as possible.
Hi, can I run this recursively on a specific mailbox?
I am running the below to delete all email address from the specific address only for the specific date and for a specific mailbox:
Get-Mailbox -id | Search-Mailbox -SearchQuery ‘from:”[email protected]” AND received=04/25/2023’ -DeleteContent -Force
however it only deletes 1 email from the mailbox
Normally, Search-Mailbox deletes all email that meet certain criteria. My first guess is that only one email met the criteria, but I assume you checked it.
You can try using the following date range Received:
04/25/2023 00:00:00..04/25/2023 23:59:00
or test different ranges with-EstimateResultsOnly
instead of-DeleteContent
to see how many results are returned.Hello,
Is there any way via Powershell to view the content of an email on a user’s mailbox?
Thanks
With the right permissions, Search-Mailbox with -TargetMailbox and -TargetFolder parameters lets you export chosen emails to another mailbox, so it gives you a kind of preview capability.
Heyy Guys ,
i am starter in Azure sentinel and KQL , can anyone please help me in posting query to see the logs of mails coming into the inbox.
OfficeActivity
|where RecordType contains “ExchangeItem”
|where UserId contains “Mailbox Name”
|where Operation contains “updated”
|where parse_json(tostring(parse_json(Item).parentfolder)).Path == “\\Inbox”
I tried with this and its not working . Would be greatful if you help me out
Hi Adam,
Is there a way to delete “contact list” items ?
This command only delete contacs and not “contact lists”
Search-Mailbox -Identity email -SearchQuery “kind:contacts” -DeleteContent
Thanks,
Alon
Hi Alon,
Unfortunately, Search-Mailbox doesn’t seem to be able to delete contact lists, just like it can’t delete mailbox folders. I’m afraid you can either delete those items manually, or use an EWS-based script (Microsoft’s website about deleting items with EWS)
Is there a way to search where the subject is equal to the SAMAccountName or other such account properties?
Yes, it is possible. One way to do this would be to use the following logic:
$jdoe = get-mailbox j.doe
Search-Mailbox $jdoe -EstimateResultOnly -SearchQuery subject:$jdoe.SAMAccountname
Of course, it makes more sense if used in a foreach loop, but the example above shows how to do it.
Hi,
I am running the following command tor try find emails with a persons name in it, but it is picking up words that also contain that name, like Ian being the name so Alliance is being picked up as well:
$AllDatabases = get-MailboxDatabase; ForEach ($DB in $AllDatabases) {$MBXBatch = get-mailbox -R
esultSize unlimited -Filter {RecipientTypeDetails -ne “DiscoveryMailbox”} -Database $DB ; $MBXBatch | Search-Mailbox -Ta
rgetMailbox ‘EMAIL ACCOUNT’ -TargetFolder ‘BODY’ -LogLevel full -SearchQuery “‘body:John Doe’ AND Received:01/01/2000..01/01/2100” -Verbose}
Am i missing something here to run this search in the email body? It is for Exchange 2016.
Thanks
A slight change in the SearchQuery syntax should do the trick:
-SearchQuery '(body:"John Doe") AND (Received:01/01/2000..01/01/2020)'
If some other names still pose a problem, think about how to rephrase your query to get less false-positives.
Try This
-SearchQuery ‘subject=”RE: this a bad email”‘
Hi Rohit,
Getting queries which include a colon is, indeed, a surprising experience. However, I found out that while
-SearchQuery "Subject='RE:test'"
does not return any results,-SearchQuery 'Subject="RE:test"'
works perfectly fine. Please make sure you are not missing or adding any spaces, change = to : and experiment with quotation marks to check if you can get the SearchQuery to work well.This actually does work
falls in the range of specified values (does not accept date intervals).
Received:”06/01/2016..06/09/2016″‘
Hi Paul,
Yes, in this form, the -SearchQuery works without any issues. In the article, I explain that you cannot use the .. operator with preset intervals like “today”, or “last week”. Which is quite logical, since “today” is already a date range.
Is it possible to delete a specific contact from a user/all users using powershell on Exchange 2016?
Ideally somthing like this (where John Doe is that contacts full name):
Search-Mailbox %USER% –SearchQuery kind:contacts name:John Doe –DeleteContent
Sorry, but the -SearchQuery does not offer advanced filtering when it comes to contacts – it is either all of them or none. So unless you want your users to rely solely on the contacts in the GAL and delete all of their local contacts, you will need to use another way.
You could, for example, use Remove-MailContact if the contact you wish to remove is external. The cmdlet will delete it from AD.
It depends on what you wish to accomplish, but you could also use mail flow rules to block messages sent to a specific address or use a smart unsubscribe mechanism.
I manage to delete Symantec EV email archiving stubs using loop through days one day at time to get around the 10000 limit of search mailbox.
for($iDay = $TESTDate_Start; $iDay -lt $TESTDate_End; $iDay = $iDay.AddDays(1)) {
Write-Host $iDay.ToString(“yyyy-MM-dd”) -BackgroundColor Green -ForegroundColor Black
$Day1 = $iDay.ToString(“yyyy-MM-dd”)
$SearchDateRange = “Sent:$Day1”
$MerssageClass = ‘”IPM.NOTE.EnterpriseVault.Shortcut”‘
$MailSearchQuery = “$MerssageClass AND ($SearchDateRange)”
$MailSearchQueryQuotationMarks = “`‘$($MailSearchQuery)`‘”
Write-Host $MailSearchQueryQuotationMarks -BackgroundColor DarkGreen -ForegroundColor White
Search-Mailbox -Identity CharmaineBl -SearchQuery $MailSearchQueryQuotationMarks -DeleteContent -Force
}
Nice job, thank you for sharing! It will help future readers who would like to delete those stubs.
Hi Adam,
thanks for the detailed article. I am looking for way to delete “IPM.Note.EnterpriseVault.Shortcut” between date range and leave these message before certain date. our new mail archiving solution only went in on day X in past and now i cannot delete the old stubs. Any suggestion how i can do this with search-mailbox ?
Thanks
Hi Juan,
The following Search Query should get this task done:
-SearchQuery ‘”IPM.Note.EnterpriseVault.Shortcut” AND (received:<start date>..<end date>)’
For more information on using the Search-Mailbox cmdlet to delete messages, please refer to How to delete email from mailboxes on Exchange 2016 / 2013 / 2010 / Online. It might be a good idea to use -EstimateResultOnly or -TargetMailbox and -TargetFolder attributes before actually deleting the results of this query.
Can you target a specific folder like the deleted items. I know you can search just the dumpster. but that doesn’t seem to include the deleted items folder.
I am afraid that the Search-Mailbox cmdlet does not let you limit searching to a specific folder. I must admit that this option would prove to be quite useful for many admins.
Has anyone been able to specify a time in the receive/sent fields?
If I do specify a date/time it will delete the message. If I specify a date:
receive=MM/DD/YYYY
receive<mm/dd/yyyy, AND receive<mm/dd/yyyy
it will not delete the message. If I do not put receive it works fine.
Hi James,
First thing, please make sure you are using the received filter, the receive will not work. Another problem is, I am not sure which date you try to specify, are you using all the filters at once? If you want to search only those items which were received at a certain date, the first filter should work without problems. You could also try to substitute the = operator with a colon. If you want to search items on a specified time range, please try using the following syntax:
received: mm/dd/yyyy..mm/dd/yyyy
. The AND operator should work too, but the more complex the query, the more chances you get that something will go wrong.Hi Adam,
This article is of great help.
I have one question. i need to search on the exchange 2010 archive mailbox on mails with subject content EG OR RM OR LU for all mails comes from [email protected] or [email protected] OR [email protected]
or sent to [email protected] or [email protected] OR [email protected] or cc [email protected] or [email protected] OR [email protected]
could you please help me
Hi Mina,
Search-Mailbox does not allow you to limit search only to Archives, but when it comes to the rest – you can easily query the database for the specified items:
First, push subjects and users to variables. As an example, I use $subjects to hold the specified subjects and $tousers and $fromusers for the addresses. Next, take a look at the syntax below. The script returns mailbox items from the selected addresses AND with the specified subjects (you can adjust the script to your needs):
$users = (Get-Mailbox);
$fromusers = ("[email protected]","[email protected]","[email protected]");
$tousers = ("[email protected]","[email protected]","[email protected]");
$subjects = ("EG","RM","LU");
foreach ($user in $users){
foreach ($subject in $subjects){
foreach ($fromuser in $fromusers){
Search-Mailbox -id $user -EstimateResultOnly -SearchQuery "(subject:$subject)AND(from:$fromuser)"}}}
Please remember to change the -EstimateResultOnly switch to -DeleteContent or -TargetMailbox and -TargetFolder, depending on your needs.
Also, mind that the script will take a while since the query is quite complex.
I am wondering if we could use search-mailbox to copy all items from the archive mailbox to the users production mailbox! Or should i follow the export to pst and then import pst procedure?
Thanks
Hi,
You could try it, but you might run into a problem. PowerShell throws an error if you try to use the same identity for both source and target mailbox in the Search-Mailbox cmdlet. What is more, Search-Mailbox only copies messages to the target folder, it does not put them into their original locations.
this does not work for Body
https://stackoverflow.com/questions/47686082/exchange-server-2013-search-mailbox-for-criteria-body-in-remote-powershell/47687417#47687417
Is it possible to search using the Modified date property on an e-mail in PowerShell?
Hi Yaniv,
No, the only date-related attributes available for e-mails are their sent and received date.
Thank you for a great article. Can I search for messages sent to and received from a certain domain using this query?
If so,
‘(to:*.xyz.com) AND (from:*.xyz.com)’
or
‘(to:xyz.com) AND (from:xyz.com)’
would be correct?
Hi Bill,
I would write the following query:
-SearchQuery: ‘to:”abc.com” AND from:”xyz.com” ’
the query will search all messages sent to domain abc.com ([email protected], [email protected]…) from domain xyz.com. If you use“*.xyz.com”
the query will search for messages sent from/to addresses which have an additional dot, like: [email protected]. The asterisk is expendable when put in front of a value or after it.Does search-mailbox command work with office 365 exchange online? I’ve archived info off for a mailbox and want to delete all emails before a certain date range. I keep hitting road blocks and getting errors that search-mailbox isn’t recognized as a cmdlet.
Hi Wendell,
Search-mailbox should work perfectly with Exchange Online. It looks like cmdlets have not been downloaded to the temporary module. Please make sure you have completed all steps necessary to connect to Office 365, because it seems you have not downloaded the cmdlets by using Import-PSSession $Session cmdlet. You can find all steps in How to start remote PowerShell session to Exchange or Office 365.
Exchange 2010, search-mailbox as Get-Mailbox | Search-Mailbox -SearchQuery Body:”Test” -TargetMailbox “Discovery Search Mailbox” -TargetFolder “Test-folder” -LogLevel Full
Results return with incorrect date and time in the sent and received field. It is one day ahead. For example, today is 5/11/2017 and I saw 5/12/2017
So, please help, greatly appreciate, thanks!
According to documentation provided by Microsoft, the dates returned by Search-Mailbox cmdlet are in UTC time (Coordinated Universal Time). Please check if the time and date are correct if you change your time to UTC.
Hi Adam,
I have used following command on exch 2010 to get count for specific message class
Search-Mailbox -Identity UserName -SearchQuery “IPM.NOTE.EnterpriseVault.Shortcut” –EstimateResultOnly
But, on exch 2013, same command, output is: ResultItemsCount: 0 even if there are
thousands of ev shorcuts in the mailbox.
how to use -searchquery option to find specific messageclass (ipm.note for example) on exchange 2013?
Thank you so much in advanced.
Rajesh
Hi Rajesh,
I’m sorry, but from what I know, Exchange 2013 does not support finding items with a specific message class with Search-Mailbox cmdlet. Some people say it’s an Exchange 2013 bug, but I haven’t found any official confirmation on the web.
Hi Adam,
Yes, i used the same command to search the mailbox. However i am getting the result of items received to mailbox within this particular time range. For Example, the conversations stored in conversation history, Sent Items etc,. But i expect only to show the emails RECEIVED (Which we can see when we do a mail trace) by the mailbox within that time range. How to achieve that? Thanks in advance for help again.
From what I found out, Search-mailbox does not have a default option to filter only the received emails (e.g. by limiting its search to Inbox folder). If I was to search a single mailbox, I would add e.g. AND to:”m.doe” to the query. For more mailboxes, I would use the same method and iterate through a list with a foreach loop.
Hi Adam,
This article is of great help.
I have one question.
We often get emails missing requests and mostly the query will be on data range. When i submit the search, it includes the other items as well. I am expecting only to find the items received on that particular time range. How we can achieve that?
Regards,
Suresh
Hi Suresh,
Let me show this on an example: The following cmdlet searches mailbox of m.doe on the date range from the January 1, 2017 up to April 14, 2017 and exports the results to Administrator mailbox, folder test search
‘Search-Mailbox “m.doe” –SearchQuery “Received:1/1/2017..04/14/2017” –TargetMailbox “Administrator” –TargetFolder “test search”
If you want to add more attributes, you can look at the examples in the article above
Hope it helps!
isread does not seem to be a valid attribute for Exchange 2013. Can you elaborate how you were able to determine that this attribute will work in Search-Mailbox -SearchQuery?
I’ve been trying to get a script to work with isread for quite some time and have hit many roadblocks.
Hi Dave,
Looks like you are right. I assumed Exchange 2013 would be identical as 2016 and 365, since they all use KQL (https://msdn.microsoft.com/library/ee558911(v=office.15).aspx).
Article already annotated.
Best regards,
Adam
How do search successfully with a subject that includes a colon? For example: I have an email I need to delete out of a mailbox with the following subject:
RE: this a bad email
Notice the colon. When I try to use search-mailbox, it returns zero results. I would assume this is because a colon something recognized by the query language and thus the search is not carried out correctly.
Hi Tom,
Please try using this syntax:
-SearchQuery 'subject=RE: this a bad email'
If it doesn’t work, please let me know what version of Exchange you are running.
Best regards,
Adam