I’ve previously written about message tracking in Exchange Server as well as some tips on how to search message tracking logs using PowerShell.
In this article I will demonstrate a few different ways that you can specify time and date ranges for message tracking log searches. This is a useful technique because it can speed up your searches by minimizing the amount of log data that the search inspects.
As an example of this speed difference, here is the result of Get-MessageTrackingLog for all logs on a single server.
[PS] C:\>Measure-Command {Get-MessageTrackingLog -ResultSize Unlimited} TotalSeconds : 161.8412674
In contrast, here is a search of only the last 24 hours of message tracking logs.
[PS] C:\>Measure-Command {Get-MessageTrackingLog -Start (Get-Date).AddHours(-24) -ResultSize Unlimited} TotalSeconds : 8.235824
If you’re wondering about that “AddHours(-24)” bit don’t worry, we’ll get to that shortly.
You can see that in a very large environment you will save yourself a lot of time by knowing how to narrow your message tracking log searches with time and date ranges.
Get-MessageTrackingLog Time/Date Range Parameters
There are two parameters for specifying time and date ranges when running the Get-MessageTrackingLog cmdlet.
- -Start – the point in time to start returning log entries. If omitted the search will begin at the first entry of the oldest message tracking log file on the server.
- -End – the point in time to stop returning log entries, up to but not including the time/date specified. If omitted the search will end at the last entry of the latest message tracking log file on the server.
Both parameters accept values in the System.DateTime format, meaning mm/dd/yyyy hh:mm:ss. An example of a valid date would be “9/19/2012”.
Get-MessageTrackingLog -Start 9/19/2012
Another example would be “9/19/2012 13:00:00”. Quotes need to be used when specifying both a date and time.
Get-MessageTrackingLog -Start "9/19/2012 13:00:00"
Specifying Relative Time/Date Ranges using Get-Date
Often you will find yourself in situations where you want to search the logs for a period of time without having to work out the exact start or end time for the search.
For example, you may wish to search only the last hour of logs because somebody has asked you to help troubleshoot a lost email that they only sent within the last hour.
In these situations the Get-Date cmdlet can be used to provide relative time/date ranges. This is actually how I perform most of my own searches.
On its own Get-Date returns a DateTime object (and outputs a human-friendly version of it to your shell).
[PS] C:\>Get-Date Thursday, 20 September 2012 10:35:05 PM
We also get several methods that are of use to us in this situation.
[PS] C:\>get-date | Get-Member TypeName: System.DateTime Name MemberType Definition ---- ---------- ---------- Add Method System.DateTime Add(System.TimeSpan value) AddDays Method System.DateTime AddDays(double value) AddHours Method System.DateTime AddHours(double value) AddMilliseconds Method System.DateTime AddMilliseconds(double value) AddMinutes Method System.DateTime AddMinutes(double value) AddMonths Method System.DateTime AddMonths(int months) AddSeconds Method System.DateTime AddSeconds(double value) AddTicks Method System.DateTime AddTicks(long value) AddYears Method System.DateTime AddYears(int value)
I tend to use the AddHours and AddDays methods the most. Here is an example of Get-Date on its own, and then Get-Date using the AddHours method to subtract one hour.
[PS] C:\>Get-Date Thursday, 20 September 2012 10:35:05 PM [PS] C:\>(Get-Date).AddHours(-1) Thursday, 20 September 2012 9:35:18 PM
So now let’s combine that with the Get-MessageTrackingLog -Start parameter to search the message tracking logs only for the last hour.
Get-MessageTrackingLog -Start (Get-Date).AddHours(-1)
Pretty simple stuff right? So let’s look at some more examples.
Remember as we go through each of these examples that you may need to use “-ResultSize Unlimited” for searches that are expected to return more than 1000 results. As a general rule I use it on all searches just to save time.
Searching Message Tracking Logs for a Single Day
In this scenario you might be tempted to specify the same value as both the start and end date, but this will return an error.
[PS] C:\>Get-MessageTrackingLog -Start 9/17/2012 -End 9/17/2012 -ResultSize unlimited The search time range was incorrectly specified. The End and Start parameter values can't be the same. + CategoryInfo : InvalidArgument: (:) [], LocalizedException + FullyQualifiedErrorId : 7A353D3
The correct method is to specify the next day as the end date, remembering that the time/date value used for -End is excluded from the results.
[PS] C:\>Get-MessageTrackingLog -Start 9/17/2012 -End 9/18/2012 -ResultSize unlimited
In the above example only log entries occurring between 9/17/2012 00:00:00 and 9/17/2012 23:59:59 will be returned. Obviously another way of achieving that is to specify those exact hours/minutes/seconds in your search.
[PS] C:\>Get-MessageTrackingLog -Start "9/17/2012 00:00:00" -End "9/17/2012 23:59:59" -ResultSize unlimited
That is more typing for the exact same result, so you may as well stick to the more efficient method of simply specifying the date on its own.
Searching Between Two Specific Times/Dates
As a follow on from the previous example it should by now be clear that you can search between any precise start and end times.
Just remember that the hh:mm:ss can be either 24-hour time or AM/PM. If you do not specify AM/PM and enter an ambiguous time such as “11:59:59” then the time will be interpreted as AM.
For example, this will search to 11:59:59 PM.
[PS] C:\>Get-MessageTrackingLog -Start "9/17/2012 00:00:00" -End "9/17/2012 11:59:59 PM" -ResultSize unlimited
And this will search to 11:59:59 PM, because the time is specified using 24-hour format.
[PS] C:\>Get-MessageTrackingLog -Start "9/17/2012 00:00:00" -End "9/17/2012 23:59:59" -ResultSize unlimited
But this will search to 11:59:59 AM, because ambiguous times will default to AM.
[PS] C:\>Get-MessageTrackingLog -Start "9/17/2012 00:00:00" -End "9/17/2012 11:59:59" -ResultSize unlimited
Searching Between a Fixed and a Relative Time/Date Range
You may also wish to combine fixed and relative time/date values in your search.
For example, a search of all messages starting from noon on 17th September and ending 8 hours later.
[PS] C:\>Get-MessageTrackingLog -Start "9/17/2012 12:00:00" -End (Get-Date "17/9/2012 12:00:00").AddHours(8) -ResultSize unlimited
This may seem a bit of a strange example, but the reason I’m using it is to demonstrate one little gotcha with DateTime values.
On my server the regional settings as set to “English (Australia)” for time, meaning the format is dd/mm/yyyy instead of the US mm/dd/yyy.
This means that I need to use US format for Get-MessageTrackingLog, but Australian format for Get-Date.
But I can avoid this confusion and also save a little typing by capturing the start date in a variable first, that I can then re-use in my Get-MessageTrackingLog command, because once the DateTime object has been capture in a variable the regional settings become irrelevant and each cmdlet is able to interpret it correctly regardless.
[PS] C:\>$date = Get-Date "17/9/2012 12:00:00" [PS] C:\>Get-MessageTrackingLog -Start $date -End $date.AddHours(8) -ResultSize unlimited
This habit also gives you the advantage of a fixed point in time if you were running multiple searches moving through the logs hour by hour as I sometimes do.
[PS] C:\>Get-MessageTrackingLog -Start $date.AddHours(-2) -End $date.AddHours(-1) -ResultSize unlimited [PS] C:\>Get-MessageTrackingLog -Start $date.AddHours(-3) -End $date.AddHours(-2) -ResultSize unlimited [PS] C:\>Get-MessageTrackingLog -Start $date.AddHours(-4) -End $date.AddHours(-3) -ResultSize unlimited
Filtering Search Results using Where-Object
As a final example remember that a good practice is to capture your message tracking log search results into a variable so that you can quickly and easily filter those results down further without needing to re-run your search.
[PS] C:\>$msgs = Get-MessageTrackingLog -Start 9/17/2012 -End 9/18/2012 -ResultSize unlimited
You can then simply use Where-Object to return more specific time/date ranges from the data already captured in that variable, using the TimeStamp value.
For example, where in the previous command I collected all message tracking log entries for the 17th September, I can now filter that down to only those entries that were written between 14:00 and 14:05.
[PS] C:\>$msgs | Where-Object {$_.TimeStamp -gt "9/17/2012 14:00:00" -and $_.TimeStamp -lt "9/17/2012 14:05:00"}
When using comparison operators against DateTime values remember that -gt (greater than) means “after/later than” and -lt (less than) means “before/earlier than”.
Summary
As you can see when you become familiar with the use of time/date ranges you can perform very fast, very precise message tracking log searches on your Exchange Servers using PowerShell.
Hi Paul, how fined received mails last month, but in night time, for example 20:00 and 08:00 next day. Thanks
Pingback: Searching Message Tracking Logs by Sender or Recipient Email Address
Hi Paul,
I just wanted to say I have googled “exchange message tracking logs practical 365” many times over the years to get the date bit right, here I am again in 2022 =) …your Exchange info is invaluable, thank you for sharing!
If it helps anyone, adding | Out-GridView is a handy option, you can then copy/paste the raw data into Excel. A great way to sort and filter after the fact.
Get-MessageTrackingLog -Start (Get-Date).AddHours(-24) -ResultSize Unlimited | Out-GridView
Cheers 🍺
Simon
https://www.howdoiuseacomputer.com/
Thank you great article could you please help me changing the timestamp to yyyy/MM/DD
Dear Paul,
thx very much for this tutorial.
Is there any Chance you could also post the command for my topic:
find all mails (inbound or outbound) from date XXX to ZZZ “afterhours”. (time range 1800 ’til 0600).
If it is possible!
Thx
Kory
Hi Paul,
I have changed the path of message tracking logs from one drive to another drive on the same MBX exchange 2013 server. After changing the path I restarted transport service, it generated new tracking log files but old logs where not moved to the new location. So I manually copied all the logs and indexing folder from old location to new location and again restarted the server. Now I am able to do message tracking of old mails but when I put “-End” in message tracking command there is no result and when I remove -End from command I get the tracking events for old mails. For new mails after changing the path works fine. Unable to understand the issue. Please guide on this issue.
The Real Person!
Author Paul Cunningham acts as a real person and passed all tests against spambots. Anti-Spam by CleanTalk.
Without seeing the command you’re running I can’t offer any suggestions.
Hi Paul,
I checked by using below command
Get-MessageTrackingLog -Server -Start “4/5/2017” -End “4/6/2017”
But If I use Get-MessageTrackingLog -Server -Start “4/5/2017”, then it shows the proper output
When I include the Timestamp field in the format-table output, I often find that rows are out of order even though I am sorting the Timestamp field. They are apparently out of order because it is only resolving the time to hh:mm:ss, not hh:mm:ss.000 syntax. Is there a way to get the Timestamp column to show the latter syntax to get the rows in the correct order?
Pingback: About My Blog | sasda1
Paul,
I have a client that is asking me to show the number of time each of their Mail Contacts were “Sent To” in the past 6 months & 3 months. My thought was to pull all the recipient email addresses for a certain period of time and then compare this with their list of Contacts.
Do you know of a way to pull all the recipient addresses into a .csv file for a period of time?
I have to generate spam report with the message tracking logs, i am able to get the report with count, with per day but in the report i am not able to put the Date. can you help me in this.
I have ran below command.
Get-TransportServer -identity hub1 |Get-MessageTrackingLog -EventID send -Recipients spam@abc.com -Start (Get-Date).AddDays(-1) -End (Get-Date) -Resultsize unlimited | Group-Object ClientHostname
It is giving me below output.
Count Name Group
—– —- —–
125 Hub1 {Microsoft.Exchange.Management.TransportLogSearchTasks.MessageTrackingEvent,
i want in this report just Date which will give me the date, count, server.
Thanks in advance.
back in the days of exchange 2003, one did not have to bother with such scripting as message tracking was more user friendly – I still regret having to upgrade to 2010.
Why did 2010 developers decided to make things more difficult?
I agree, this is a really great article. I haven’t seen this much information in a while. I have been using time tracking software for a while. This seems like it will save a lot of time! Thanks so much for sharing.
Pingback: Tofa IT » Searching Message Tracking Logs by Email Subject
Great article, as always, Thanks Paul.
Only this morning I was playing with the MTL in 2010 and came up with the following which may be of help to others. It’s very basic, no error checking, but when saved as a .ps1 script, lets you grab the last x minutes of logs across all transport servers. The key issue I was trying to solve was that when searching multiple transport servers at the same time, you’d get all of the results from the first server, then all from the 2nd, etc.., which when you’re looking for a particular time, can be a pain. It isn’t pretty, and I probably wouldn’t use it where there are more than a couple of hub servers, but it works :
[PS] C:Scripts>.Get-MTLLastMins.ps1 15
#copy the rest to a script
param([int]$mins=60); #default to 60mins if no number added
Write-Host “Last $mins minutes of MessageTrackingLog across all Transport Servers.”
Get-TransportServer | Get-MessageTrackingLog -Start (Get-Date).AddMinutes(-$mins) -Resultsize unlimited | Select-Object TimeStamp,EventId,Source,@{Name=”MessageSubject”;Expression={($_.MessageSubject).substring(0,25)}},@{Name=”Sender”;Expression={($_.Sender).substring(0,30)}},@{Name=”ClientHost”;Expression={($_.ClientHostname).substring(0,14)}},@{Name=”ServerHost”;Expression={($_.ServerHostName)}},Recipients | Sort TimeStamp | ft
#end of script
Pingback: Tofa IT » How to Deal with SSL Requirements for Exchange when Certificate Authorities Won’t Issue You a Certificate
Thanks
interesting as always
very much appreciated Paul
Great article. this will save a lot of time.