Just a quick post today on a recent script I had to put together.
The message trace feature within Exchange Online works pretty well but can be a challenge if you want to search based on a particular email subject. In a scenario where you want to know who received an email or a set of emails, you have to employ some tricks to be able to query large amounts of logs.
The script below allows you to search on a subject or variants of a subject going back X number of days. The output is logged to a CSV file showing the details of the trace log entry.
Some Influences…
Some of the code in this script was inspired by the example at “Praveen’s Blog“.
Using The Script
The script takes three command line switches and all are mandatory. The parameters are as follows:
Number of days back to search.
Subject
Subject of message to search.
OutputFile
Name of CSV file to populate with results.
In the scenario where you’re looking for something like a phishing campaign, you might know that the emails all come through with a unique but patterned subject. So you may have subjects like “Invoice TUINV65988 from Tip Top Delivery” and “Invoice HXINV44152 from Tip Top Delivery” where the only difference is the “invoice” number. Using the asterisk in your subject line will allow you to search for variants.
So using the following would search 5 days back for an email with the subject “*Invoice*Tip Top*” and save the results in c:\scripts\output.csv:
.\Get-MessageTraceBySubject.ps1 -Days 5 -Subject "*Invoice*Tip Top*"
During the query, which can take an extended amount of time, you can see in the progress bar what date range is currently being evaluated. Messages are evaluated in batches of 5,000 per query.
Limitations
The Get-MessageTrace cmdlet only returns a maximum of 5,000 results per query unless you use paging and then you can return up to 1,000 pages. So the theoretical limit on this query is 5,000,000 entries.
Download
The script for this post can be found in the Microsoft Script Center at the following link: Get-MessageTraceBySubject.ps1
Did you find this article helpful?
Leave a comment below or follow me on Twitter (@JoePalarchio) for additional posts and information on Office 365.
Looking to do some more reading on Office 365?
Catch up on my past articles here: Joe Palarchio.
Excellent script. Thanks for sharing!
Nice blog!! thanks for sharing this informative blog with us.
This is great in theory.
In practice, when you reach Page numbers around 200 you start getting massive errors and the search cannot continue.
“We cannot currently process your request, please wait a few minutes and try again.”
+ CategoryInfo : InvalidOperation: (:) [Get-MessageTrace], FfoReportingException
[FailureCategory=Cmdlet-FfoReportingException] E84BA170,Microsoft.Exchange.Management.FfoReporting.GetMessageTrace
GW-
How far back you were trying to search? I searched about 50 or so pages without issue before I ran out of entries; I’ll try and test with a larger data set.
Thanks
Joe
Thanks for sharing! One question though, I am in the UK and the script won’t work unless I change my date / time setting to US. Is there any adjustments I can make to the script or is this the only workaround?
Great script, however, my search results do not return emails that were sent within a few hours of when I ran the script. If I perform a message trace based on sender, the GUI returns results that the script does not.
We cannot currently process your request, please wait a few minutes and try again.
+ CategoryInfo : InvalidOperation: (:) [Get-MessageTrace], FfoReportingException
+ FullyQualifiedErrorId : [Server=***************,RequestId=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,TimeStamp=5/17/2017 7:45:06 AM] [FailureCategory=Cmdlet-FfoReportingException] EB574841,Microsoft.Exchange.Manage
ment.FfoReporting.GetMessageTrace
The above error bounced when the search result for 3 days exceeded 970000+
Here are some mods to include the spam diagnostics in the output.
$Messages | Where {$_.Subject -like $Subject} | %{
$mtd = $_ | Get-MessageTraceDetail | ?{$_.Event -eq “Spam Diagnostics”}
$data = [xml] $mtd.Data
$_ | Add-Member -MemberType NoteProperty -Name “SpamDiagnostics” -Value $data.root.MEP.Blob
$Entries += $_ | Select Received,SenderAddress,RecipientAddress,Subject,Status,FromIP,Size,MessageId,SpamDiagnostics
}
$Entries | Export-Csv $OutputFile -NoTypeInformation -Append
.\Get-MessageTraceBySubject.ps1 : File C:\Users\geshak\Get-MessageTraceBySubject.ps1 cannot be loaded. The file
C:\Users\geshak\Get-MessageTraceBySubject.ps1 is not digitally signed. You cannot run this script on the current
system. For more information about running scripts and setting execution policy, see about_Execution_Policies at
http://go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
Regarding Time/Date issues with location settings (US vs UK, etc..)
[DateTime]$DateEnd = (get-date).ToString(“MM””/””dd””/””yyyy”)
[DateTime]$DateStart = (get-date).AddDays($Days * -1).ToString(“MM””/””dd””/””yyyy”)
Hi Joe,
like Victor Solis wrote. It doesn’t work exactly.
I tried to search:
$Subject = “*Bezpečnostné*” … or… $Subject = “Bezpečnostné*” but it find nothing. When I use sender address not subject, i will find all messages.
The counter in the last Write-Host line is outputting “0 Entries” upon completion; doesn’t look like the $FoundCount variable is incrementing properly. Is it incrementing properly for anyone else?
Any chance to re-upload the script somewhere ?
We’ll be soon 2024 and Exchange Admin still doesn’t have the feature.