How it works · The archive · Reports · Quick start · User guide · Developer guide
Important
Files downloaded from the Internet may be blocked by Windows and fail to run. Before using this project, unblock every file in the downloaded folder:
Get-ChildItem "C:\Chemin\Du\Dossier" -Recurse -File -Force | Unblock-FileReplace the example path with the folder where you downloaded or extracted this project.
Which messages are in this archive? Did these people receive this contract, and where is it now — in the mailbox, in the archive, or deleted? eDiscovery answers with an export, Get-MailboxFolderStatistics with counts, Outlook one mailbox at a time. None of them gives a plain list of the messages — date, subject, sender, recipients, folder — of the primary mailbox and of the archive, for many mailboxes at once.
The mail API of Microsoft Graph is documented for the primary mailbox only. But the In-Place Archive is a mailbox of its own for Exchange Online: Graph gives its ID (MBX:<ArchiveGuid>@<tenant ID>) and opens it with the same API. This tool builds on that — measured on a lab tenant — to list every message of the primary mailbox, the archive and Recoverable Items, with Microsoft Graph only: no Exchange Online PowerShell, no export. It only reads.
- The primary mailbox and the archive: every mail folder of both, with its path (
\Inbox\Projects\Alpha); Recoverable Items with-IncludeRecoverableItems(Deletions, Purges, Versions, DiscoveryHolds...). Each message says where it is: Primary or Archive, and Recoverable Items or not. - What is read: received and sent date and time, subject, sender, To, Cc, Bcc, Internet message ID, folder and path, attachments, importance, type. The reports never hold the body or the attachments.
- Filtered by Exchange: the period (
-Start,-End, received date) and the subjects (-Subject, any of them) are a$filterof Graph, written the way Exchange accepts it (the date first, thencontains()). Folders can be left out (-ExcludeFolder '\Junk Email'). - One mailbox or thousands:
-Mailboxor a list (text or CSV); one report for all of them, one per mailbox (with a summary that links to each), or both. - Large mailboxes: 16 requests in flight, 4 at a time per mailbox (a primary mailbox and its archive are two mailboxes); a large folder is read in slices of the same number of messages, side by side, cut again while read so that the 4 requests of a mailbox stay busy (39,414 meeting messages with recipients: 14 min → 3 min); each page is written to disk at once — the memory does not grow with the messages. The console and the window give the time left.
- The window, like Outlook: the search typed in the window, then the folders of each mailbox and of its archive in a tree, the first 10 messages of each folder, and a reading pane with the recipients, the dates, the folder and the content of the message selected (read on demand, with
Mail.Read, logged). - Application permissions of Microsoft Graph and a certificate:
Mail.ReadBasic.AllandUser.Read.All(Mail.Readonly for the content in the reading pane); no user account, no module.
GET /beta/users/megan.bowen@contoso.com/settings/exchange
-> "inPlaceArchiveMailboxId": "MBX:3f8b52d6-...@0b6c7d1e-..." (= ArchiveGuid of Get-EXOMailbox)
GET /v1.0/users/MBX:3f8b52d6-...@0b6c7d1e-.../mailFolders/delta
GET /v1.0/users/MBX:3f8b52d6-...@0b6c7d1e-.../mailFolders/{id}/messages?$filter=receivedDateTime ge ... and contains(subject,'...')- No Exchange Online PowerShell:
settings/exchangegives the archive ID withUser.Read.All. Without it, a CSV list can give theArchiveGuidof each mailbox (Get-EXOMailbox -Properties ArchiveGuid | Export-Csv). Mail.ReadBasic.Allis enough — measured with temporary applications: the folders and every column of the report, in the archive and in Recoverable Items too.- Not the auxiliary archives of an auto-expanding archive: a folder whose content moved there is reported Failed, the others are read.
settings/exchangeis a beta endpoint of Graph.
Every measurement is in the developer guide, chapter 3 and appendix C.
Each run writes MailboxMessageReport-Messages.csv (every message; a list of thousands of recipients cut to fit an Excel cell, with their number), -Mailboxes.csv, -Folders.csv, -Summary.json and a self-contained HTML report with every message, compressed, in a table with filters (1,000,000 messages: 32 MB, open in 4 s), in a folder of its own; with -Layout PerMailbox or Both, the CSV and HTML report of each mailbox in Mailboxes\.
| Item | Requirement |
|---|---|
| Exchange | Exchange Online: the primary mailbox, its In-Place Archive (not the auxiliary archives) and Recoverable Items |
| PowerShell | 7.4 or later — a portable zip is enough; 7.5 or later for the Windows 11 look of the window |
| Windows | Windows 10 / 11 or Windows Server 2016 to 2025; the window needs a desktop session, the command line runs anywhere (scheduled task) |
| Application | An application registered in Microsoft Entra with the application permissions Mail.ReadBasic.All and User.Read.All (admin consent), and a certificate whose private key is in the Windows store of the account that runs the tool (developer guide, chapter 5) |
| Account | No Exchange or Entra role to run it: the application signs in. No module. |
| Network | HTTPS to login.microsoftonline.com and graph.microsoft.com |
Download MailboxMessageReport-<version>.zip from the latest release, extract it (for example in C:\Tools) and unblock the files (command at the top of this page). You can also copy the repository package folder.
cd C:\Tools\MailboxMessageReport-2.1.0
notepad .\config\MailboxMessageReport.config.psd1 # tenant, application, certificate thumbprint
.\Invoke-MailboxMessageReport.ps1 -Gui # the window
# Or the command line: nothing is ever changed in a mailbox
.\Invoke-MailboxMessageReport.ps1 -Mailbox megan.bowen@contoso.com # primary mailbox and archive
.\Invoke-MailboxMessageReport.ps1 -Mailbox megan.bowen@contoso.com -Location Archive -Start 2019-01-01 -End 2019-12-31
.\Invoke-MailboxMessageReport.ps1 -MailboxFile .\team.csv -Subject 'Contrat Alpha' -IncludeRecoverableItems -Layout Both
.\Invoke-MailboxMessageReport.ps1 -Mailbox room-paris-01@contoso.com -SkipRecipients # very large folders, fastOne command per everyday question — what is in this archive, who received this message and where it is now, what arrived in a period, a report for every mailbox of a team: see the user guide.
The package folder of this repository holds exactly the files needed to run, with the guides. The zip of each release contains the same run-time files with the HTML guides; .\tools\New-MailboxMessageReportPackage.ps1 builds that zip content from the repository.
| Guide | Content |
|---|---|
| User guide | For the people who run the tool: prerequisites, the one-time setup and everyday commands only — the messages of an archive, where a message is, a period, a team, the archive without User.Read.All, a very large mailbox, the window, the results. |
| Developer guide | Everything else: how it works, how the archive is read through Microsoft Graph (measured), what is read and how it is filtered, the application and the least permissions, every setting and parameter, the window, the report, the files produced, the architecture, performance and limits, tests, troubleshooting, security. |
Both guides also exist as a single HTML file with a light and a dark theme (package/docs/MailboxMessageReport-UserGuide.html, package/docs/MailboxMessageReport-Guide.html): download them and open them locally, or use the copies in the release zip.
.\Run-Tests.ps1 # Pester 6.1+, a simulated Exchange Online tenant, no network
pwsh -File .\tools\Measure-MailboxMessageReport.ps1 -Messages 500000 -Simulated # time of each step, synthetic dataThe tool was also validated on a lab tenant: primary mailboxes and archives read through their MBX: IDs, Recoverable Items, mailboxes without archive, on-premises and not found, a list with ArchiveGuid and the permissions measured with temporary applications, periods and subjects, a folder of 39,419 messages read in 16 slices cut again while read — every message once (developer guide, appendix C).
MIT.
This Script is a Personal project. It's provided "AS-IS". It's not an official Microsoft product so no support can be expected from Microsoft.
As any scripts you must read carefully the documentation and test it first in a Test environment before any run in Production.
The archive is read through an ID that Microsoft Graph gives (a beta endpoint) and opens, but that its documentation does not describe for the archive: test it in your environment before production use. The reports contain personal data (addresses, subjects): store and share them accordingly.





