Step-By-Step: Identifying Large Exchange Mailbox Folders Via PowerShell
Identifying users with large Exchange mailboxes is a task undertaken by most system administrators who are in need of freeing up space on their mail servers. While most search for mailboxes approaching a certain size, I wanted to take this a step further and identify the large folders within user mailboxes. An example of this would be to find all the users who have a large Deleted Items folder or Sent Items or Calendar that would be eligible to be cleaned out. It’s made to be run from a Remote Exchange Management Shell connection instead of by logging into an Exchange server via remote desktop and running such a shell manually.
Let’s get started by defining the function and parameters:
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $False)]
[ValidateSet('All', 'Calendar', 'Contacts', 'ConversationHistory', 'DeletedItems', 'Drafts', 'Inbox', 'JunkEmail', 'Journal', 'LegacyArchiveJournals', 'ManagedCustomFolder', 'NonIpmRoot', 'Notes', 'Outbox', 'Personal', 'RecoverableItems', 'RssSubscriptions', 'SentItems', 'SyncIssues', 'Tasks')]
[string]$FolderScope = 'All',
[Parameter(Mandatory = $False)]
[int]$Top = 1,
[Parameter(Mandatory = $False,
Position = 1,
ValueFromPipeline = $True)]
[string]$Identity = '*'
)
}
This function is to be named Get-LargeFolder and takes three parameters.
- $FolderScope is used in the Get-MailboxFolderStatistics cmdlet and must belong to the set of values specified.
- $Top is an integer used to define how many results we’re going to return
- $Identity can be specified as an individual username to examine a specific mailbox, or left blank (defaulted to *) to examine the entire organization.
function Get-LargeFolder
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $False)]
[ValidateSet('All', 'Calendar', 'Contacts', 'ConversationHistory', 'DeletedItems', 'Drafts', 'Inbox', 'JunkEmail', 'Journal', 'LegacyArchiveJournals', 'ManagedCustomFolder', 'NonIpmRoot', 'Notes', 'Outbox', 'Personal', 'RecoverableItems', 'RssSubscriptions', 'SentItems', 'SyncIssues', 'Tasks')]
[string]$FolderScope = 'All',
[Parameter(Mandatory = $False)]
[int]$Top = 1,
[Parameter(Mandatory = $False,
Position = 1,
ValueFromPipeline = $True)]
[string]$Identity = '*'
)
Get-Mailbox -Identity $Identity -ResultSize Unlimited |
Get-MailboxFolderStatistics -FolderScope $FolderScope
}
Next I’ve added a lines to retrieve all of my organizations mailboxes which I direct the data stream into a Get-MailboxFolderStatistics command with the FolderScope parameter set to the same value we passed to our function. Now we need to sort the results.
function Get-LargeFolder
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $False)]
[ValidateSet('All', 'Calendar', 'Contacts', 'ConversationHistory', 'DeletedItems', 'Drafts', 'Inbox', 'JunkEmail', 'Journal', 'LegacyArchiveJournals', 'ManagedCustomFolder', 'NonIpmRoot', 'Notes', 'Outbox', 'Personal', 'RecoverableItems', 'RssSubscriptions', 'SentItems', 'SyncIssues', 'Tasks')]
[string]$FolderScope = 'All',
[Parameter(Mandatory = $False)]
[int]$Top = 1,
[Parameter(Mandatory = $False,
Position = 1,
ValueFromPipeline = $True)]
[string]$Identity = '*'
)
Get-Mailbox -Identity $Identity -ResultSize Unlimited |
Get-MailboxFolderStatistics -FolderScope $FolderScope |
Sort-Object -Property @{
e = {
$_.FolderSize.split('(').split(' ')[-2].replace(',','') -as [double]
}
} -Descending
}
The FolderSize parameter returns with a Get-MailboxFolderStatistics cmdlet which is a string to be split up to provide only the value in bytes which I am casting to a double. Once the stats have been gathered and set in order, they need to be selected so they can be returned.
The complete script is as follows:
function Get-LargeFolder
{
[CmdletBinding()]
param (
[Parameter(Mandatory = $False)]
[ValidateSet('All', 'Calendar', 'Contacts', 'ConversationHistory', 'DeletedItems', 'Drafts', 'Inbox', 'JunkEmail', 'Journal', 'LegacyArchiveJournals', 'ManagedCustomFolder', 'NonIpmRoot', 'Notes', 'Outbox', 'Personal', 'RecoverableItems', 'RssSubscriptions', 'SentItems', 'SyncIssues', 'Tasks')]
[string]$FolderScope = 'All',
[Parameter(Mandatory = $False)]
[int]$Top = 1,
[Parameter(Mandatory = $False,
Position = 1,
ValueFromPipeline = $True)]
[string]$Identity = '*'
)
Get-Mailbox -Identity $Identity -ResultSize Unlimited |
Get-MailboxFolderStatistics -FolderScope $FolderScope |
Sort-Object -Property @{
e = {
$_.FolderSize.split('(').split(' ')[-2].replace(',','') -as [double]
}
} -Descending |
Select-Object -Property @{
l = 'NameFolder'
e = {
$_.Identity.Split('/')[-1]
}
},
@{
l = 'FolderSize'
e = {
$_.FolderSize.split('(').split(' ')[-2].replace(',', '') -as [double]
}
} -First $Top
}
This can now be accomplished once completed:
#Get 25 largest Deleted Items folders in your organization
Get-LargeFolder -FolderScope 'DeletedItems' -Top 25
#Get my largest 10 folders
Get-LargeFolder -Identity ThmsRynr -Top 10
#Get the top 25 largest Deleted Items folder for users in a specific group
$arrLargeDelFolders = @()
(Get-ADGroupMember 'GroupName' -Recursive).SamAccountName | ForEach-Object -Process {
$arrLargeDelFolders += Get-LargeFolder -FolderScope 'DeletedItems' -Identity $_
}
$arrLargeDelFolders |
Sort-Object -Property FolderSize -Descending |
Select-Object -Property NameFolder, @{
l = 'FolderSize (Deleted Items)'
e = {
'{0:N0}' -f $_.FolderSize
}
} -First 25 |
Format-Table -AutoSize