PowerShell: Report To Avoid Hidden Exchange Mailbox Quota Violations

There are two separate quotas for a Microsoft 365 mailbox. One is for the size of the mailbox. The other lesser-known limit is on the recoverable items database.

It is the recoverable items that frequently catch people off-guard. This quota isn’t shown in the admin portal dashboards. Furthermore, the limit is usually only an issue if you have a mailbox on legal hold.

These two things combine to make a frustrating situation. A user’s mailbox can stop due to a quota violation when it isn’t shown as being full on the portal. Here is a link to Microsoft’s documentation on the subject if you would like to know more.

Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline
$Report = @()
$UserMailboxes = (Get-ExoMailbox -ResultSize unlimited -Filter {(RecipientType -eq ‘UserMailbox’)}).UserPrincipalName
Foreach ($Mailbox in $UserMailboxes){
    $MailboxTotalSize = [PSCustomObject]@{
        Name = $Mailbox
        Mailbox = Get-ExoMailboxStatistics -Identity $Mailbox | Select-Object TotalItemSize -ExpandProperty TotalItemSize
        RecoverableItems = Get-ExoMailboxFolderStatistics -Identity $Mailbox -FolderScope RecoverableItems | Select-Object Name,FolderAndSubfolderSize -ExpandProperty FolderAndSubfolderSize |Where-Object {$_.Name -like “*Recoverable*”}
    }
    $Report += $MailboxTotalSize
}
$Report |Export-Csv -Path
“C\Temp\MailboxTrueSizeReport.csv” -NoTypeInformation

I use the report to help prevent quota lockouts at my employer. You will need to run the script from a machine that has the Exchange Online Management Powershell module installed. Executing the script also requires an account with Exchange Online mailbox administrator permissions.

The output is an easy-to-read three-column report. The headers are Name (the user’s UPN), Mailbox, and RecoverableItems. The script takes around one hour per thousand mailboxes on average. This time can vary wildly,  the point is that it’s slow. Don’t let the computer running it go to sleep.

PowerShell; Report Mailbox and OneDrive Size per User

Microsoft’s 365 has a ton of built-in reports for almost every metric you can think of. I recently needed to show Exchange Online and OneDrive consumption in the same report for a migration project. I was surprised to find the data I needed was available in separate reporting functions, but not together.

I briefly considered using Power BI or Excel to extract the data from the two separate reports and combining the attributes into a new one. Ultimately, I decided PowerShell would be faster. The script below requires that the MS 365 modules be installed on the machine it is run from. This Microsoft article has instructions for installing them. https://learn.microsoft.com/en-us/microsoft-365/enterprise/connect-to-all-microsoft-365-services-in-a-single-windows-powershell-window?view=o365-worldwide

#Import Required Modules 
Import-Module ExchangeOnlineManagement
Import-Module Microsoft.Online.SharePoint.PowerShell

#Connect to the Tennant
Connect-ExchangeOnline
Connect-SpOService -Url https://URL to top level SharePoint Site 

#Retrieve Data
Get-Mailbox -ResultSize Unlimited | Select-Object DisplayName, UserPrincipalName, ForwardingSmtpAddress, DeliverToMailboxAndForward, 
    @{N="MailboxSize"; E={(Get-MailboxStatistics -Identity $_.UserPrincipalName | Select-Object TotalItemSize).TotalItemSize}}, 
    @{N="MailboxLastLogon"; E={(Get-MailboxStatistics -Identity $_.UserPrincipalName | Select-Object LastLogonTime).LastLogonTime}}, 
    @{N="OneDriveUsedGB"; E={(Get-SPOSite -IncludePersonalSite $true -Limit all -Filter "Owner -like '$($_.UserPrincipalName)'" | Select-Object   StorageUsageCurrent).StorageUsageCurrent/1024}} |
Export-Csv -Path $env:userprofile\Documents\365_Use_Report.csv -NoTypeInformation