Overview

Tracking mailbox sizes in Office 365 is critical for managing storage and preventing disruptions.

Our tenant has a large number of mailboxes. We needed a way to check active users and their current storage usage accurately.

Microsoft’s built-in tools lag by multiple days and don’t provide a real-time view of mailbox sizes.

To solve this, I created a PowerShell script that:

  • Pulls real-time mailbox size data using Microsoft’s CLI tools
  • Targets a specific distribution list instead of scanning the entire tenant
  • Exports results to a CSV file for tracking and analysis
  • Ensures we work with up-to-date and accurate data

This approach helps IT teams proactively manage storage and avoid mailbox overages.


What This Script Does

Retrieves:

  • User’s name & email address
  • Mailbox size in GB
  • Whether archive is enabled
  • Retention policy assigned
  • Number of mailbox items
  • Archive size
  • Auto-Archive status

Targets:

  • A specific distribution list instead of scanning all mailboxes.

Outputs:

  • A CSV file that can be opened in Excel for easy analysis.

Requirements

Before running this script, ensure you have:

  • PowerShell 5.1+
  • Exchange Online PowerShell Module
  • Administrator privileges
  • A distribution list containing all users you need to check

The PowerShell Script

# Define the group email address
$groupEmail = "staff@domain.com"

# Get members of the distribution group
$groupMembers = Get-DistributionGroupMember -Identity $groupEmail | 
    Select-Object Name, DisplayName, PrimarySmtpAddress, RecipientType

# Export to CSV
$exportPath = "C:\365_reports\staff_" + (Get-Date -Format "yyyyMMdd") + ".csv"
$groupMembers | Export-Csv -Path $exportPath -NoTypeInformation

Write-Output "Group members exported to $exportPath"

# Target only Members of Staff + AutoExpand
$staffGroupMembers = Get-DistributionGroupMember -Identity "staff@domain.com" | Where-Object { $_.RecipientType -eq 'UserMailbox' }

# Fetch mailbox statistics for group members only
$staffGroupMembers | 
    ForEach-Object {
        $mailboxDetails = Get-Mailbox -Identity $_.PrimarySmtpAddress
        $stats = Get-MailboxStatistics -Identity $_.PrimarySmtpAddress
        $archiveStats = Get-MailboxStatistics -Archive -Identity $_.PrimarySmtpAddress

        $totalItemSizeGB = switch ($stats.TotalItemSize.ToString().Split(" ")[1]) {
            "KB" { [math]::Round([double]$stats.TotalItemSize.ToString().Split(" ")[0] / 1MB, 2) }
            "MB" { [math]::Round([double]$stats.TotalItemSize.ToString().Split(" ")[0] / 1KB, 2) }
            "GB" { [math]::Round([double]$stats.TotalItemSize.ToString().Split(" ")[0], 2) }
            Default { [double]$stats.TotalItemSize.ToString().Split(" ")[0] }
        }

        $archiveStatus = if ($archiveStats.ArchiveQuota -ne "0 B") {"Enabled"} else {"Disabled"}
        $autoArchiveEnabled = if ($mailboxDetails.AutoExpandingArchiveEnabled) {"Enabled"} else {"Disabled"}

        $_ | Select-Object DisplayName, 
            PrimarySmtpAddress, 
            @{Name="RetentionPolicy";Expression={$mailboxDetails.RetentionPolicy}},
            @{Name="TotalItemSizeGB";Expression={$totalItemSizeGB}},
            @{Name="ItemCount";Expression={$stats.ItemCount}},
            @{Name="ArchiveStatus";Expression={$archiveStatus}},
            @{Name="ArchiveSize";Expression={$archiveStats.TotalItemSize}},
            @{Name="AutoArchiveEnabled";Expression={$autoArchiveEnabled}}
    } | 
    Export-Csv -Path ("C:\365_reports\StaffMailboxStatistics_" + (Get-Date -Format "yyyyMMdd") + ".csv") -NoTypeInformation

Script Breakdown & Customization Guide

1. Define the Distribution List

$groupEmail = "staff@domain.com"

Replace staff@domain.com with your distribution list. Ensure the list includes only active users.


2. Get Distribution List Members

$groupMembers = Get-DistributionGroupMember -Identity $groupEmail | 
    Select-Object Name, DisplayName, PrimarySmtpAddress, RecipientType

Retrieves users from the distribution list and selects name, display name, email, and recipient type.


3. Export Members to CSV

$exportPath = "C:\365_reports\staff_" + (Get-Date -Format "yyyyMMdd") + ".csv"
$groupMembers | Export-Csv -Path $exportPath -NoTypeInformation

Saves the list to a CSV file using the current date in the filename. Change the file path if needed.


4. Target Only User Mailboxes

$staffGroupMembers = Get-DistributionGroupMember -Identity "staff@domain.com" | Where-Object { $_.RecipientType -eq 'UserMailbox' }

Filters for user mailboxes only — excludes shared mailboxes and groups.


5. Get Mailbox Statistics

$staffGroupMembers | 
    ForEach-Object {
        $mailboxDetails = Get-Mailbox -Identity $_.PrimarySmtpAddress
        $stats = Get-MailboxStatistics -Identity $_.PrimarySmtpAddress
        $archiveStats = Get-MailboxStatistics -Archive -Identity $_.PrimarySmtpAddress

Retrieves mailbox size, item count, archive status, and retention policy.


6. Convert Mailbox Size to GB

$totalItemSizeGB = switch ($stats.TotalItemSize.ToString().Split(" ")[1]) {
    "KB" { [math]::Round([double]$stats.TotalItemSize.ToString().Split(" ")[0] / 1MB, 2) }
    "MB" { [math]::Round([double]$stats.TotalItemSize.ToString().Split(" ")[0] / 1KB, 2) }
    "GB" { [math]::Round([double]$stats.TotalItemSize.ToString().Split(" ")[0], 2) }
    Default { [double]$stats.TotalItemSize.ToString().Split(" ")[0] }
}

Converts mailbox size to GB for consistent reporting.


7. Check Archive & Retention Policies

$archiveStatus = if ($archiveStats.ArchiveQuota -ne "0 B") {"Enabled"} else {"Disabled"}
$autoArchiveEnabled = if ($mailboxDetails.AutoExpandingArchiveEnabled) {"Enabled"} else {"Disabled"}

Checks if archive is enabled and determines auto-archiving status.


8. Export the Final Report

$_ | Select-Object DisplayName, 
    PrimarySmtpAddress, 
    @{Name="RetentionPolicy";Expression={$mailboxDetails.RetentionPolicy}},
    @{Name="TotalItemSizeGB";Expression={$totalItemSizeGB}},
    @{Name="ItemCount";Expression={$stats.ItemCount}},
    @{Name="ArchiveStatus";Expression={$archiveStatus}},
    @{Name="ArchiveSize";Expression={$archiveStats.TotalItemSize}},
    @{Name="AutoArchiveEnabled";Expression={$autoArchiveEnabled}}

Selects all fields for the report. Modify as needed to include or exclude fields.


9. Save the Report with a Timestamp

Export-Csv -Path ("C:\365_reports\StaffMailboxStatistics_" + (Get-Date -Format "yyyyMMdd") + ".csv") -NoTypeInformation

Saves the final report as a CSV with a date-stamped filename.


Summary of Changes to Make

SectionChange
Define Distribution ListUpdate to your group email
File Export PathChange where reports are saved
Fields in ReportAdd or remove fields
Data FilteringAdjust mailbox type filters

Final Thoughts

This script helps Exchange admins automate mailbox monitoring. Customize the distribution list, fields, and export path to fit your needs.

Need help customizing the script? Email me!