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

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 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 ---------------------------------------------------------------------------

# Get members of the distribution group
$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

This script retrieves mailbox statistics for a specific distribution list in Exchange Online. Follow these steps to customize it for your organization.


1. Define the Distribution List

1
$groupEmail = "staff@domain.com"
  • Replace staff@domain.com with your distribution list.
  • Ensure the list includes only active users.

2. Get Distribution List Members

1
2
$groupMembers = Get-DistributionGroupMember -Identity $groupEmail | 
    Select-Object Name, DisplayName, PrimarySmtpAddress, RecipientType
  • Retrieves users from the distribution list.
  • Selects name, display name, email, and recipient type.

3. Export Members to CSV

1
2
$exportPath = "C:\365_reports\staff_" + (Get-Date -Format "yyyyMMdd") + ".csv"
$groupMembers | Export-Csv -Path $exportPath -NoTypeInformation
  • Saves the list to a CSV file.
  • Uses the current date in the filename.
  • Change the file path if needed.

4. Target Only User Mailboxes

1
$staffGroupMembers = Get-DistributionGroupMember -Identity "staff@domain.com" | Where-Object { $_.RecipientType -eq 'UserMailbox' }
  • Filters for user mailboxes.
  • Excludes shared mailboxes and groups.

5. Get Mailbox Statistics

1
2
3
4
5
$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.
  • Modify this section to include additional data if needed.

6. Convert Mailbox Size to GB

1
2
3
4
5
6
$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.
  • Ensures consistent reporting.

7. Check Archive & Retention Policies

1
2
$archiveStatus = if ($archiveStats.ArchiveQuota -ne "0 B") {"Enabled"} else {"Disabled"}
$autoArchiveEnabled = if ($mailboxDetails.AutoExpandingArchiveEnabled) {"Enabled"} else {"Disabled"}
  • Checks if archive is enabled.
  • Determines auto-archiving status.

8. Export the Final Report

1
2
3
4
5
6
7
8
$_ | 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 fields for the report.
  • Modify as needed to include or exclude fields.

9. Save the Report with a Timestamp

1
Export-Csv -Path ("C:\365_reports\StaffMailboxStatistics_" + (Get-Date -Format "yyyyMMdd") + ".csv") -NoTypeInformation
  • Saves the final report as a CSV file.
  • Modify the path if needed.

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! 🚀