Get-ActiveExchangeUsers 2.0

A while a go I wrote the initial script and post about it here. Due to my experience over the last few weeks and to meet additional requirements it was time to go over the script and extend its functionality. I thought about updating the previous post, but due to the major changes I decided to create this new post.

Update May 30, 2016:

Many thanks to fellow MCM/MCSM Thomas Stensitzki, who added some code for nicer format and preview when sending the output as e-mail:


Update November 11, 2018:

There is a new version available on GitHub. You can find the script and any new version here:

I added a bunch of new features and improvements:

  • UseASPDOTNET: As the Exchange performance counters are not reliable, you can now query IIS performance counters to gather current requests
  • IISMemoryUsage: This will gather the memory usage of the application pools (we had some issue with memory leaks).
  • UseCIM: As you’ll get only a generic name when you use IISMemoryUsage (performance counters doesn’t know any names of application pools), you can use CIM for gathering the data

Please read the Readme. I have also some posts queued to show the daily usage.

The script will query multiple performance counters from Exchange servers in a given AD site.

Default counter collection

MSExchange RpcClientAccess\User Count

Shows the number of users connected to the service.

MSExchange RpcClientAccess\Connection Count

Shows the total number of client connections maintained.

RPC/HTTP Proxy\Current Number of Unique Users

Shows the number of unique users currently connected to a back-end server via RPC/HTTP.

MSExchange OWA\Current Unique Users

Shows the number of unique users currently logged on to Outlook Web App. This value monitors the number of unique active user sessions, so that users are only removed from this counter after they log off or their session times out.

MSExchange ActiveSync\Current Requests

Shows the number of HTTP requests waiting to be assigned to a thread.

W3SVC_W3WP(*msexchangeservicesapppool)\Active Requests

Shows the number of active EWS requests.

MSExchange MapiHttp Emsmdb\Active User Count

Active User Count is the number of unique users that have shown some activity in the last 2 minutes.

MSExchange MapiHttp Emsmdb\Connection Count

Connection Count is the total number of client connections maintained.

W3SVC_W3WP(*MSExchangeMapiFront*)\Active Requests

Shows the number of active requests of the MSExchangeMapiFrontEndAppPool.

W3SVC_W3WP(*MSExchangeMapiMailbox*)\Active Requests

Shows the number of active requests of the MSExchangeMapiMailboxAppPool.

Web Service(_Total)\Current Connections

Shows the number of current total connections to the IIS.

Web Service(_Total)\Maximum Connections

Shows the max number of total connections to the IIS.

Netlogon(_Total)\Semaphore Timeouts

Shows the number of Semaphore Timeouts since the last start of the Netlogon service.

Most of those counters are described here and here. Why should you also have an eye on the Netlogon counter? If you have a larger environment and/or multiple forests you will agree that this is a good idea after you read this. In short: the counter should be always zero. If not you might have a bottleneck and consider to tweak MaxConcurrentAPI.

Updated version

As described above the script collects by default the performance counters previously mentioned. One of the major changes is that the format of the output is not anymore a formated list (Format-Table). It will return an object. It will also show the list of Exchange server found only when you use the common parameter -Verbose. Since the object has more than 10 properties and in case you want to use Format-Table or Format-List, you need to specify the parameter -Property * to get all properties. Personally I like Out-GridView.

Here how it looks like


Let’s have a closer look. Within this AD site you can see different versions and roles of Exchange:


When you look at the values for MAPI FE AppPool and MAPI BE AppPool you can see that the CAS role only have values for the FE, but not for the BE. And of course the Exchange 2010 CAS don’t have any values. I also added the ratio between the BE and FE. This is an important topic when it comes to fault tolerance and HA, but this will be topic of a different post.

Switch Summary

When you use the summary switch only a few main performance counters will be collected and summed up to a total number


The interesting part here is that the overall number of active requests reported for the MAPI application pools are almost equal. Why only almost? For instance think of those request on the FE component, which are not authenticated and never make it to the BE.

Switch -HTTPProxyAVGLatency

By using this switch the following counters will be collected:

MSExchange HttpProxy(autodiscover)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(eas)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(ecp)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(ews)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(mapi)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(oab)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(owa)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(owacalendar)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(powershell)\Average ClientAccess Server Processing Latency
MSExchange HttpProxy(rpchttp)\Average ClientAccess Server Processing Latency

All of those reflect the average latency (ms) of CAS processing time (does not include time spent proxying) over the last 200 requests.


As the HttpProxy component only exist on servers starting with version 2013 no legacy servers are listed.

Note: The values for Outlook Anywhere are always high(at least in this environmet), but user experience is still good. I haven’t found an explanation for the values so far.

Switch HTTPProxyOutstandingRequests

By using this switch the following counters will be collected:

MSExchange HttpProxy(autodiscover)\Outstanding Proxy Requests
MSExchange HttpProxy(eas)\Outstanding Proxy Requests
MSExchange HttpProxy(ecp)\Outstanding Proxy Requests
MSExchange HttpProxy(ews)\Outstanding Proxy Requests
MSExchange HttpProxy(mapi)\Outstanding Proxy Requests
MSExchange HttpProxy(oab)\Outstanding Proxy Requests
MSExchange HttpProxy(owa)\Outstanding Proxy Requests
MSExchange HttpProxy(owacalendar)\Outstanding Proxy Requests
MSExchange HttpProxy(powershell)\Outstanding Proxy Requests
MSExchange HttpProxy(rpchttp)\Outstanding Proxy Requests

Those counters show the number of concurrent outstanding proxy requests and should be monitored closely.


Here you can see that some servers report a high value. This is an issue I have seen with multiple performance counters. Recycling the application pool helps to have the affected servers triggering a reload of those counters.

Note: Keep in mind that recycling application pools affects client connectivity!

Switch HTTPProxyRequestsPerSec

By using this switch the following counters will be collected:

MSExchange HttpProxy(autodiscover)\Proxy Requests/Sec
MSExchange HttpProxy(eas)\Proxy Requests/Sec
MSExchange HttpProxy(ecp)\Proxy Requests/Sec
MSExchange HttpProxy(ews)\Proxy Requests/Sec
MSExchange HttpProxy(mapi)\Proxy Requests/Sec
MSExchange HttpProxy(oab)\Proxy Requests/Sec
MSExchange HttpProxy(owa)\Proxy Requests/Sec
MSExchange HttpProxy(owacalendar)\Proxy Requests/Sec
MSExchange HttpProxy(powershell)\Proxy Requests/Sec
MSExchange HttpProxy(rpchttp)\Proxy Requests/Sec

If you some performance issue this is a good point to look into it as those counters show the number of proxy requests processed each second.

Switch E2EAVGLatency

By using this switch the following counters will be collected:

MSExchangeIS Client Type(administrator)\RPC Average Latency
MSExchangeIS Client Type(airsync)\RPC Average Latency
MSExchangeIS Client Type(availabilityservice)\RPC Average Latency
MSExchangeIS Client Type(momt)\RPC Average Latency
MSExchangeIS Client Type(owa)\RPC Average Latency
MSExchangeIS Client Type(rpchttp)\RPC Average Latency
MSExchangeIS Client Type(webservices)\RPC Average Latency
MSExchangeIS Client Type(outlookservice)\RPC Average Latency
MSExchangeIS Client Type(simplemigration)\RPC Average Latency
MSExchangeIS Client Type(contentindexing)\RPC Average Latency
MSExchangeIS Client Type(eventbasedassistants)\RPC Average Latency
MSExchangeIS Client Type(transport)\RPC Average Latency
MSExchange RpcClientAccess\RPC Averaged Latency
MSExchange MapiHttp Emsmdb\Averaged Latency

I picked those counters to see the latency and also possible end-user impact.


Switch TimeInGC

By using this switch the following counters will be collected:

.NET CLR Memory(w3w*)\% Time in GC
.NET CLR Memory(w3*)\Process ID
W3SVC_W3WP(*)\Active Requests


This is besides the HTTPProxyOutstandingRequests one of the most important switch, when it comes to performance issues. The goal is to get an idea how long a worker process spent time in GC(garbage collection) instead of responding to client requests. In order to find the correct counter for each worker you need to collect 2 additional counters. The script is doing this and when you use the -Verbose parameter it will report the process ID and the name of the worker. This makes life easier if you want to check those important counters with perfmon and don’t want to spent time for finding the right counter. For each protocoll the average, if you used the -MaxSamples switch, and the maximum value will be return. If you didn’t define the -MaxSamples the average equals the maximum value.

Where can I find the script?

You can download the script here Get-ActiveExchangeUsers.ps1

What parameters are available?



ADSite here you can define in which ADSite is searched for Exchange server. If omitted the current AD site will be enumerated.
Summary switch to get a summary of main counters
HTTPProxyAVGLatency collects the name related counters
HTTPProxyOutstandingRequests collects the name related counters
HTTPProxyRequestsPerSec collects the name related counters
E2EAVGLatency here you can define in which ADSite is searched for Exchange server
TimeInGC collects the name related counters for Exchange related protocols
SpecifiedServers you can specify one or multiple server within an AD site, if you don’t want to query all
MaxSamples the script utilze the CmdLet Get-Counter, which supports this parameter in order to specify the number of samples to collect. The default is one. If you specify a higher value the average across all samples will be returned.
SendMail switch for sending the result as CSV file
From the FromAddress for sending the e-mail
Recipients list of one or multiple recipients
SmtpServer the SMTP server to use

I hope this helps you to get a better understanding and troubleshooting(if needed) of your environment.

Feedback is always more than welcome!

78 thoughts on “Get-ActiveExchangeUsers 2.0

  1. Pingback: How many users are connected to Exchange per protocol? | The clueless guy

  2. Just some cosmetics… The screenshot shows a table output, but the FT has been commented in the script, so a FL output is generated. 🙂


    • Hey Thomas,
      you mean the TimeInGC? Due to the verbose there is an output like FL. Out-GridView shows it as a table. But there is an inconsitency: I’m forcing a FT for the summary…:P


  3. Pingback: exchange stuff may 2016 | 503 5.0.0 polite people say HELO

  4. Question. Using a domain admin account, that is local admin, and performance monitor user, it returns the servers, but all zeros in verbose mode. what have i missed? Thoughts?


    • Hi Richard. This could be a language topic if your operating system is installed in another language than english. Here is an example. The counter “\MSExchange ActiveSync\Current Requests” is called “\MSExchange ActiveSync\Aktuelle Anforderungen” on a german operating system


  5. Hi,

    I think you should add the following line in your script
    #Requires -Version 3.0

    because it returns 0 for all value in Exchange Management Shell Exchange 2010 (Powershell 2.0)

    In PowerShell 2.0, $ArrayVariable.Property –> $null
    In PowerShell 3.0+, $ArrayVariable.Property –> an array of Property value

    In order to get it working on PowerShell 2.0, you have to replace everywhere (i.e. with $RPC)
    ([math]::Round(($RPC.CookedValue | measure -Average).Average))
    ([math]::Round(($RPC | Select-Object -ExpandProperty CookedValue | measure -Average).Average))



  6. to get it working on PowerShell 2.0, you also need to replace
    ForEach ($Sample in $CounterStats.CounterSamples | ? {$_.Path -match $Server})
    ForEach ($Sample in ($CounterStats | Select-Object -ExpandProperty CounterSamples | ? {$_.Path -match $Server}))

    Without this correction, $CounterStats.CounterSamples return null when MaxSamples is greater than 1.



  7. Pingback: Exchange performance:Garbage Collection | The clueless guy

  8. Very useful tool on my english exchange server. But unfortunately we also have a German exchange server with the german parameters. Do you have this Get-ActiveExchangeUsers.ps1 script in German?


      • Counters name is not different in PS but the folders from Exchange are different.

        I found this commands to show the current users:

        Get-Counter “\MSExchange OWA\Aktuelle eindeutige Benutzer” -ComputerName EXSVR01
        Get-Counter “\MSExchange RpcClientAccess\Anzahl Benutzer” -ComputerName EXSVR01
        Get-Counter “\MSExchange ActiveSync\Aktuelle Anforderungen” -ComputerName EXSVR01
        Get-Counter “\MSExchangeImap4(*)\Aktuelle Verbindungen” -ComputerName EXSVR01
        Get-Counter “\MSExchangePop3(*)\Aktuelle Verbindungen” -ComputerName EXSVR01


  9. Hi,
    first of all thanks for the great script.
    I was wondering, is there a way to verify which user(s) is currently connected on a given protocol.
    I see a “Outlook Anywhere” connection with one user, but would like to know who that user (or process) is.
    Any ideas ??


  10. I can’t figure out the sendmail switch and others related to send email functions in this script. Can you please provide an example?


  11. Hi,
    For the most part it’s a really great script thank you. One thing is not really working well on Exchange 2016 and that’s the OWA output.

    Get-Counter “\MSExchange OWA\Current Unique Users”

    Timestamp CounterSamples
    ——— ————–
    17-10-2018 10:40:08 \\MSexch02\\msexchange owa\current unique users : 2147483652



    Server : MSexch02
    RPC User Count : 254
    RPC Connection Count : 460
    OutlookAnywhere : 6
    Outlook Web App : 2147483649
    ActiveSync : 992
    EWS : 0
    MAPI User count : 4
    MAPI Connection Count : 5
    MAPI FE AppPool : 2
    MAPI BE AppPool : 5
    MAPI Ratio BE|FE : 2,50
    IIS Current Connection Count : 2873
    IIS Max Connection Count : 3412
    SemaphoreTimeouts : 0

    Another server has 2 OWA connections and another has 5.
    How does it look on your system?



    • Hi Timo,
      that happens with the Exchange counters. Recycling the app pool fix this, bug will disconnect existing sessions. I really have to publish my latest version, where there’s a switch to use IIS perf counters, which are reliable. I’ll publish this within the next week on Github….stay tuned and thanks!


      • Hi Ingo,
        I am getting a unexpected number in active sync connections (2147505823) .It will be nice if script would suggest if recycling any such app pool is required. It would be really helpful. Thanks


      • Hi Ingo, I tried running this with ASPDOTNET switch , it is giving out put with headers like Cafe ECP / Cafe EWS / Cafe MAPI and MB MAPI / MB EWS / MB ECP etc , I a mnot sure what café and MB stands here for? without this switch it gives detailed info in headers like : RPC User Count \ RPC Connection Count \ OutlookAnywhere \ actve sync Outlook Web App


      • Hi Mailadmin,
        Café is for ClientAccessService and MB reflects the MailboxServer component. When you look at the IIS you see 2 websites and both have their application pools. Using this switch will show you the respective current requests. If you want to know how many users are really connected, you need to look at the MB counters. When you want to check all incoming requests and whether your load balancer works correctly you need to look at the Café counters. Makes sense?


  12. Ingo, thanks for the great article and script. I had a question about the counters and thresholds.
    Do you have a link for all of the counters you have included so we can see what the thresholds should be for each of them?
    I was looking at the two links you had above and I couldn’t find information on all of the counters you have included here

    Like these for example:
    MSExchange HttpProxy(autodiscover)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(eas)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(ecp)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(ews)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(mapi)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(oab)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(owa)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(owacalendar)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(powershell)\Average ClientAccess Server Processing Latency
    MSExchange HttpProxy(rpchttp)\Average ClientAccess Server Processing Latency


    • Hi Clifford,
      actually there is nothing documented about these counters. I added them as we have seen that this is a good indication to determine performance bottlenecks. I think the best way would be to do a baseline monitoring and start from there.


      • Thanks for the advise
        Yeah we are busy working on a baseline with our MS Exchange PFE, to measure up against


  13. Ingo,

    One more question
    Is there a way to include all AD sites instead of selecting one by one?
    Like maybe some variable? $ADSites = (get-adsite)
    Then something along the lines of? .\Get-ActiveExchangeUsers.ps1 -ADSite $ADSites


    • Hi Clifford,
      sorry for the delay. Yes, you can use the script with multiple AD sites. The parameter accepts multiple strings. I’m using it also across 2 sites in 2 different DC. But keep in mind it might takes a while to collect perf counters across DCs. Just give the parameter an array with AD site names. One quick and dirty example would be: [System.Array]$((Get-ADSite).Name)


      • Update:
        To make it work I did the following:

        # Exchange Servers in all sites:

        $exsites=[system.array]((get-exchangeserver SERVEX*) | sort -Unique)

        .\Get-ActiveExchangeUsers.ps1 -ADSite $exsites | Out-Gridview


  14. Ingo, I am able to get these reports sent to my Outlook but I am struggling to get this to work as a scheduled task? Have you had any success?
    Tried a couple of things and they don’t work?
    IE: Start a program:
    Program/Script: C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    Add arguments: -NonInteractive -WindowStyle Hidden -command “. ‘F:\Exchangesr\Bin\RemoteExchange.ps1’; Connect-ExchangeServer -auto; F:\ExchangeScripts\Get-ActiveExchangeUsers.ps1 -ADSite $allex -TimeInGC -SendMail -From “” -Recipients -SmtpServer”

    Have also tried
    Add arguments: F:\ExchangeScripts\Get-ActiveExchangeUsers.ps1 -ADSite $allex -TimeInGC -SendMail -From -Recipients -SmtpServer

    When I run these manually I get the email with the CSV attachment

    When I run scheduled task, I get the email and attachment but no body in the email or any information in the attached CSV?

    Wanted to set this as a scheduled task to get a baseline going

    Any ideas?


    • Hi Clifford,
      thanks for your patience!
      First of all: You don’t need to run the script within EMS. It’s retrieving the Exchange server from AD and then query the perf counters. There might be a problem, when I export the result to CSV. In which context runs the scheduled task and have you defined the working folder? I believe this can be fixed by setting the working folder in the properties of the task.
      I’ll test this as well


  15. Hi, I’m trying to troubleshoot some Exchange 2016 performance issues – I’m getting about 2,147,483,742 in the Outlook Web App column. Is this to be expected?

    Kind regards,


    • Hi Mark,
      that’s why i don’t like the Exchange perf counter. It’s broken and you can only get this fixed by recycling the respective app pool. I started using the W3WP Active Requests as they are more stable…


  16. Hi,

    Any idea why the script isn’t working with Exchange 2019?
    Don’t get any errors, but also no result.

    Thanks and best regards,



    • Hi Konstantinos,
      since Exchange 2013 you can find daily performance counters on each servers.
      If you want the average users across the whole day, you can either collect these logs or collect and save the ad-hoc queried data.
      Note: these counters cannot give you the unique users.
      For this you would need to parse the IIS logs.
      I hope this answers your question.


      • Hi Idgo,
        Sorry for the late replay.
        I did find the daily performance but does not display but stack on running.

        Thank you for your help.
        You do make a nice PowerShell script by the way.
        I hope you are well and not affected by Covid-19!



  17. This script shows bunch of errors running on Exchange 2016. Following are first two,

    .\Get-ActiveExchangeUsers.ps1:145 char:19
    + Sign up
    + ~
    The ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double
    quotation marks (“&”) to pass it as part of a string.
    At C:\source\Scripts\Get-ActiveExchangeUsers.ps1:172 char:190
    + … ata-ga-click=”(Logged out) Header, go to Features”>Features <span cla …
    + ~


    • Hi JT,
      could you please share from where you have downloaded the script? I don’t have something in the script with “”(Logged out) Header, go to Features”>Features <span cla".


  18. I am using dotnet framework 4.5.2 to add value to a user id – den.Properties[“msExchVersion”].Value =”44220983382016″ , but getting error..can some1 help


  19. A great script – is it possible to use it on a German Exchange Server? Up to now the output only contains the values 0
    This is probably due to the localized names of the counters.


  20. Hi Ingo
    Thank you for the great script! Can the script pull the data from multiple exchange servers (like 50) at the same time? Or it processes each of them one by one? I wanted to be sure if I’m looking at the data that are taken at the same time with like by using parallel processing.


    • Hi Metin,
      sorry for the delay!
      I have used the script in our productive environment with over 100 servers across 2 AD sites. It works, but depending on network latency and FW settings. The 2 AD sites were in EMEA. We also had servers in US, but from EMEA querying the data from US servers, even with less than 100ms latency….took ages.


    • Hi Stefan,
      as the localization for the counters is very complex, you can only use the ASPDotNet counters.
      If someone has a way for getting the Exchange related counters localized, perfect.
      The only way at the moment would be to lookup the names and change it in the script.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s