Finding High Item Count Folders Using the Exchange Management Shell


EDIT 06/18/2010: Few post changes to match the newest version of the script.

Working in Exchange Customer Service and Support, we often see cases where user performance, or overall server performance, is impacted because of a high number of items in critical folders within user’s mailboxes. This issue has already been documented in multiple places, including the following articles:

Understanding the Performance Impact of High Item Counts and Restricted Views
http://technet.microsoft.com/en-us/library/cc535025.aspx

Using PFDAVAdmin to get the item count within the folders on an exchange server
http://msexchangeteam.com/archive/2007/04/24/438170.aspx

For the past few months, I have been using a simple Exchange Management Shell command to find all folders that have more than a certain number of items. The shell command is as follows:

Get-Mailbox | Get-MailboxFolderStatistics | Where {$_.ItemsInFolder -gt 5000} | Sort-Object -Property ItemsInFolder -Descending | fl Identity, ItemsInFolder

The above command finds all folders in the Organization that have more than 5,000 items, sorts them in descending order, and then gives the full Folder Path and Item Count. By modifying the Get-Mailbox portion of the command, you can target the command to obtain mailboxes from specific Servers or Databases.

Since there are different folder item limits for each version of Exchange, I thought it might be beneficial to write a script that could analyze folders on all versions, and determine if they were over their limit. The limits are as follows:

Version

Folder Item Limit

Exchange 2000/2003

5,000

Exchange 2007

20,000

Exchange 2010

100,000

It should be noted that these numbers are just the Microsoft recommended limits. Actual numbers could vary greatly depending on how many users are over the limit, the way mailboxes are being accessed (i.e. Outlook Cached Mode, Outlook Online Mode, via Mobile Phone, etc.) as well as certain 3rd party application integration.

The script is called HighItemFolders.ps1. It can be used against the entire organization, a single server, or a single database. It has the option to search all folders, or only critical folders. It can find folders above the Microsoft recommended limits, or above a specified value. And it can send the results solely to the screen, or export the results to a CSV file.

Parameters

The script has the following parameters, which are all optional:

-CriticalFoldersOnly: Specifies whether to check only Critical Folders, which are Calendar, Contacts, Inbox, and Sent Items, or to check all folders. Should be specified as either $true or $false. If omitted, the default value is $true.

-Database: Specifies the target database to retrieve mailboxes from. This switch overrides the -Server switch if both are used.

-DomainController: Specifies the Domain Controller to use for all mailbox and folder tests. If omitted, the default value is $null.

-FormatList: Writes output to the screen in list format instead of table format. Should be input as either $true or $false. If omitted, the default value is $false.

-ItemCount: Ignores the Microsoft recommended item limits, and finds folders with the specified item count.

-OutputFile: Specifies the file to output the results to. This should be a .CSV file.

-ResultSize: Specifies the maximum number of mailboxes to check. If omitted, the default value is unlimited.

-Server: Specifies the target Exchange server to retrieve mailboxes from.

Examples

Obtains all users in the organization, and checks only critical folders over the Microsoft recommended item counts:

C:\> .\HighItemFolders.ps1

Obtains all users on a specified database, checks all folders, and outputs to a CSV file:

C:\> .\HighItemFolders.ps1 -Database “e2k7-1\First Storage Group\Mailbox Database” -CriticalFoldersOnly $false -OutputFile output.csv

Obtains all users on a specific Exchange server with more than 1000 items in any folder:

C:\> .\HighItemFolders.ps1 -Server “e2k3-5” -ItemCount 1000

Output

The script always writes output to the screen. If the -OutputFile switch is used, it will write to a file in addition to the screen.

Screen Output:

CSV Output:

Script

The script can be downloaded from the below location, and then executed from the Exchange Management Shell.

http://gallery.technet.microsoft.com/scriptcenter/42fc40d2-46a8-4e48-b15c-f0ad23357739

Notes

1. In some cases, the CSV file does not separate the columns properly when opening it directly with Excel. To format the columns correctly, do the following (with Excel 2007):

  • Open Excel
  • Choose Open, and browse to the CSV file
  • Choose Delimited as the format. Hit Next
  • Use Tab as the Delimiter. Hit Finish.

2. Error detection has been included in the script to determine if any of the mailboxes reside on a database or server that is inaccessible. If so, that database or server will be skipped so we don’t have a lengthy timeout for each mailbox. However, this detection only works on Exchange 2007 and higher. Exchange 2003 mailboxes still time out individually if they are inaccessible, and can cause the script to take a very long time to run.

Hope you find this useful!

Mike Hendrickson

Comments (20)
  1. Cole says:

    One thing I found in running the script is that the result size is limited to the first 1000 mailboxes.  Adding the -resultsize unlimited to the get-mailbox command gets around this issue for those of us with a large number of mailboxes on one server.

    Cheers.

  2. Mike Hendrickson says:

    Thanks for the comment Cole. I’m working on an update for the script right now. In the meantime, you are correct in that you can modify the Get-Mailbox portions of the script (there are three different Get-Mailbox commands that can be run), and append "-ResultSize Unlimited" to the end of them.

    Thanks.

  3. pesospesos says:

    Awesome, can’t wait to try it out!

  4. Petri says:

    Damn, one script more to keep administrators be heavily busy for running and looking for the results. Why an earth this has not been made by more cleaver way?

    Why you have not asked Outlook team (and you for the OWA) add a feature on the client side which recognize such a problem and report valid methods to fix the problem? Or do it the same way than quota limitation check has been done,

    Why the administrators has to run the script and find such a users.

  5. This is great, perfect timing as I am helping a client move from 2003 to 2007 now and they have quite a few folks that ar between 5000 and 20,000 items in a folder that should see better performance but some that are WAY higher that need some helping learning how to file and archive!

  6. Mailman says:

    I apologize if this is not the correct place for this question, but is there any way to intentionally corrupt a mail item in a mailbox?

    We would like to test a 3rd party tool that includes a feature to  "Skip Corrupt Items per mailbox" when moving a mailbox or exporting it to a pst file.

  7. Garry Trinder says:

    Great script :-)

    However it generates an error message for every mailbox it finds:

    Exception calling "ToDouble" with "1" argument(s): "Input string was not in a c

    orrect format."

    At D:tedHighItemFolders.ps1:334 char:36

    +     return ([System.Convert]::ToDouble <<<< ($temp2))

       + CategoryInfo          : NotSpecified: (:) [], MethodInvocationException

       + FullyQualifiedErrorId : DotNetMethodException

    The command used was:

    .HighItemFolders.ps1 -database "servernamesgnamedbname" -ItemCount 5000

  8. Pax says:

    Nice script. But maybe adding -domaincontroller would be great for different domains?

    My largest user-inbox has 220291 items… well… I think it’s time for user-education…

  9. Mike Hendrickson says:

    Hey Ted,

    I can’t seem to reproduce this in my lab, however it looks like you are failing while trying to read the ExchangeVersion attribute on a mailbox. On one of these problem mailboxes, can you try running "Get-Mailbox MBXNAME | FL Name, ExchangeVersion"? See if anything shows up for ExchangeVersion.

    However, I think I can make this script more resilient by calling "(Get-Mailbox 2k7mbx1).ExchangeVersion.ExchangeBuild.Major" instead of using a more complicated function.

    Pax,

    Thanks for the comment. That would indeed be a good switch to add. I’ll go ahead and work on that for the next update.

    Thanks!

  10. Petri says:

    Is there any reasons why the administrators have to run such a script like this? How many of you are using some .ps script to see whose mailboxes are full and send email based of that information for the users?

    Why the Exchange does not do this automatically, if this is so markable issue? Or why Outlook does not report for the user, "Your Outlook performance has been decreased because of number of the items in these folders, recommended actions:…"

    In my mind this is not the enterprise way to do work.

  11. Mike Hendrickson says:

    Hi Petri,

    There is no built in way to block specific item counts in Exchange, as there could be legitimate reasons for having many items (like an archive mailbox). This script is more intended to alert administrators of potential problems, and allow them to take action. The best way to combat this would be to deploy MRM, and set policies to move items based on a certain date so that items do not pile up in user’s critical folders. Additionally, this may be a good time to educate users on how to manage their mailbox. There are also multiple performance counters built into Exchange to monitor slow searches, which could be caused as the result of having too many items. These could be monitored directly through Perfmon, or through a monitoring tool like SCOM.

    http://technet.microsoft.com/en-us/library/bb201689(EXCHG.80).aspx

  12. Petri says:

    I actually did not meant to block the number of the messages. Even I compared that to mailbox quotas. Reasons are the same as you describes. More likely my point was, that Outlook is capable to detect when the responses are coming slowly and it will know the number of the items, so why it does not report that to user? At least it might cause less calls to help desk when users are aware of this.

    By the enterprise level, I meant, how many times you have forgot to run some scripts (yes you could schedule them, for that you need account which password never ends etc..). I hope that your target is not to run Exchange with scripts ;-)

    And no doubt, this is great script and it gives very useful informative, but still I like to see this in normal daily maintenance process which Exchange is running by itself. And monitored with SCOM.

  13. Chris Lehr says:

    I get an error that it’s "missing file specification after redirection operator" when I run just the Ps1.  If I specify output file…  same error.  Any ideas?

  14. Mike Hendrickson says:

    Hi Chris,

    Can you post the full error like Ted did above? That will show me what specific line of the script it’s failing on.

    Thanks!

  15. Jiff Lemon says:

    Hey guys, I’m now failing to get the script to run:

    getting error:

    Invalid assignment expression. The left hand side of an assignment operator needs to be something that can be assigned to like a variable or a property.

    At C:ScriptsHighItemFolders.ps1:15 char:29

    + [string] $DomainController = <<<<  "",

       + CategoryInfo          : ParserError: (:) [], ParentContainsErrorRecordException

       + FullyQualifiedErrorId : InvalidLeftHandSide

    The weird thing is, it did work previously!

    Tried downloading the script again, but get the same error.

  16. Michael Gorn says:

    I get an error on every user that has an apostrophe in the "Full Name":

    Invoke-Expression : The string starting:

    At line:1 char:52

    + Get-MailboxFolderStatistics -Identity ‘Ken O’Connor <<<< ‘ -ErrorAction Silen

    tlyContinue

    is missing the terminator: ‘.

    At C:Documents and SettingsmgornDesktopHighItemFolders.txt.ps1:76 char:33

    +     $getFolders = Invoke-Expression <<<<  -Command $getFoldersString

       + CategoryInfo          : ParserError: ( -ErrorAction SilentlyContinue:Str

      ing) [Invoke-Expression], IncompleteParseException

       + FullyQualifiedErrorId : TerminatorExpectedAtEndOfString,Microsoft.PowerS

      hell.Commands.InvokeExpressionCommand

  17. Mike Hendrickson says:

    Hi Jiff,

    I can’t seem to reproduce your issue in any of my labs. As a workaround, you may try using the -DomainController switch. This should overwrite the blank entry that is assigned by default.

    Michael,

    I just added an update to the script so that it can handle names with apostrophe’s in them. The new script should make it online within a day or two. In the meantime though, you can fix the script by changing the line that assigns $getFoldersString. Change it as follows:

    $getFoldersString = "Get-MailboxFolderStatistics -Identity `"$($mbx.Value)`" -ErrorAction SilentlyContinue"

    Thanks.

  18. Michael Gorn says:

    now I get this error when I run it:

    [PS] C:temp>.HighItemFolders.ps1

    Unexpected token ‘$(‘ in expression or statement.

    At C:tempHighItemFolders.ps1:69 char:65

    +     $getFoldersString = "Get-MailboxFolderStatistics -Identity ‘"$( <<<< $mbx

    .Value)’" -ErrorAction SilentlyContinue"

       + CategoryInfo          : ParserError: ($(:String) [], ParseException

       + FullyQualifiedErrorId : UnexpectedToken

  19. Jay thy says:

    Michael, I’m receiving same error as you..were you able to get it resolved? Thanks.

  20. Kevin O says:

    I was getting the same error as Michael and Jay. I changed this line:

    $getFoldersString = "Get-MailboxFolderStatistics -Identity ‘"$($mbx.Value)’" -ErrorAction SilentlyContinue"

    to:

    $getFoldersString = "Get-MailboxFolderStatistics -Identity ‘$($mbx.Value)’ -ErrorAction SilentlyContinue"

    Note removal of quotation marks around $($mbx.Value). Currently validating results, caveat: I am not a programmer and tried this because it looked out of place. Results may vary.

Comments are closed.