Get Exchange Mailbox Deleted Items Folder Size

Get Exchange Mailbox Deleted Items Folder Size

I initially wrote this post based on a simple command I used to use. That turned out to be partially wrong as sometimes it wasn’t finding the “Deleted Items” folder. After asking on technet, I told it was best to use the -FolderScope option in the command I was running. Guess what? In my environment also that turned out not to be 100% accurate. I was still left with loads of empty results. So I decided to merge the two in a script.

In order to get Exchange Mailbox Deleted Items Folder Size of an Exchange 2010’s mailbox, with the FolderScope option, run the below:

Get-MailboxFolderStatistics -identity alias -FolderScope DeletedItems | Select-Object FolderSize

If you want to specify a folder, without giving the FolderScope and such folder is called Deleted Items, use this:

Get-MailboxFolderStatistics -identity "alias" | where {$_.Name -eq "Deleted Items"} | Select-Object FolderSize

Where alias is the alias of the mailbox you’re searching against.

Problems, problems everywhere!

The above commands seems pretty simple if it wasn’t for the fact that in my environment, they didn’t always work as I said above. This is a list of issues I was getting on a few mailboxes:

  1. -FolderScope DeletedItems returns more folders than just the Deleted Items one
  2. -FolderScope DeletedItems returns no results at all
  3. where {$_.Name -eq “Deleted Items”} returns no results at all
  4. where {$_.Name -eq “Deleted Items”} returns more than one folder

Point 1 and 2

-FolderScope is great as it shrinks the amount of time needed to get such results as it doesn’t go through each folder. The problem was that sometimes, for a few mailboxes, I was getting a huge list of folders in the mailbox (note that it wasn’t a full list, I tried running Get-MailboxFolderStatistics with no filters and I was able to see more folders – for some reason they had the DeletedItems scope). Sometimes instead it seemed like the mailbox had no DeletedItems scope, which obviously didn’t return any size.

Point 2 and 4

Point 4 is obvious: the user must have created a new folder himself and called it Deleted Items! Good job! Point 3 instead is also understandable, but I didn’t think Exchange 2010 would have done this.. I’m talking of translating it into the user’s client’s language! So basically Deleted Items wasn’t found but “Elementos eliminados” was! So the criteria wasn’t met and the size was not found. Look at this mailbox for instance:

Get-MailboxFolderStatistics Deleted Items Spanish

I did run the scripts against all mailboxes and against an imported list of aliases and when running it against the entire environment, I noticed that I had about more than 10% of mailboxes missing. If I run a command against a list of mailboxes it’s because I would like to get the results in the same order, but when something isn’t found, then you get into troubles as the Export-CSV won’t add empty lines, it’ll just write back what you have (see below example of how you would run it against a text file full of MailboxGUIDs):

Get-Content C:\temp\mailboxes.txt | ForEach-Object {Get-MailboxFolderStatistics -identity $_ -FolderScope DeletedItems | Select-Object FolderSize} | Export-csv C:\temp\deleteditemsreport.csv

I needed a script that captured a few more info, but if you’re looking to get a better report that will also show you the items that have been skipped, then keep reading this.

The core of the script is this:

$FolderSize = $FolderSize = (get-mailboxfolderstatistics -identity $identity -FolderScope DeletedItems | Select-Object FolderSize).FolderSize
			If ($FolderSize -is [system.array] -OR $FolderSize -eq $NULL)
			{
				$FolderSize = (get-mailboxfolderstatistics -identity $identity -FolderScope DeletedItems | where {$_.Name -eq "Deleted Items" -OR $_.Name -eq "Itens Excluídos" -OR $_.Name -eq "Éléments supprimés" -OR $_.Name -eq "Itens Eliminados" -OR $_.Name -eq "Elementos eliminados" -OR $_.Name -eq "Gelöschte Objekte" -OR $_.Name -eq "Elementy usuniete" -OR $_.Name -eq "Törölt elemek" -OR $_.Name -eq "Gelöschte Elemente" -OR $_.Name -eq "Mensagens excluídas"} | Select-Object FolderSize).FolderSize
				
				If ($FolderSize -is [system.array] -OR $FolderSize -eq $NULL)
				{
					$FolderSize = (get-mailboxfolderstatistics -identity $identity | where {$_.Name -eq "Deleted Items" -OR $_.Name -eq "Itens Excluídos" -OR $_.Name -eq "Correos eliminados" -OR $_.Name -eq "Éléments supprimés" -OR $_.Name -eq "Itens Eliminados" -OR $_.Name -eq "Elementos eliminados" -OR $_.Name -eq "Gelöschte Objekte" -OR $_.Name -eq "Elementy usuniete" -OR $_.Name -eq "Törölt elemek" -OR $_.Name -eq "Gelöschte Elemente" -OR $_.Name -eq "Mensagens excluídas"} | Select-Object FolderSize).FolderSize
				}
			}

You will see the full script later on in this page, however I first want to show you the logic process I followed.
First of all, $identity is the MailboxGUID I gathered earlier on in the script and the first thing I run is a Get-MailboxFolderStatistics against that identity with the -FolderScope DeletedItems. This is generally pretty quick to run. If the mailbox is ok, the script is done. But if for any reason the variable $FolderSize is empty or it’s an array (which means there’s more than one result), then the script will try to run the same command, this time we’ll add the where filter and look what I did, I searched the mailboxes where I didn’t get a result and found a few translation based on the folder list. Obviously that is not all of them, so if you have more in the environment, just add them in!
If also this time $FolderSize is empty or an array, then just try to run the command again, this time excluding the -FolderScope option. This one will be the slowest command as it’ll search through the folders. This made the script much quicker, I went from a report that lasted 10.5 hours to one that lasted almost 4 (large environment).

No worries, if your environment is big enough you might end up having a few mailboxes where the script couldn’t get a size for them 🙂 . For example, let’s say that a user created a Deleted Items folder and for some reason it’s also set as a DeletedItems scope. That means the first command will catch both the original one and the new one. The second command will do the same and the third one as well. But from what I’ve seen, it’s a very special case. Instead you might have a few not being recognised. For instance I’ve seen a couple of users in Moscow showing “?????” as folder name. I just left them and didn’t mind skipping just a few.

The script

I will also leave the info I needed, I think these are handy to get a full overview of what’s going on in terms of usage in the environment. The output (C:\ExchangeReport_20151015) will include:

  • The Display Name of the user’s Mailbox
  • The Size of the Mailbox
  • The Database where the Mailbox is currently stored
  • The Deleted Items size
  • The UserAccountControl (that carries the user account state – whether it’s disabled or not and its type)
  • The OU where the user’s object is in
  • The MailboxGUID
#Get the list of mailboxes (Display Name, Mailbox Size, DB and MailboxGUID)
	Write-Host "Gathering a list of Mailboxes (including Display Name, Total Item Size, Database and MailboxGUID).."
	$mailboxes = Get-Mailbox -ResultSize Unlimited | Get-MailboxStatistics | Sort-Object TotalItemSize -Descending | Select-Object DisplayName,TotalItemSize,Database,MailboxGuid

#Output file
	$yyyyMMdd = Get-Date -format "yyyyMMdd"
	$txtOutput = "C:\ExchangeReport_$($yyyyMMdd).txt"
	
	#Deletes the output file if it exists
		If (Test-Path $txtOutput){
			Remove-Item $txtOutput
		}
	#Creates the first line of the output file
		# Splitting them with a "|" instead of a comma. It'll be easier to work on it later on
		# due the commas in the FolderSize result.
		Add-Content -Path $txtOutput -Value "DisplayName|TotalItemSize|Database|DeletedItemsSize|UserAccountControl|OrganizationalUnit|MailboxGUID"
	
#Count the number of mailboxes based on $mailboxes
	$numberOfmailboxes = $mailboxes.count

#Initialise the counter
	$counter = 1

$mailboxes | ForEach-Object {
	
	#Get MailboxGUID
		$identity = $_.MailboxGUID.guid
	#Get Archive DB
		$archiveDB = (Get-Mailbox -identity $identity | Select-Object ArchiveDatabase).Name
	#Get OU
		$OU = (Get-Mailbox -identity $identity | Select-Object OrganizationalUnit).OrganizationalUnit
	#Get DB
		$DB = $_.database.name
	#Get DisplayName
		$DisplayName = $_.displayname
	#Get TotalItemSize
		$TotalItemSize = $_.TotalItemSize.Value
	#Get UserAccountControl to report if the account is disabled.
		$UserAccountControl = (Get-User -identity $identity | Select-Object UserAccountControl).UserAccountControl
	#Get FolderSize for DeletedItems Folder scope. If the variable is empty or it's an array, try to get it based (again) on its Scope
	#but this time limiting the result to a few known language (there might be a few more). If also this time the variable is an array
	#or it's empty, then try to get the size searching through all folders (again, based on known languages).
	#This should speed up the process a lot if the folder is found.
		$FolderSize = $FolderSize = (get-mailboxfolderstatistics -identity $identity -FolderScope DeletedItems | Select-Object FolderSize).FolderSize
			If ($FolderSize -is [system.array] -OR $FolderSize -eq $NULL)
			{
				$FolderSize = (get-mailboxfolderstatistics -identity $identity -FolderScope DeletedItems | where {$_.Name -eq "Deleted Items" -OR $_.Name -eq "Itens Excluídos" -OR $_.Name -eq "Éléments supprimés" -OR $_.Name -eq "Itens Eliminados" -OR $_.Name -eq "Elementos eliminados" -OR $_.Name -eq "Gelöschte Objekte" -OR $_.Name -eq "Elementy usuniete" -OR $_.Name -eq "Törölt elemek" -OR $_.Name -eq "Gelöschte Elemente" -OR $_.Name -eq "Mensagens excluídas"} | Select-Object FolderSize).FolderSize
				
				If ($FolderSize -is [system.array] -OR $FolderSize -eq $NULL)
				{
					$FolderSize = (get-mailboxfolderstatistics -identity $identity | where {$_.Name -eq "Deleted Items" -OR $_.Name -eq "Itens Excluídos" -OR $_.Name -eq "Correos eliminados" -OR $_.Name -eq "Éléments supprimés" -OR $_.Name -eq "Itens Eliminados" -OR $_.Name -eq "Elementos eliminados" -OR $_.Name -eq "Gelöschte Objekte" -OR $_.Name -eq "Elementy usuniete" -OR $_.Name -eq "Törölt elemek" -OR $_.Name -eq "Gelöschte Elemente" -OR $_.Name -eq "Mensagens excluídas"} | Select-Object FolderSize).FolderSize
				}
			}
			
	
		$output = "$($DisplayName)|$($TotalItemSize)|$($DB)|$($FolderSize)|$($UserAccountControl)|$($OU)|$($identity)"
		Add-Content -Path $txtOutput -Value "$($output)"
		Write-Host "$($counter) of $($numberOfmailboxes)"
		Write-Host "$($output)" #Displays the output on screen (I like to know where the script is at and what it is doing)
		Write-Host ""
	
	$counter = $counter+1
	
}

Hope this helps when you end up having the same issues I have. I’ll look at updating the script with other languages I’ll find.
You can add as many more info as you want in it, the more you put in, the longer it’ll take but the longer it’ll take the more info you have 🙂 . I’m lazy so on mine I also have the script to send me an email with the report attached once completed. See this article to get more info about sending an email with PowerShell.

IT Droplets

IT Droplets