Getty Images/iStockphoto

Checking Exchange Online health with PowerShell automation

Learn how to use scripts to streamline Exchange Online monitoring, produce reports and address issues related to mail flow and other key areas before they affect your organization.

Exchange Online health checks aren't just for routine maintenance but to stay ahead of bigger problems and maintain order in Microsoft's hosted email platform.

PowerShell elevates monitoring by automating tasks to cut down on manual work, and helps instill confidence in the system's reliability. A sophisticated script can give a clear view of Exchange Online to see where things are working properly and where help is needed. These insights let you act early to adjust resources or investigate unusual activity. PowerShell is not just a tool -- it's your frontline defense mechanism.

This article will show you how to set up and use PowerShell to automate Exchange Online health checks, detect issues and generate reports to keep the email system running reliably.

Advantages of using PowerShell to check Exchange Online

When it comes to monitoring Exchange Online, PowerShell offers multiple benefits:

  1. Automated scheduling. You can schedule PowerShell scripts to run at specific intervals, eliminating the need for manual intervention and ensuring consistent oversight.
  2. Detailed system insights. PowerShell can access key metrics in Exchange Online, such as message tracking logs and mailbox statistics, to reveal anomalies and track usage trends in your Exchange Online infrastructure.
  3. Customized monitoring. You can tailor scripts for specific locations, such as mailbox growth, user activity or delivery delays, for control over what to monitor and when to trigger alerts.
  4. Reporting features. You can generate reports for auditing or sharing information with stakeholders.

PowerShell provides comprehensive tools to monitor and manage your Exchange Online environment effectively.

Prerequisites for using PowerShell with Exchange Online

Before you can start monitoring Exchange Online using PowerShell, there are a few prerequisites to consider.

First, ensure you have the necessary permissions to access and monitor Exchange Online. Typically, this involves being an Exchange Online administrator role member or assigning the necessary Exchange Online management roles to your account.

Next, you must install the Exchange Online PowerShell V3 (EXO V3) module to connect to your Exchange Online environment and work within it.

Lastly, develop a basic understanding of PowerShell scripting. You can find prebuilt scripts online but it's helpful to know how to customize and modify scripts. Learning the basics of PowerShell, such as variables, loops and conditional statements, will enable you to create more advanced monitoring scripts.

To use PowerShell with Exchange Online, you must complete the following:

  1. Set up your environment: You need a compatible Windows environment to use PowerShell with Exchange Online. The recommended OS is Windows 10 or 11.
  2. Install the required software:
    1. PowerShell: Install the latest version of PowerShell. As of publication, PowerShell 7.4 or later is the latest version, but you should download the most recent one. Windows PowerShell 5.1 will also work but Microsoft recommends the newer open source version of PowerShell.
    2. Microsoft .NET Framework: Exchange Online requires .NET Framework, specifically version 4.7.1 or later.
    3. PowerShellGet and PackageManagement modules: These modules are required for REST API-based connections used by the EXO V3 module.
  3. Install the EXO V3 module: The PowerShell module provides cmdlets for managing Exchange Online. You can install it using the PowerShell command: 

Install-Module -Name ExchangeOnlineManagement

  1. Set execution policy: You might need to set the execution policy in PowerShell to allow the execution of scripts. You can do this using the Set-ExecutionPolicy cmdlet. Be careful when setting this policy, as it can have security implications. A commonly used policy for this purpose is RemoteSigned.
  2. Connect to Exchange Online: Use the Connect-ExchangeOnline cmdlet to connect to Exchange Online. The system will prompt you to enter your Exchange Online credentials.

As a reminder, always refer to the latest documentation from Microsoft for the most up-to-date instructions. Also, these steps might require administrative privileges. Be sure to understand the implications of each step, especially when changing system settings or execution policies.

Monitor mail flow in Exchange Online with PowerShell

Monitoring mail flow in Exchange Online is crucial to ensure that email is sent and received correctly. PowerShell provides several cmdlets that can help you check mail flow and troubleshoot any issues that might arise. One of the key cmdlets for this work is Get-MessageTraceV2, the replacement for the legacy Get-MessageTrace cmdlet that Microsoft deprecated in September 2025.

Get-MessageTraceV2 lets you retrieve information about messages sent or received within a specific period. You can filter the results based on various criteria, such as sender, recipient, subject or message status. By regularly running Get-MessageTraceV2 and analyzing the results, you can identify any potential mail flow issues and take appropriate actions. The following are examples of using Get-MessageTraceV2.

# Retrieve information about messages sent or received in the last 24 hours
Get-MessageTraceV2 `
    -StartDate (Get-Date).AddDays(-1) `
    -EndDate (Get-Date)
# Retrieve messages sent by a specific sender in the last 24 hours
Get-MessageTraceV2 `
    -SenderAddress [email protected] `
    -StartDate (Get-Date).AddDays(-1) `
    -EndDate (Get-Date)

# Retrieve information about messages that failed in the last 24 hours
Get-MessageTraceV2 `
    -DeliveryStatus Failed `
    -StartDate (Get-Date).AddDays(-1) `
    -EndDate (Get-Date)

You can use Get-MessageTraceV2 to automate checks and export entries based on delivery failures. The following script retrieves the record of the last seven days of failed delivery entries, exports it as a CSV for further review, then disconnects from Exchange Online.

Connect-ExchangeOnline `
    -UserPrincipalName [email protected] `
    -ShowProgress $true
$endDate = Get-Date
$startDate = $endDate.AddDays(-7)
$failedMessages = Get-MessageTraceV2 `
    -StartDate $startDate `
    -EndDate $endDate | `
    Where-Object { $_.DeliveryStatus -eq "Failed" }
if ($failedMessages) {
    $failedMessages | Export-Csv `
        -Path "C:\Temp\FailedMessages.csv" `
        -NoTypeInformation
} else {
    Write-Host "No failed messages found in the last seven days."
}
Disconnect-ExchangeOnline -Confirm:$false

Assess mailbox sizes using PowerShell

In addition to Get-MessageTraceV2, PowerShell also offers other cmdlets such as Get-EXOMailboxStatistics -- the replacement for the Get-MailboxStatistics cmdlet -- to monitor mailbox usage in Exchange Online.

Get-EXOMailboxStatistics provides valuable information about mailbox sizes, item counts and last logon times. By monitoring these metrics, you can proactively address performance issues and storage limits that can affect the user's experience.

The following are examples of using the command Get-EXOMailboxStatistics.

# Get mailbox statistics for a specific user
Get-EXOMailboxStatistics `
    -Identity [email protected]

# Get specific mailbox statistics for a user
Get-EXOMailboxStatistics `
    -Identity [email protected] | `
        Select DisplayName, LastLogonTime, TotalItemSize

You can also use Get-EXOMailboxStatistics in a PowerShell script to automate the retrieval of mailboxes, then check whether the total item size exceeds a set threshold.

The script exports the list of any mailboxes that exceed the threshold of 10 GB to a CSV file.

Connect-ExchangeOnline `
    -UserPrincipalName [email protected] `
    -ShowProgress $true

$mailboxStats = Get-EXOMailbox -ResultSize Unlimited | ForEach-Object {
    $stats = Get-EXOMailboxStatistics -Identity $_.UserPrincipalName
    [PSCustomObject]@{
        DisplayName       = $_.DisplayName
	TotalItemSizeMB   = [math]::Round(($stats.TotalItemSize.ToMB()), 0)
        ItemCount         = $stats.ItemCount
        LastLogonTime     = $stats.LastLogonTime
    }
}

$sizeThreshold = 10240  # 10 GB


$largeMailboxes = $mailboxStats | Where-Object {
    $_.TotalItemSizeMB -gt $sizeThreshold
}

if ($largeMailboxes) {
    $largeMailboxes | Export-Csv `
        -Path "C:\Temp\LargeMailboxes.csv" -NoTypeInformation
} else {
    Write-Host "No large mailboxes found."
}

Tracking user activities in Exchange Online using PowerShell

Monitoring user activities on Exchange Online is crucial for security, compliance and troubleshooting purposes. PowerShell provides several cmdlets to monitor user activities and track suspicious or unauthorized actions.

The Search-MailboxAuditLog cmdlet was previously used to search mailbox audit logs for specific user activities, such as message deletions, mailbox logins or access by external parties. But Microsoft deprecated this cmdlet in favor of the Search-UnifiedAuditLog cmdlet, which provides a unified view of audit events across Microsoft 365 services.

The following script checks for a range of mailbox-related activity by a user.

# Search for Exchange mailbox audit events in the last seven days $startDate = (Get-Date).AddDays(-7)
$endDate = Get-Date
Search-UnifiedAuditLog `
  -StartDate $startDate `
  -EndDate $endDate `
  -UserIds "[email protected]" `
  -RecordType ExchangeMailbox `
  -Operations SendAs, HardDelete, SoftDelete `

PowerShell offers other cmdlets optimized for Exchange Online management, such as
Get-EXOMailboxPermission and Get-EXOMailboxFolderPermission, which are used to retrieve information about mailbox and folder permissions. These cmdlets help ensure users have the appropriate access rights and privileges to mailboxes and the contents.

# Get mailbox permissions for a specific user
Get-EXOMailboxPermission -Identity [email protected]

# Get non-default mailbox permissions for a user
Get-EXOMailboxPermission -Identity [email protected] | `
Where-Object { 
    ($_.IsInherited -eq $false) -and ($_.User -notlike "NT AUTHORITY\SELF")
}

# Get folder permissions for a specific folder in a user's mailbox
Get-EXOMailboxFolderPermission -Identity [email protected]:\Inbox

# Get folder permissions for all folders in a user's mailbox
$mailbox = "[email protected]"
$folders = Get-MailboxFolderStatistics -Identity $mailbox | `
    Select-Object -ExpandProperty FolderPath
foreach ($folder in $folders) {
    Get-EXOMailboxFolderPermission `
        -Identity "$mailbox`:$folder" | `
        Select-Object @{Name='FolderPath';Expression={$folder}}, User, AccessRights
}

Generate an Exchange Online report with PowerShell

Building reports of Exchange Online activities is valuable for auditing, compliance and communication purposes. PowerShell can generate customized reports based on specific criteria and requirements.

To build a report of Exchange activities, you can use PowerShell cmdlets such as Get-MessageTraceV2, Get-EXOMailboxStatistics and Search-UnifiedAuditLog. By combining the outputs of these cmdlets and formatting the data using PowerShell's formatting cmdlets, you can create comprehensive reports that include information, such as mail flow statistics, mailbox sizes and user activities.

 PowerShell can export the reports in various formats, such as CSV or HTML, to make it easier to share the information with stakeholders or import it into other systems for further analysis. By regularly generating and reviewing these reports, you can learn about the usage and performance of your Exchange Online environment, identify trends or anomalies and make informed decisions to optimize operations.

 The following example script checks mail flow and mailbox statistics from the last seven days and exports it into a CSV file:

Connect-ExchangeOnline -UserPrincipalName [email protected]
$mailboxes = Get-EXOMailbox -ResultSize Unlimited
$report = foreach ($mailbox in $mailboxes) {
    $mailboxStats = Get-EXOMailboxStatistics -Identity $mailbox.UserPrincipalName |
        Select-Object DisplayName, TotalItemSize, ItemCount
    $messageTrace = Get-MessageTraceV2 `
        -RecipientAddress $mailbox.UserPrincipalName `
        -StartDate (Get-Date).AddDays(-7) `
        -EndDate (Get-Date) | Measure-Object | Select-Object -Property Count
    $auditLogs = Search-UnifiedAuditLog `
        -UserIds $mailbox.UserPrincipalName `
        -StartDate (Get-Date).AddDays(-7) `
        -EndDate (Get-Date) `
        -RecordType ExchangeMailbox `
        -Operations SendAs, HardDelete, SoftDelete | Measure-Object | `
        Select-Object -Property Count
    [PSCustomObject]@{
        UserPrincipalName    = $mailbox.UserPrincipalName
        DisplayName          = $mailboxStats.DisplayName
        TotalItemSize        = $mailboxStats.TotalItemSize
        ItemCount            = $mailboxStats.ItemCount
        MessagesLast7Days    = $messageTrace.Count
        AuditLogsLast7Days   = $auditLogs.Count
    }
}
$report | Export-Csv -Path "C:\Temp\ExchangeReport.csv" -NoTypeInformation
Disconnect-ExchangeOnline -Confirm:$false

You could also change the PowerShell code to export the report as HTML:

$report | ConvertTo-Html `
-Title "Exchange Activities Report" `
-Body "<h1>Exchange Online Activities Report</h1>" | `
Out-File "C:\Temp\ExchangeActivitiesReport.html"

You can modify this script further to include other details within the report, such as the failed email delivery for the last seven days.

Connect-ExchangeOnline -UserPrincipalName [email protected]
$mailboxes = Get-EXOMailbox -ResultSize Unlimited
$report = foreach ($mailbox in $mailboxes) {
    $mailboxStats = Get-EXOMailboxStatistics `
        -Identity $mailbox.UserPrincipalName |
        Select-Object DisplayName, TotalItemSize, ItemCount
    $messageTrace = Get-MessageTraceV2 `
        -RecipientAddress $mailbox.UserPrincipalName `
        -StartDate (Get-Date).AddDays(-7) `
        -EndDate (Get-Date) | Measure-Object | Select-Object -Property Count
    $auditLogs = Search-UnifiedAuditLog `
        -UserIds $mailbox.UserPrincipalName `
        -StartDate (Get-Date).AddDays(-7) `
        -EndDate (Get-Date) `
        -RecordType ExchangeMailbox `
        -Operations SendAs, HardDelete, SoftDelete | Measure-Object | Select-Object -Property Count
    [PSCustomObject]@{
        UserPrincipalName    = $mailbox.UserPrincipalName
        DisplayName          = $mailboxStats.DisplayName
        TotalItemSize        = $mailboxStats.TotalItemSize
        ItemCount            = $mailboxStats.ItemCount
        MessagesLast7Days    = $messageTrace.Count
        AuditLogsLast7Days   = $auditLogs.Count
    }
}
$failedMessages = Get-MessageTraceV2 `
    -StartDate (Get-Date).AddDays(-7) `
    -EndDate (Get-Date) | Where-Object { $_.Status -eq "Failed" }
$reportHtml = $report | ConvertTo-Html `
    -Title "Exchange Activities Report" `
    -Body "<h1>Exchange Online Activities Report</h1>"
$failedMessagesHtml = $failedMessages | ConvertTo-Html `
    -Title "Failed Messages" `
    -Body "<h1>Failed Messages</h1>" -As List
$finalHtmlReport = $reportHtml + $failedMessagesHtml
$finalHtmlReport | Out-File "C:\Temp\ExchangeActivitiesReport.html"

PowerShell automation helps with Exchange Online health checks

PowerShell is a powerful tool to maintain the health of Exchange Online thanks to its automation, flexibility and extensive reporting capabilities. The EXO V3 module is vital to streamline monitoring tasks, gather valuable insights and proactively address potential issues.

 Whether it's monitoring mail flow or user activities, PowerShell provides a comprehensive set of cmdlets to help you effectively monitor and manage your Exchange Online infrastructure. Invest your time to learn PowerShell and how to use the EXO V3 module to enjoy the benefits of efficient monitoring and management of Exchange Online.

 Liam Cleary is the founder and owner of SharePlicity, a technology consulting company that helps organizations with internal and external collaboration, document and records management, business process automation, automation tool deployment and security controls and protection. Cleary's areas of expertise include security on the Microsoft 365 and Azure platforms, PowerShell automation and IT administration. Cleary is a Microsoft MVP and a Microsoft Certified Trainer.

Dig Deeper on Microsoft messaging and collaboration