A while ago I wrote the post Troubleshooting Exchange with LogParser:RCA logs, which describes how you can parse RCA logs using PowerShell and LogParser.
With the new protocol MAPI over HTTP also new kinds of logs were introduced. When it comes to connectivity or performance issues, those logs might help you to find the root cause.
Update 14.01.2017
Exchange 2016 CU4
In Exchange 2016 CU4 the location and the layout of these logs were changed. Before this build the logs could be found in $exinstall\Logging\MAPI Client Access and the total number of folders in $exinstall\Logging was 64
Note: The number is 66 as there are 64 folders and 2 items.
Once you’ve upgrade to Exchange 2016 CU4 the number increased to 70
and the location is moved to $exinstall\Logging\MapiHttp\Mailbox
As the layout changed, not all the queries could be run against these logs. ConcurrentConnections is not available anymore. In order to query MapiHttp logs of Exchange 2016 CU4 or later versions, just use the new switch E16CU4orLater.
How it works?
As the other scripts you need to fulfill the following prerequisites:
- LogParser
- a server from where you will run the script. This server needs SMB access to all Exchange servers as we will reach the MAPI Client Access logs via UNC path
- adjust the execution policy. Here is an example, which bypass the policy only for the running process:
Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass
- the script itself, which you can download here
The script will search for Exchange server within a given AD site, determines the installation path and search then in those paths for log files. There are several possibilities you can filter for (e.g.: servers, AD sites, dates, users).
The full list of parameters:
Parameter |
Description |
---|---|
UserID | a given mailbox, which you want to query the logs for. The last part from the LegacyExchangeDN is extracted for this e.g.:”/o=contoso/ou=Exchange Administrative Group (FYDIBOHF23SPDLT)/cn=Recipients/cn=Administrator37d” will be “Administrator37d”
Note: It doesn’t has to be the exact one! |
UserIDs | same as UserID, but it allows you to define multiple users comma separated |
StartDate | this is used for filtering the logfiles to be parsed. The default format is yyMMdd, but you can also use yyMMddHH.
Default: Current day |
EndDate | this is used for filtering the logfiles to be parsed. The default format is yyMMdd, but you can also use yyMMddHH.
Default: Current day |
LogParser | Define path to LogParser.exe.
Default: “${env:ProgramFiles(x86)}\Log Parser 2.2\LogParser.exe” |
ADsite | Search for Exchange servers in one or multiple sites. The default is the current site from the script is running. You can define multiple sites comma separated.
Default: The site of the machine you are running the script |
Outpath | Define where the CSV files will be stored. Default:”$env:temp” |
ConcurrentConnections | Switch to query number of concurrent connections within the given ConcurentIntervall |
ConcurrentIntervall | Define the interval of the query ConcurrentConnections in seconds.
Default: 900 seconds=15 minutes |
ClientReport | Creates a report of all unique user-agents and the number of hits for each. Note: This is NOT the unique number of users |
ErrorReport | Creates a report of all errors |
SpecifiedServers | Comma separated filter for only specified servers in an AD site |
E16CU4orLater | With Exchange 2016 CU4 the path and design of these log files have been changed. With this switch you can query these. |
Localpath | if you have log files in a local folder. There is no filtering by date! All files will be analyzed |
How does it looks like?
In this example I queried for my user. In this AD site only one DAG with 4 nodes exists:
.\Get-MAPIStats.ps1 -UserID Ingo -Outpath $env:USERPROFILE\Documents
The output is a CSV file, which you can import in your favorite editor or with PowerShell. As you can see there are a lot of details:
In the following example I analyzed the concurrent connections within 15 minutes for all users on those servers:
.\Get-MAPIStats.ps1 -ConcurrentConnections -Outpath $env:USERPROFILE\Documents
And here the output:
There was nothing bad, but as you might realized there is one mailbox with 196 concurrent connections. In general not a problem, but I’ve seen client with several thousands connections. There could be several reasons (e.g.: broken profile, Outlook Add-Ins), which cause this misbehaviour. When it comes to high number of misbehaving clients, it could be a severe performance issue for your servers.
To get a report about all logged errors run the following:
.\Get-MAPIStats.ps1 -ErrorReport -Outpath $env:USERPROFILE\Documents
The output is the same as in the first query, but the script search only for entries, where the failures field is not empty:
Filtering tips
For faster parsing I recommend to define a Start and EndDate including the hours you want to parse.
Example:
.\Get-MAPIStats.ps1 -UserID Ingo -StartDate 16111506 -EndDate 16111508
Also keep in mind that those logs are only written on the server, where the mailbox’ database is currently mounted.
Example:
.\Get-MAPIStats.ps1 -UserID Ingo -SpecifiedServers server1,server2
If you have a DAG with 16 servers and the users mailboxdatabase has 4 copies, you need to parse only the servers, which have a copy of this database. Why those 4 and not only the one where it’s currently active? You don’t know whether the database did a failover just before you checked where it’s mounted.
Happy parsing! I hope this helps and feedback is always more than welcome!
Ingo, thanks for sharing. Very helpful manual.
LikeLike
Hi Ingo,
There is a small error in your script regarding the selection of Exchange servers.
You have defined a filter on CAS and combined CAS/MBX, but it should be MBX and combined CAS/MBX.
There are no MAPI Client Access Logs on the Exchange 2013 CAS servers.
So:
[array]$Servers += GetExchServer -Role 16385,16439 -ADSites $ADSite
should be:
[array]$Servers += GetExchServer -Role 54,16439 -ADSites $ADSite
LikeLiked by 1 person
Hi Remko,
nice spot! You’re right. Anyways I’m currently updating the script to reflect the change in Exchange 2016 CU4. The updated version will be available in the next days.
Ciao,
Ingo
LikeLike
Hi Remko,
updated version is available.
Thanks again!
Ciao,
Ingo
LikeLike
Hello there,
Very useful script, curious if it is tried and tested with Exchange 2013?
LikeLike
Hi Michael,
actually I wrote the script when we migrated to Exchange 2013 and no Exchange 2016 was in production. Short answer: Yes. The game changed with Exchange 2016 CU4 as mentioned in my update, which created the need for an additional switch.
Ciao,
Ingo
LikeLike
Hey Ingo!
Great script, thanks!
I was trying to run it against a couple of Exchange 2016 servers (with CU4), but I keep getting this error:
PS C:\temp\logs> .\Get-MAPIStats.ps1 -E16CU4orLater
C:\temp\logs\Get-MAPIStats.ps1 : Parameter set cannot be resolved using the specified named parameters.
Any clue on what might be the problem? If I run the script without parameters, it gives me the “no server found!” error.
Thanks!
Cheers,
HN
LikeLike
Hey HN, is the server/computer you’re running the script in the same AD site like the Exchange servers?
LikeLike
Yes, it’s a small lab environment, with 2 Exchange 2016 boxes. It’s odd because I ran it on another lab with 2010, 2013 and 2016 machines, and it picked up the 2013 and 2016 without a problem.
I’ve also double checked the AD objects for the versions, role numbers, etc, and everything seems to be in order.
Thanks!
Cheers,
HN
LikeLike
And when you provide the AD site name? Maybe something wrong with this box. Make sure you’re logged on with a domain account and not with the local admin.
LikeLike
Hi Ingo!
So I finally had some time to do some more testing 🙂
It seems to be related to the position of the parameters.
I’ve tried a few combinations and here are the results:
Works:
get-mapistats.ps1 -E16CU4orLater -errorreport
get-mapistats.ps1 -E16CU4orLater -errorreport -outpath .\
get-mapistats.ps1 -E16CU4orLater -clientreport -outpath .\
get-mapistats.ps1 -E16CU4orLater -clientreport
Doesn’t Work:
get-mapistats.ps1 -E16CU4orLater
get-mapistats.ps1 -E16CU4orLater -outpath .\
get-mapistats.ps1 -E16CU4orLater -specifiedservers hggn-ex1
get-mapistats.ps1 -specifiedservers hggn-ex1 -e16cu4orlater
I hope this can help 🙂
Thanks!
Cheers,
HN
LikeLike
Hi HN, thanks for testing! The point is that this is on purpose. The switch -E16CU4orLater is intended to work only with User/Users or ErrorReport. The information to get the report for ConcurrentConnections is not available anymore in the logs. And I made a user or users mandatory to search for. Otherwise you would get all log entries. I enforced this with the ParameterSetName in the script.
Makes sense?
Ciao,
Ingo
LikeLike
Hey Ingo!
Ah I see, now it makes sense, yes!
Thanks for your help!
Cheers,
HN
LikeLike
Version: 42. LOL.
LikeLike
I think if have Exchange manager Tools installed. It is better to use Get-ExchangeServer to get all exchange servers.
LikeLike
well, but then you need to have it installed. Maybe you want to run it from a dedicated servers and LDAP is always much faster than Exchange…;-)
LikeLike
Why not leverage Remote Powershell and connect to an Exchange box to pull that data? 🙂
LikeLike
Have you every tried to parse several GB of log files with PowerShell? It takes ages and consumes a lot of memory. LogParser just runs through within a fractional amount of time. 🙂
LikeLike
Ah I see, but I meant just for the Get-ExchangeServer part, after that, you could drop the remote Powershell session and let LogParser do its magic 😀
LikeLike
Pingback: When iCloud breaks your Outlook | The clueless guy
Pingback: Outlook Cached Mode and TCP connections | The clueless guy
Hi Ingo,
I’m using this for the first time. I keep getting the error:
expecting FROM keyword instead of token ‘file.csv”
LikeLike
Hi Scotch, does the script find and show logs to be parsed?
Ciao,
Ingo
LikeLike
yes, it shows a lot.
LikeLike
If I do it with my Alias as userid, I get no errors, but shows Elements output: 0
I then tried to use the last part of the LegacyExchangeDN, then I get that error.
Start query!
Error: Syntax Error: : expecting FROM keyword instead of token ‘sco_Cervalis_11-54-44.csv’
LikeLike
Hi Scott, that’s interesting. Could you do me a favor and uncomment in the End block of the script the line and send me to rca[at]thecluelessguy.de the file? You can check. there are no information in the file. It’s only the query for LogParser. Also all parameter, which have been used.
Thx!
LikeLike
Hi Ingo,
I see a line at the bottom of the script with End, but I’m not sure what you want me to do. If you want you can email me directly.
LikeLike
I’m getting “No logs found!” when specifying StartDate/EndDate parameters for both yymmdd and yymmddhh formats. If this parameter is omitted, then logs for the day across all specified servers are found (EX2016 servers -E16CU4orLater parameter)
Any idea what could be the problem?
LikeLike
Hi Jimmy,
do you see the folder listed when using the Verbose switch? If so: Can the user, which runs the script access the folders via UNC path?
Ciao,
Ingo
LikeLike
Your scripts are amazing. I use several of them and they’ve really helped in troubleshooting issues. How could I modify any one of them so that I could use it to troubleshoot receive connectors? I’m trying to find/create a script that gathers receive connector logs from multiple servers, parse them for the specified IP address, and combine them into one CSV file that I can open in grid view.
Any suggestions on how to modify for this use would be appreciated.
LikeLike
Hey Phil,
thanks for the kind words. It all starts with a working Logparser query. Once you have this you can write a new script.
Ciao,
Ingo
LikeLike
Hi, we are in the middle of migration hundreds users to exch2016 and I would like to know who connect trough Outlook/owa for last day. Becasue I use another script to migration their mails I can not use lastlogon. This script is excelent and I know that all infomration is in the logs.
LikeLike
Hi Ingo
I wanted to try this script but the download isn’t available any more.
Can I find the script elsewhere?
Regards,
Manfred
LikeLike
Hi Manfred,
I’ll publish it to my GitHub repository. Once done I’ll update the links here. Next Monday is my target…
Ciao,
Ingo
LikeLike
Hi Ingo
This script sure seems interesting. Did you get a chance to update it to GitHub?
LikeLike
Hi Budakkan,
you can find the script now on GitHub:
https://github.com/IngoGege/Get-MAPIStats/blob/main/Get-MAPIStats.ps1
Ciao,
Ingo
LikeLike
Hi Ingo. Your script looks promising but no matter what parameter combinations I try it just gives me “No server found!” on a single Exchange 2016 instance. Get-AdSite cmdlet in management shell shows correct site name. I tried the -SpecifiedServers parameter but it’s the same. Am I missing something here?
LikeLike
I have the same issue, No server found!
LikeLike
Hi,
even with the latest version?
I expect that the script is running within the same ADSite of Exchange servers. If you are running it from different, please provide the name in the parameter ADSite. If omitted, the script will use the following logic:
([System.DirectoryServices.ActiveDirectory.ActiveDirectorySite]::GetComputerSite()).Name
Ciao,
Ingo
LikeLike
Hi Ingo,
Thank you for the script. I downloaded from here : https://github.com/IngoGege/Get-MAPIStats/blob/main/Get-MAPIStats.ps1
But i am getting no logs found! error.
[PS] C:\scripts>.\Get-MAPIStats.ps1 -ADSite sitename -UserID “username”-Outpath L:\output\ -Verbose
VERBOSE: Add ADSite AEU to filter!
Found the following Exchange servers:
SERVER1,SERVER2
No logs found!
C:\Program Files\Microsoft\Exchange Server\V15\Logging\MapiHttp\Mailbox in this directory there are logs. How to fix it?
LikeLike
now i am able to get log files using -Localpath parameter but now i got an error like this when i use -ErrorReport parameter
[PS] C:\scripts>.\Get-MAPIStats.ps1 -ADSite sitename -UserID “username” -ErrorReport -Outpath l:\output
C:\scripts\Get-MAPIStats.ps1 : Parameter set cannot be resolved using the specified named parameters.
At line:1 char:1
LikeLike
Hi,
which Exchange version do you have?
Ciao,
Ingo
LikeLike
Hi Ingo,
Now all is good with MapiStats.ps1 . I use Exchange 2016 with latest CU. But i am having issue with IISStats.ps1 if you could check my comment will be happy.
Thanks!
LikeLike
Any reason why this doesn’t work with EXH 2019?
LikeLike
Hi Daniel,
it’s on my backlog for 2019.
Ciao,
Ingo
LikeLike