A question from a reader is often a good start to a useful discussion or to probe into a topic. Tim Read contacted me to discuss some problems he had with using the Search-Mailbox cmdlet (available in cloud and on-premises versions of Exchange). In this case, he was using Exchange 2013 CU5 and wanted to be able to search mailboxes for items that matched specific values for the sender, date, and subject attributes.
Apparently it was easy enough to run a search that found items that matched a combination of sender and subject but things got a little tricky when a date was thrown into the mix and not much joy was extracted from examples found on various sites.
Parser errors were reported when a date was specified, which indicated that the date was in a format unacceptable to Search-Mailbox. Some confusion arose on this point as it is natural to assume that search criteria have to be stated in KQL syntax because this is what is used by the Search Foundation, which provides the indexes that Exchange interrogates to perform mailbox searches.
However, the Search Foundation was only introduced in Exchange 2013 and code written for Exchange 2010 has to continue working on Exchange 2013 or in Office 365. The cmdlet therefore masks the change that occurred in the underlying search engines. Dates should be formatted like any other date consumed by Exchange according to the locale installed on the server. So 1 October 2014 is “1/10/1014” in Ireland or the U.K. or “10/1/2014” in the U.S. Alternatively, you can pass a date like “14-Oct-2014” in either locale.
Now that we understand how to format dates, we can construct a Search-Mailbox command to do the work. This example creates a collection of mailbox objects from a database and searches them for items sent by a user called “Ben Andrews” (the SMTP email address for the user can also be used) on 13-Oct-2014 with “Interesting” in the message subject. Items in the Recoverable Items folder structure are included in the search.
Get-Mailbox –Database VIP –ResultSize Unlimited | Search-Mailbox -TargetMailbox AdminSearchMailbox -TargetFolder “Search Results” -SearchQuery {Subject:"Interesting" AND From:"Ben Andrews" AND Sent:"10/13/2014"} -LogOnly -LogLevel Full –SearchDumpster
This command will create a log of the discovered items in the target folder in the target mailbox. No items are copied unless the –LogOnly switch is removed. If the command is then rerun, Exchange creates a folder named after the searched mailbox and date and time in the target folder and copies the discovered items there, placing them in sub-folders corresponding to the folders in the source mailbox.
Search-Mailbox is often to remove unwanted items that arrive into user mailboxes. This is done by adding the –DeleteContent switch to a command. Clearly you should not rush into removing content from mailboxes until you are absolutely sure that your command targets the correct items, which is one good reason to run a command with the –LogOnly switch before proceeding to delete anything.
Exchange protects administrators against themselves by requiring those who want to delete content to possess the special “Mailbox Import Export” Role-Based Access Control (RBAC) role. As the role name implies, it is designed to allow administrative access to user mailbox data to import data from PSTs or export items to PSTs. In this instance, it’s used because deleting content is obviously something that should be controlled.
If your account does not hold the role, you won’t see the –DeleteContent switch or be able to use it with the Search-Mailbox cmdlet. You can either create a new RBAC role group containing the role and assign it to the appropriate users or add the role to an existing role group, which means that any user that is already part of the group will be able to use the switch. For instance, here’s how to add the role to the Organization Management role group, which is what I did for my Office 365 tenant.
New-ManagementRoleAssignment -Name "Import Export_Organization Management" -SecurityGroup "Organization Management" -Role "Mailbox Import Export"
You have to create a new EMS session to pick up the RBAC amendments because RBAC only evaluates a user’s permissions when EMS initializes. Once EMS is ready, I can run a command like this to remove the offending content.
Get-Mailbox –Database VIP –ResultSize Unlimited | Search-Mailbox -TargetMailbox AdminSearchMailbox -TargetFolder “Search Results” -SearchQuery {Subject:"Interesting" AND From:"Ben Andrews" AND Sent:"10/13/2014"} -DeleteContent -LogLevel Full –SearchDumpster
So there you are… A reader query that led to some interesting consideration of a very useful command and its various switches. Hopefully this will help others who struggle with similar challenges.
Follow Tony @12Knocksinna
Pingback: Weekly IT Newsletter – October 13-17, 2014 | Just a Lync Guy
Pingback: NeWay Technologies – Weekly Newsletter #117 – October 16, 2014 | NeWay
Pingback: NeWay Technologies – Weekly Newsletter #117 – October 17, 2014 | NeWay
How can you use a variable for say the subject? I’ve tried every which way but cannot get it to work when I insert a variable. It just returns nothing.
$subject =”interesting”
Get-Mailbox –Database VIP –ResultSize Unlimited | Search-Mailbox -TargetMailbox AdminSearchMailbox -TargetFolder “Search Results” -SearchQuery {Subject:”‘$subject'” AND From:”Ben Andrews” AND Sent:”10/13/2014″} -DeleteContent -LogLevel Full –SearchDumpster
.
running it without the variable returns the correct results, running it with the variable returns 0 results
I was able to run a search using a variable with:
Search-Mailbox -Id MailboxToSearch -TargetMailbox AdminSearchMailbox -TargetFolder “Search Results” -SearchQuery {Subject:$Subject -AND …}
Putting the variable inside quotes stopped PowerShell resolving its value.
Saved the day, thanks!
hi Rich,
I have the same issue for $subject variable inside searchquery. Tried all permutations and combinations with single quotes, double quotes, braces etc. No luck. Did you find a solution?
foreach ( $line in $info ) {
Search-mailbox -id $line.RecipientAddress -SearchQuery { “Subject:$($line.Subject)” } -TargetFolder Purge -TargetMailbox **** -LogLevel Full
}
Try using Invoke-Command. This code worked for me:
$Users = import-csv “C:\temp\people.csv”
ForEach ($i in $Users) {
$Search = “Subject: ” + $i.Subject
$Command = { Search-Mailbox -Identity $i.Name -SearchQuery $Search -TargetFolder Search -TargetMailbox CServices -LogLevel Full }
Invoke-Command -ScriptBlock $Command }
You should really try out Lookeen (www.lookeen.com). It is a great search outlook plugin that finds everything from text passages to dates or attachments in no time. Really handy tool. There is a 14 day full version trial so just try it out.
Disclaimer: I work for the developer of Lookeen
Lookeen is more for Outlook Mail Search. Can it sear Exchange MB Databases?
Lookeen depends on client-side indexes. If Outlook has fetched copies of items from Exchange mailboxes, they are included in the Lookeen indexes.
Tony,
Thanks for the article. Was just wondering if there’s an AQS keyword for the folder? And if so a syntax example would be killer. I’d like to use New-MailboxSearch to get estimates of items in specific folders (particularly Inbox & Sent Items) within given date ranges. Unfortunately there doesn’t seem to be an include/exclude folder parameter as there is with New-MailboxExportRequest.
Any information you can provide would be very appreciated. Thanks.
Steven
Unfortunately Exchange doesn’t seem to support the folder, foldername, or in keywords specified at http://msdn.microsoft.com/en-us/library/aa965711(v=vs.85).aspx. That’s rather unfortunate.
Great Article, had to use it today, works, but the date field cannot be in Quotes. You need to have Sent:01/15/2015 (Or Received:01/15/2015).
The date field can be in quotes. I just tested it again using Exchange Online and the date element of the search worked perfectly. Perhaps it’s the version that you used. Who knows!
I confirm that the date field in quotes won’t work in Exchange 2010, removing “” will do the trick.
In case others run across this post, I think it’s worth noting Exchange Online/2013 KQL instead of AQS. I am not sure if it would be the case or not, but this may be the issue. Also, I know that PowerShell 4.0 has several difference from previous versions as well.
Yep, Exchange 2013, SharePoint, Exchange Online, and the Compliance Center all use KQL. That’s why the query contained in the example is in KQL syntax. The older AQS syntax should be used for Exchange 2010. See https://msdn.microsoft.com/en-us/library/aa965711(v=vs.85).aspx
Pingback: Using PowerShell to Remove Specific Emails | Exchange Source Book
Reblogged this on Notes by Tom and commented:
I don’t usually Reblog posts, but I found this Search-Mailbox article from Tony Redmond and it’s better than what I would write myself. Enjoy!
Great. Thank you!. Any way to search for certain words in message header? Also any way to delete all messages under one folder?
What words do you want to find in the message header?
And there’s no way to limit Search-Mailbox to a particular folder. It processes everything in a mailbox… no matter what folder the items are in.
Thank you for answering! As to what I want to find in the message header – sometime the subject of the message is too broad. If I can search message header for originating server/application name then it would be more accurate. I don’t know if such parameter exists. Thanks again!
It doesn’t. Not as far as I know anyway…
Great Info Tony. I was wondering if it’s possible to run a search bassed on a Conversation ID or IntMsgID or ConversationIndex.
I don’t think so. http://blogs.technet.com/b/quentin/archive/2014/07/30/using-search-properties-and-operators-with-ediscovery.aspx is a great source of information about what can be used in searches (for Exchange 2013; Exchange 2010 uses different operators) and I don’t see them there.
Is there a way to modify the mail search to look for email from a specific sender prior to a certain date?
Thanks for the info.
What version of Exchange? With Exchange 2013 or Exchange Online you should be able to pass a date range to specify what you want. For example, -SearchQuery {Received:”01/01/2013..01/01/2015″}
I think I figured it out. Here is what I was able to come up with to do the search on Exchange 2010. This will only do the search and not copy the items or delete them. I thought I would share it back. Thank you for pointing me in the right direction.
Get-Mailbox -ResultSize unlimited | Search-Mailbox -SearchQuery “from:noreply@contoso.com and Received:> $(’01/01/2014′) and Received:< $('12/31/2014')" -TargetMailbox "searchresults@contoso.com" -TargetFolder "SearchResults" -LogOnly -loglevel full
Great. Thanks!
We ran this Search-Mailbox -identity username@contoso.com -searchquery {(Received:> 01/01/2015 and Received:< 01/03/2015)} -DeleteContent
Unfortunately it also picks up contacts, calendars tasks and notes. Essentially everything. Is there any way to delete just email and leave the rest alone? Thanks for the article.
What version of Exchange?
2010 Enterprise.
Hmmm… Exchange 2013 uses KQL, a different query language that might be able to do what you want. I’d have to do some testing to prove that… and I am on vacation right now so that’s not going to happen anytime soon!
Is it only possible to restrict the search by date? Or can we narrow the results even further by adding a time parameter? For instance, if I want to return a messages that were sent 07/01/2015 15:34. Is this possible?
http://blogs.technet.com/b/quentin/archive/2014/07/30/using-search-properties-and-operators-with-ediscovery.aspx is a pretty good cheat sheet for what’s possible with Exchange properties. It looks as if Read and Sent dates use the day only. KQL accommodates date and specific times, but perhaps not for Exchange. I have asked the question.
The answer is that even though KQL supports a DateTime data type for searches, the parser used by Exchange only uses the date value. So you can’t search for a specific date and time. Sorry!
Pingback: Removing on-hold items from Exchange and SharePoint: unsupported but doable | WebSetNet
Hi Tony. I am trying to search for the number of “Deleted Items” for a date range, in particular, the number and size of emails that were deleted more than 14 days ago. I DON’T need the information for the ‘recoverable items’, just what in the “Deleted Items” folder. I can’t seem to find anything to allow me to do this. Do you have any suggestions?
I am using a similar script on Exchange 2010 to locate number and size of “Sent” emails older than 13 months (395 days).
$today=(get-date).adddays(-395)
$users = (Get-Content C:\psscripts\CheckMailAge\valid_users.txt)
foreach ($user in $users){
write-host “Working on mailbox for ” $user
search-mailbox -identity $user -targetmailbox ‘Test User1’ -targetfolder ‘NBFCMailsent-395’ -searchquery “Sent:< $($today)" -logonly -loglevel full | select identity, displayname, database, ResultItemsCount, ResultItemsSize | ft -hidetableheaders DisplayName,Database,ResultItemsCount,ResultItemsSize | out-file -Append -NoClobber .\AllUsersSentItems-395Days.txt
}
Much appreciated!
Rob.
I don’t think you can confine Search-Mailbox to a specific folder. However, I am doing a little research to make sure that I am right.
I’ve confirmed that none of the Microsoft eDiscovery tools currently support a folder scope. They are considering doing something in the future, but nothing exists today. You could try doing something with Exchange Web Services (EWS) and program a search to meet your needs. https://blogs.msdn.microsoft.com/emeamsgdev/2013/06/25/powershell-search-mailbox-for-items-of-a-particular-message-class-itemclass/ provides some examples of how to use EWS in this manner.
Thanks Tony, I appreciate your responses. I’ll see what I can do with EWS.
RobM
Great article, thanks.
Is there a way to output the results, i.e. all messages with a certain subject?
Just the good stuff like sender, recipients, subject, attachments and so on?
Thanks,
Lars
No, the output for Search-Mailbox are the items exported to the target mailbox. There’s no way to get just a nicely formatted report. LogOnly gives you a log, but I suspect it’s not what you want…
Tony,
Is there anyway to seach for email with a certain MessageID instead of by subject? Thanks for the great article btw!
Sorry. I don’t think the message identifier can be used for searching. See https://msdn.microsoft.com/library/ee558911(v=office.15).aspx#kql_property_restriction_queries and (even better) https://blogs.technet.microsoft.com/quentin/2014/07/30/using-search-properties-and-operators-with-ediscovery/
Tony,
I need to search mailboxes for emails with a specific subject, and a from address but I only want to use the domain, not the email address for the from value. Is this possible?
Try a search query like ‘(Subject: “Some text”) AND (From: “*gmail.com”)’. I just tested it here and that syntax works against Exchange Online. It should also work against Exchange 2013 and Exchange 2016.
For those that find themselves on this thread and still get tripped up on this, there’s a better alternative now: PowerMapi (http://powermapi.com/cmdlets).
PowerMapi is a .NET compiled powershell module that provides direct access to MAPI.
For example, to get the results requested by the title of this post with PowerMapi:
import-module PowerMapiLoader
$sess=new-MapiSession OutlookProfileName
$inbox=get-MapiFolder $sess Inbox
$found=search-MapiItems $inbox “PR_SUBJECT -has redmond -and PR_MESSAGE_DELIVERY_TIME -btw 12/1/2016::1/1/2017”
In the above, which is hopefully simple to understand, the -btw operator is ‘between’. The search feature in PowerMapi is a “brute force” search meaning that it is not based on the limitations of MAPI’s ‘restriction’ structures (for those MAPI devs out there :). This means that the list of operators and how it works is more flexible and feature rich, including Regular Expression matching, courtesy of the .NET framework!
So, it’s possible to do something like: search-MapiItems $inbox “PR_SUBJECT -match regex pattern goes here -and attach(PR_ATTACH_FILENAME -match regex pattern here also)”
This will search for subjects AND attachment names!
YES!! Can this tool take action on items in the folder “Top of Information Store” and be done by an admin as opposed to MFCMapi requiring a profile using the user creds? I’m wanting to move items out of “Top of Information Store” and into an actual folder.
It’s possible, but it is mapi and still requires a profile.
The key to this is permissions up front. if you create a new user account in the domain/environment and either give it full access permission to all the mailboxes you want to open, or give this account Receive-As (and possibly Administer Information Store for system privilege) to the database(s) of the mailboxes, you can open the mailboxes you want from a single profile.
this would be done by the Open-MapiExchangeMailbox cmdlet.
once you get the reference to a user’s mailbox store, you can get the IPM_Subtree (aka “Top of Information Store”) quite easily and then get to any contents.
How do you stop a search-mailbox -deletecontent command from running if someone used the -force parameter?
CTRL/C or terminate the PowerShell session?
We’re looking to search for specific strings like CI or SP but all our testing has shown that eDiscovery on Exchange 2013 returns everything with ci or sp in it. Has anyone grappled with this and found a solution?
Pingback: Using Different Queries When Processing Multiple Mailboxes with Search-Mailbox - Office 365 for IT Pros
If I have a list of recipients, let´s say Mailx.txt I usually were doing a Get-Content Mails.txt | Search-Mailbox …….
now I do not why but the cmdlet runs and only runs the search on the last user of the mails.txt. How do I do to make the search to run on each of the addresses in that Mails.txt
$Contents = Get-Content Contents.txt
Foreach ($C in $Contents) {Write-Host “Now Processing” $C}
(Substitute the Search-Mailbox command for the Write-Host command shown in the example)
Tony,
I’m just an average user, and I’m trying to search my mailbox for emails sent to John Doe, or Jane Doe, or Jim Doe, but no one else. The problem I’m running into is excluding emails which are to one of those individuals, but also include anyone else.
(to:(”Doe, John” OR ”Doe, Jane” OR “Doe, Jim”) AND (NOT( NOT to:(”Doe, John” OR ”Doe, Jane” OR “Doe, Jim”))
Any help you can offer would be appreciated.
Pingback: 具有多个短语的Exchange 2013电子邮件搜索 - 实战宝典