Back to script library
Entra / Microsoft 365 · Users & guests

Report user inbox count

A script to show how to fetch mailbox folder statistics using a combination of PowerShell and the Microsoft Graph ListFolders API.

Connect & set up

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

Import-Module ImportExcel -ErrorAction SilentlyContinue

Run it

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

param(
[string] $TenantId = "",
[string] $AppId = ""
)
Clear-Host
# Check that we are connected to Exchange Online
Import-Module ImportExcel -ErrorAction SilentlyContinue
$ExcelAvailable = $True
[array]$ModulesLoaded = Get-Module | Select-Object -ExpandProperty Name
If ("ExchangeOnlineManagement" -notin $ModulesLoaded) {
Write-Host "Please connect to the Exchange Online Management module and then restart the script"
Break
}
# See if we can use ImportExcel
If ("ImportExcel" -notin $ModulesLoaded) {
$ExcelAvailable = $False
}
$ExcelOutput = "c:\temp\UserInboxCounts.xlsx"
$CSVOutput = "c:\temp\UserInboxCounts.csv"
# Define the values applicable for the application used to connect to the Graph - change these for your tenant
# to use the app id and app secret for the Azure AD registered app you want to use for this script
$AppSecret = 'yVh8Q~oA9.QJchbNqSDd89Iz1-xNTZ9m8PPVYdgP'
# Construct URI and body needed for authentication
$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"
$body = @{
client_id = $AppId
scope = "https://graph.microsoft.com/.default"
client_secret = $AppSecret
grant_type = "client_credentials"
}
# Get OAuth 2.0 Token
$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing
# Unpack Access Token
$token = ($tokenRequest.Content | ConvertFrom-Json).access_token
$Headers = @{
'Content-Type' = "application\json"
'Authorization' = "Bearer $Token"
'ConsistencyLevel' = "eventual" }
Write-Host "Finding user mailboxes..."
[array]$Mbx = Get-ExoMailbox -ResultSize Unlimited -RecipientTypeDetails UserMailbox | Sort-Object DisplayName
If (!($Mbx)) { Write-Host "No mailboxes found... exiting!" ; break }
$Report = [System.Collections.Generic.List[Object]]::new()
$i = 1
ForEach ($M in $Mbx) {
Write-Host ("Processing mailbox {0} of {1}: {2}" -f $i, $Mbx.Count, $M.DisplayName); $i++
$Uri = "https://graph.microsoft.com/v1.0/users/" + $M.ExternalDirectoryObjectId + "/mailFolders?`$top=250"
$FolderData = Invoke-RestMethod -Headers $Headers -Uri $Uri -UseBasicParsing -Method "GET" -ContentType "application/json"
$InboxData = $FolderData.Value | Where-Object {$_.displayname -eq "Inbox"}
$TotalMbxItems = ($FolderData.Value.totalitemcount | Measure-Object -Sum | Select-Object -ExpandProperty Sum)
$TotalMbxSize = ($FolderData.Value.SizeInBytes | Measure-Object -Sum | Select-Object -ExpandProperty Sum)
$ReportLine = [PSCustomObject][Ordered]@{ # Write out details of the mailbox
"User" = $M.DisplayName
UPN = $M.UserPrincipalName
InboxCount = $InboxData.totalItemCount
UnreadCount = $InboxData.unreadItemCount
TotalMbxFolders = $FolderData.Value.Count
TotalMbxItems = $TotalMbxItems
TotalMbxFolderSize = [math]::Round($TotalMbxsize/1Mb,2) }
$Report.Add($ReportLine)
}
# If you don't have the ImportExcel module available, you can change this to export to a CSV file using the Export-CSV cmdlet
$Report | Sort-Object UnreadCount -Descending
If ($ExcelAvailable -eq $True) {
Export-Excel -Path $ExcelOutput -WorkSheetName "Inbox Counts" -TableStyle Medium16 `
-Title "Inbox Data for Mailboxes"
Write-Host ("Excel worksheet available in {0}" -f $ExcelOutput)
} Else {
Export-CSV -NoTypeInformation $CSVOutput
Write-Host ("CSV file available in {0}" -f $CSVOutput)
}

Parameters

ParameterDefaultNotes
-TenantId""Microsoft Entra tenant ID for app-only Graph authentication.
-AppId""Application (client) ID for the app registration used to connect.
Attribution