Back to script library
Entra / Microsoft 365 · Exchange Online

Check shared mailbox quotas

Example of how to check the current quota usage of shared mailboxes and email.

Connect & set up

Run these once per session. All scopes are read-only unless the script makes changes.

Connect-ExchangeOnline

Run it

The main script. Copy it, or download the .ps1 and run it from your console.

param(
[string] $TenantId = "a662313f-14fc-43a2-9a7a-d2e27f4f3478" # Define your tenant identifier here",
[string] $AppId = "d86b1929-b818-411b-834a-206385bf5347" # Define the app identifier",
[string] $CertThumbPrint = "F79286DB88C21491110109A0222348FACF694CBD" # Define the certificate thumbprint"
)
Function Add-MessageRecipients {
# Function to build an addressee list to send email
[cmdletbinding()]
Param(
[array]$ListOfAddresses )
ForEach ($SMTPAddress in $ListOfAddresses) {
@{
emailAddress = @{address = $SMTPAddress}
}
}
}
# Need to connect to Exchange Online to get mailbox information
If ($Null -eq (Get-ConnectionInformation)) {
Connect-ExchangeOnline
}
# Connect to the Graph to retrieve information about mailbox licenses and send messages. This
# uses an Entra ID registered app authenticated using a client thumbprint. The app has consent for the
# necessary User.Read.All and Mail.Send.All permissions.
# Get rid of any existing Graph sessions to make sure that we pick up the correct permissions
Disconnect-MgGraph | Out-Null
Connect-MgGraph -NoWelcome -TenantId $TenantId -AppId $AppId -CertificateThumbprint $CertThumbPrint
# Mailbox to receive notifications when a shared mailbox has no registered user with full access
$DefaultNotificationAddress = "Lotte.Vetler@Office365itpros.com"
# Address to send notification messages from
$MailSentFrom = "Azure.Management.Account@office365itpros.com"
# Service plan identifiers to check for licensing
[array]$ServicePlans = "efb87545-963c-4e0d-99df-69c6916d9eb0"
Write-Host "Searching for shared mailboxes..."
[array]$SharedMailboxes = Get-ExoMailbox -RecipientTypeDetails SharedMailbox -ResultSize Unlimited -PropertySet Quota -Properties DisplayName
If (!($SharedMailboxes)) {
Write-Host "Can't find any shared mailboxes to process"
} Else {
$QuotaReport = [System.Collections.Generic.List[Object]]::new()
ForEach ($Mbx in $SharedMailboxes) {
$ExoP2 = $False; $NoOwnerFlag = $False
Write-Host "Checking accounts with full access rights to shared mailbox..."
[array]$Owners = Get-ExoMailboxPermission -Identity $Mbx.ExternalDirectoryObjectId | Where-Object {$_.User -ne "NT AUTHORITY\SELF"} | `
Select-Object User, AccessRights | Where-Object {$_.AccessRights -Like "FullAccess"} | Select-Object -ExpandProperty User
If (!($Owners)) { # No owners found - use default notification address
$Owners += $DefaultNotificationAddress
$NoOwnerFlag = $True
Write-Host ("No owners found for mailbox {0}" -f $Mbx.DisplayName) -ForegroundColor Red
} Else {
[array]$ExpandedOwners = $Null
ForEach ($Owner in $Owners) {
$OwnerType = (Get-EXORecipient -Identity $Owner).RecipientTypeDetails
Switch ($OwnerType) {
"MailUniversalSecurityGroup" {
$ExpandedOwners += (Get-DistributionGroupMember -Identity $Owner).PrimarySmtpAddress }
"UserMailbox" {
$ExpandedOwners += $Owner }
}
}
[array]$Owners = $ExpandedOwners | Sort-Object -Unique
$OutputOwners = $Owners -join ", "
Write-Host ("Found owners {0} for mailbox {1}" -f $OutputOwners, $Mbx.DisplayName )
}
# Check if the shared mailbox has an Exchange Online Plan 2 license to allow for a larger quota
[array]$Licenses = Get-MgUserLicenseDetail -UserId $Mbx.ExternalDirectoryObjectId
If ($Licenses) {
[array]$ServicePlansMbx = $Licenses.ServicePlans | Where-Object {$_.ProvisioningStatus -eq "Success"} | Select-Object -ExpandProperty ServicePlanId
ForEach ($SP in $ServicePlans) {
If ($SP -in $ServicePlansMbx) {
Write-Host ("Exchange Online Service Plan 2 found for mailbox {0}" -f $Mbx.displayName )
$ExOP2 = $True
}
}
}
Write-Host "Fetching mailbox usage statistics"
[array]$MbxStats = Get-ExoMailboxStatistics -Identity $Mbx.ExternalDirectoryObjectId
[INT64]$QuotaUsed = [convert]::ToInt64(((($MbxStats.TotalItemSize.ToString().split("(")[-1]).split(")")[0]).split(" ")[0]-replace '[,]',''))
# Byte count for mailbox quota
[INT64]$MbxQuota = [convert]::ToInt64(((($Mbx.ProhibitSendReceiveQuota.ToString().split("(")[-1]).split(")")[0]).split(" ")[0]-replace '[,]',''))
$MbxQuotaGB = [math]::Round(($MbxQuota/1GB),2)
$QuotaPercentUsed = [math]::Round(($QuotaUsed/$MbxQuota)*100,2)
$QuotaUsedGB = [math]::Round(($QuotaUsed/1GB),2)
$ReportLine = [PSCustomObject]@{
Mailbox = $Mbx.Identity
Name = $Mbx.DisplayName
Email = $Mbx.PrimarySmtpAddress
Quota = ("{0} GB" -f $MbxQuotaGB)
Items = $MbxStats.ItemCount
Size = ("{0} GB" -f $QuotaUsedGB)
"% Used" = $QuotaPercentUsed
Owners = $Owners
License = $EXOP2
"No Owner" = $NoOwnerFlag}
$QuotaReport.Add($ReportLine)
}
}
# Code to email the owners of each shared mailbox
[int]$i=0
ForEach ($Item in $QuotaReport) {
Write-Host ("Sending notification message for mailbox {0}" -f $Item.Name)
# Get the list of shared mailbox owners
$EmailRecipients = @( $Item.Owners.Split(",").Trim() )
# Add them as message recipients
[array]$MsgToRecipients = Add-MessageRecipients -ListOfAddresses $EmailRecipients
$MsgSubject = ("Shared Mailbox Quota Information for {0}" -f $Item.Mailbox)
$HtmlHead = "<h2>Mailbox Quota Information</h2><p>The current quota information for the shared mailbox is as follows.</p>"
$HtmlBody = $Item | ConvertTo-Html -Fragment
$HtmlMsg = "</body></html><p>" + $HtmlHead + $Htmlbody + "<p>"
# Construct the message body
$MsgBody = @{
Content = "$($HtmlMsg)"
ContentType = 'html'
}
$Message = @{subject = $MsgSubject}
$Message += @{toRecipients = $MsgToRecipients}
$Message += @{body = $MsgBody}
$Params = @{'message' = $Message}
$Params += @{'saveToSentItems' = $True}
$Params += @{'isDeliveryReceiptRequested' = $True}
# And send the message using the parameters that we've filled in
Send-MgUserMail -UserId $MailSentFrom -BodyParameter $Params
$i++
}
Write-Host ("Processing complete and quota usage notifications sent for {0} mailboxes" -f $i)

Parameters

ParameterDefaultNotes
-TenantIda662313f-14fc-43a2-9a7a-d2e27f4f3478" # Define your tenant identifier hereMicrosoft Entra tenant ID for app-only Graph authentication.
-AppIdd86b1929-b818-411b-834a-206385bf5347" # Define the app identifierApplication (client) ID for the app registration used to connect.
-CertThumbPrintF79286DB88C21491110109A0222348FACF694CBD" # Define the certificate thumbprintCertificate thumbprint for app-only Graph authentication.
Attribution