Get Exchange Online Mailbox Size in GB

Summary: Microsoft PFE, Brian Jackett, talks about using Windows PowerShell to get Exchange Online Mailbox size in GB.

Microsoft Scripting Guy, Ed Wilson, is here. Today I want to welcome back guest blogger, Brian T. Jackett.

Brian T. Jackett is a premier field engineer at Microsoft who has specialized in SharePoint development, Project Server, and Windows PowerShell for over four years. Brian is a steering committee member of the Buckeye SharePoint User Group, and he enjoys giving back to the community through giving presentations, planning and volunteering at conferences, maintaining a SharePoint/.NET-centric blog, and contributing to the SharePoint Twitterverse. He also holds several Microsoft Certified Technology Specialist (MCTS) certifications for SharePoint-related technologies.
Brian’s blog: The Frog Pond of Technology

Now, here’s Brian…

Office 365 is picking up in deployments and user adoption. Windows PowerShell is one tool for the administration of Office 365 that is similar to its on-premises counterparts, but it can have a few differences. In this post, I will discuss one way to get the size of an Exchange Online mailbox in bytes and consequently GBs.


Getting the size of an on-premises Exchange 2010 mailbox is fairly easy. In his blog The Get-MailboxStatistics Cmdlet, the TotalitemSize Property, and that pesky little “b”,  fellow PFE Gary Siepser, explains how to accomplish this task by using the mailbox TotalItemSize property with methods such as ToMB() and ToGB(). Note that Gary’s script will not work when remoting from a local machine that doesn’t have the Exchange object model installed or loaded.

A similar type of scenario exists if you are executing Windows PowerShell against Exchange Online. The data type for TotalItemSize being returned (ByteQuantifiedSize) exists in the Exchange namespace. If the WindowsPowerShell session doesn’t have access to that namespace (or hasn’t loaded it), Windows PowerShell works with an approximation of that data type.

The following script is a sample on the TechNet article View Mailbox Sizes and Mailbox Quotas Using Windows PowerShell, which a customer of mine tried, but it was failing. (I made minor edits to fit it on page and remove references to deleted item size.)

Get-Mailbox -ResultSize Unlimited |

  Get-MailboxStatistics |

  Select DisplayName,StorageLimitStatus, `

  @{name="TotalItemSize (MB)"; expression={[math]::Round( `

  ($_.TotalItemSize.Split("(")[1].Split(" ")[0].Replace(",","")/1MB),2)}}, `

  ItemCount |

  Sort "TotalItemSize (MB)" -Descending

Image of command output

The script is targeted to Exchange 2010, but it fails for Exchange Online. In Exchange Online, when referencing the TotalItemSize property, there is not a Split method, which ultimately causes the script to return no data for “Total Item Size (MB)” column.


A simple solution would be to add a call to the ToString method off of the TotalItemSize property (shown in bold on line 5 in the following script).

Get-Mailbox -ResultSize Unlimited |

  Get-MailboxStatistics |

  Select DisplayName,StorageLimitStatus, `

  @{name="TotalItemSize (MB)"; expression={[math]::Round( `

  ($_.TotalItemSize.ToString().Split("(")[1].Split(" ")[0].Replace(",","")/1MB),2)}}, `

  ItemCount |

  Sort "TotalItemSize (MB)" -Descending |

  Export-CSV "C:\My Documents\All Mailboxes.csv" -NoTypeInformation

Image of command output

This fixes the script to run but the numerous string replacements and splits are an eyesore to me. I attempted to simplify the string manipulation with a regular expression. (For more information about regular expressions in Windows PowerShell, see the website.)

The result is a working script that adds two pieces of functionality. First, the script allows you to input a specific user to search for (or all users if no input is supplied). A technique called splatting is used to allow “@Params” to send additional optional parameters to the Get-Mailbox cmdlet. Second, the script adds a new member to the mailbox statistics called TotalItemSizeInBytes. With this member you can then convert to any byte level that suits your needs (for example, KB, MB, or GB).

Note   You can download the full version of this script from the Script Center Repository (it includes commands to connect to Exchange Online session):  
Get Exchange Online Mailbox Size in GBs

$userToFind = Read-Host -Prompt "Enter user to find (leave blank for all)"


$params = @{}

if([string]::IsNullOrEmpty($userToFind) -eq $false)

{$params = @{Identity = $userToFind}



$UserMailboxStats = Get-Mailbox -RecipientTypeDetails UserMailbox `

  -ResultSize Unlimited @Params |


$UserMailboxStats |

  Add-Member -MemberType ScriptProperty -Name TotalItemSizeInBytes `

  -Value {$this.TotalItemSize -replace "(.*\()|,| [a-z]*\)", ""}

$UserMailboxStats |

  Select-Object DisplayName, TotalItemSizeInBytes,@{Name="TotalItemSize (GB)"; `


Image of command output

The regular expression ‘$this.TotalItemSize –replace "(.*\()|,| [a-z]*\)", ""’ is searching for the following three patterns and replacing them with empty strings. The result is the total item size in bytes with no other extra characters.

  1. .*\( = Any number of characters followed by an opening parentheses
  2. , = Commas
  3. [a-z]*\) = Any number of alphabetic characters followed by a closing parentheses (i.e. “bytes)”)

Moving from on-premises to the cloud with Windows PowerShell (and Windows PowerShell remoting in general) can sometimes present new challenges due to what you have access to. This means that you must always test your code and scripts.


I still believe that not having to physically RDP to a server is a huge gain over some of the small hurdles that you may encounter during the transition. Scripting is the future of administration, and it makes you more valuable. Hopefully this script and the concepts presented help you be a better admin and developer.

For more information, watch my video series: The One Thing: Brian Jackett and SharePoint 2010.

—Frog Out


Awesome job, Brian. Thanks for an informative and helpful guest blog post. Join me tomorrow when I will talk about using Windows PowerShell to explore process threads.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy


Comments (8)

  1. I’ve been trying to modify this script to display mailboxes based on their size as a percentage of the Warning Quota. But my Where-Object expression does not return the values I expected. It seems that since the values of DatabaseIssueWarningQuota and
    TatalItemSize are in Bytes, and since you can’t have a fraction of a byte, the division will one return an integer. Either “0 Byte”, if the results of the division is less than 1, or “1 Byte” if the results of the division is more than 1.

    I’ve tried many ways to force the division to return a decimal result, but all have failed. Amy ideas to make it work.

    Get-Mailbox -ResultSize Unlimited |
    Get-MailboxStatistics |
    Where {$_.TotalItemSize / $_.DatabaseIssueWarningQuota) -lt .90} |
    Sort-Object TotalItemSize -Descending | ft –auto

    1. In fact all values returned by Remote PowerShell are Strings, so you need to convert DatabaseIssueWarningQuota as well TotalItemSize to integer first:

      Get-Mailbox -ResultSize Unlimited | Get-MailboxStatistics | where { ( ( ( $_.TotalItemSize.ToString() -Split ‘\s’ )[2] -replace ‘\(|\,’ ).Trim() / 1GB ) / ( ( ( $_.DatabaseIssueWarningQuota.ToString() -Split ‘\s’ )[2] -replace ‘\(|\,’ ).Trim() / 1GB ) -lt 0.90 }

    2. It looks like I cannot edit my own comment here.
      Below please find command without “/ 1GB” operators. I have also added Sort-Object cmdlet from your example. Please note that you cannot sort by TotalItemSize since it is a string
      Get-Mailbox -ResultSize 10 | Get-MailboxStatistics | where { ( $SizeInBytes = ( ( $_.TotalItemSize.ToString() -Split ‘\s’ )[2] -replace ‘\(|\,’ ).Trim() ) / ( $DatabaseIssueWarningQuotaBytes = ( ( $_.DatabaseIssueWarningQuota.ToString() -Split ‘\s’ )[2] -replace ‘\(|\,’ ).Trim() ) -gt 0.50 } | select *, @{ n = ‘SizeInBytes’ ; e = { $SizeInBytes } }, @{ n = ‘DatabaseIssueWarningQuotaBytes’ ; e = { $DatabaseIssueWarningQuotaBytes } } -ExcludeProperty TotalItemSize, DatabaseIssueWarningQuota | Sort-Object SizeinBytes -Descending | ft -AutoSize

  2. Tunde says:

    Interesting! I used below trick in mine and it produces same result as yours. The crazy part is I search everywhere for something like this before I decided to resolve it myself.


    $stats = $mb | Get-MailboxStatistics | Select-Object TotalItemSize,ItemCount,LastLogonTime,StorageLimitStatus,TotalDeletedItemSize

    $lastlogon = $stats.LastLogonTime

    $TotalItemSize = [double]$Stats.TotalItemSize.SubString($Stats.TotalItemSize.indexof("(")+1, $Stats.TotalItemSize.indexof(" b")-$Stats.TotalItemSize.indexof("("))

    $TotalItemSizeGB = $TotalItemSize / 1073741824

    $TotalItemSizeGB = "{0:N2}" -f $TotalItemSizeGB

    $TotalItemSizeMB = $TotalItemSize /1048576

    $TotalItemSizeMB = "{0:N0}" -f $TotalItemSizeMB


  3. Hayden Shaw says:

    Megabyte Solutions is a 100% Australian owned business , operating in Newcastle with a National reach since 2005. We are dedicated to providing innovative and cost effective ICT solution and strategies to clients in the SMB, Education and Enterprise sectors. Our goal is to understand your specific business processes and needs so that we can become an integral part of your team. We are focused in providing a customer centric quality solution for all customer IT needs.

  4. royax says:

    how can we export the result to a .csv file?

  5. Shiva Sharma says:

    Problem is, Get-MailboxStatistics output just a display name – not unique and cant really be used as such. The other half of the information you need is in Get-Mailbox :- found answer in following link. once you have the data on all your mailboxes, and
    the output can be IMPORTED into excel you can do all your sorting etc and delete whatever you dont want

    ***if this is what you were looking for, please click this link and give the guy some credit.. i didnt come up with this, i just found it


    $Mailboxes = Get-Mailbox -ResultSize Unlimited
    foreach ($Mailbox in $Mailboxes)
    $Mailbox | Add-Member -MemberType "NoteProperty" -Name "MailboxSizeMB" -Value ((Get-MailboxStatistics $Mailbox).TotalItemSize.Value.ToMb())
    $Mailboxes | Sort-Object MailboxSizeMB -Desc | Select PrimarySMTPAddress, MailboxSizeMB

    #REM – to export this out — do the following 😉 enjoy (see the part where it says "Select" you can add additional fields like ALIAS etc to this)

    $Mailboxes = Get-Mailbox -ResultSize Unlimited
    foreach ($Mailbox in $Mailboxes)
    $Mailbox | Add-Member -MemberType "NoteProperty" -Name "MailboxSizeMB" -Value ((Get-MailboxStatistics $Mailbox).TotalItemSize.Value.ToMb())
    $Mailboxes | Sort-Object MailboxSizeMB -Desc | Select PrimarySMTPAddress, MailboxSizeMB | Export-Csv -NoType "C:tempMailboxessize.csv"

  6. Here is my approach. Just a bit shorter.
    Get-Mailbox -ResultSize 1 | Get-MailboxStatistics | select @{ n = ‘SizeInBytes’ ; e = { ( ( $_.TotalItemSize.ToString() -Split ‘\s’ )[2] -replace ‘\(|\,’ ).Trim() / 1GB } }

Skip to main content