Export a 30-Day Shared Mailbox Usage Report with Exchange Online PowerShell
Question details
The user needs a 30-day report of sent and received message activity across shared Microsoft 365 mailboxes.

- Product
- Microsoft 365 Exchange Online
- Device & OS
- not provided
- Scenario
- Export shared mailbox message activity with PowerShell for review or reporting.
- Observed behavior
- The desired result is an exported report showing sent and received activity for each shared mailbox over the selected 30-day period.
Confirm the shared mailbox addresses, reporting end date, and CSV export location. Install the ExchangeOnlineManagement PowerShell module if needed and use an account with permission to run message traces.
Export shared mailbox message trace counts with PowerShell
Use Exchange Online message traces to create an approximate 30-day activity report for selected shared mailbox addresses.
The original script was not provided. The example below counts delivered message trace records in three 10-day windows; it is not a mailbox usage report and may differ from counts of messages stored in a mailbox.
Trace records are counted per recipient, so a sent message with multiple recipients can contribute multiple records. Address aliases, send-on-behalf activity, and trace retention or data availability can also affect the totals.
Open PowerShell and run `Connect-ExchangeOnline`. Sign in with an account authorized to run message traces.
Set the shared mailbox addresses, end date, and export path. For example: `$mailboxes = @('shared1@contoso.com','shared2@contoso.com'); $end = [datetime]::UtcNow; $path = './shared-mailbox-trace.csv'`. Replace the example addresses and choose the end date and path for your environment.
Run the following example after setting the parameters: `$report = foreach ($mailbox in $mailboxes) { $sent = @(); $received = @() for ($i = 3; $i -ge 1; $i--) { $start = $end.AddDays(-10 * $i) $stop = $end.AddDays(-10 * ($i - 1)) $s = @(Get-MessageTraceV2 -SenderAddress $mailbox -StartDate $start -EndDate $stop -Status Delivered -ResultSize 5000) $r = @(Get-MessageTraceV2 -RecipientAddress $mailbox -StartDate $start -EndDate $stop -Status Delivered -ResultSize 5000) if ($s.Count -ge 5000 -or $r.Count -ge 5000) { throw 'A query reached the result limit. Use pagination or smaller time windows before exporting.' } $sent += $s; $received += $r } [pscustomobject]@{ Mailbox = $mailbox StartUtc = $end.AddDays(-30) EndUtc = $end SentTraceRecords = @($sent | Group-Object MessageTraceId, RecipientAddress).Count ReceivedTraceRecords = @($received | Group-Object MessageTraceId, RecipientAddress).Count } } $report | Export-Csv -Path $path -NoTypeInformation`
Open the CSV at the path you selected and check the date range and counts against a sample message trace. Run `Disconnect-ExchangeOnline` when you finish.

Review your shared mailbox report in WPS Spreadsheets
Exchange Online generates the message trace report; WPS Office provides a free, lightweight alternative for opening and reviewing the exported CSV. Its familiar interface and Office format support make it easy to move spreadsheet work from Microsoft Office.

Frequently Asked Questions
What permissions do I need to run the report?
Use an Exchange Online account with permission to run message traces, then connect with `Connect-ExchangeOnline`. Ask your Microsoft 365 administrator to grant the appropriate access if the commands are unavailable.
Why does the example query three 10-day windows?
`Get-MessageTraceV2` limits the date range of an individual query. The example divides the 30-day period into three windows and deduplicates trace records at their boundaries.
Why might sent trace counts differ from the Sent Items folder?
The report counts delivered trace records per recipient, not stored messages. A message sent to multiple recipients can produce multiple records, and send-on-behalf activity or aliases may not match the shared mailbox address used in the query.
What should I do if a query reaches 5,000 results?
Use supported message trace pagination or query smaller time windows, then deduplicate the combined records before counting. Do not treat a capped query as a complete report.




