An excellent method to search for messages in Exchange Online mailboxes is with PowerShell. You can tweak the commands to your liking and get the results you need. Also, an export of the results to CSV file is great, so you can filter in there. In this article, you will learn how to search emails with PowerShell.
Install Microsoft Graph PowerShell
Run Windows PowerShell as administrator and Install Microsoft Graph PowerShell.
Install-Module Microsoft.Graph -Force
Install-Module Microsoft.Graph.Beta -AllowClobber -Force
Important: Always install the Microsoft Graph PowerShell and Microsoft Graph Beta PowerShell modules. That’s because some cmdlets are not yet available in the final version, and they will not work. Update both modules to the latest version before you run a cmdlet or script to prevent errors and incorrect results.
Configure app registration in Microsoft Entra
Before you can run the commands or scripts, you must first create an app registration with the correct permissions and a client secret to authenticate with Microsoft Graph PowerShell.
1. Register new application
Register a new application in Microsoft Entra ID:
- Sign in to Microsoft Entra admin center
- Click Identity > Application > App registrations
- Click New Registration
- Name the application Search-Mail
- Select Accounts in this organizational directory only (EXOIP only – Single tenant)
- Click Register
The application Search-Mail has been successfully created. Copy the below values and paste them into Notepad, as you will need them later when connecting to Microsoft Graph PowerShell.
- Copy the Application (client) ID
- Copy the Directory (tenant) ID
2. Assign API permissions
Assign API permissions for the application that you registered in the previous step:
- Click API permission
- Click Add a permision
- Click Microsoft APIs
- Click Microsoft Graph
- Click Application permissions
- Search for User.Read.All
- Select Users > User.Read.All
- Search for Mail.Read
- Select Mail > Mail.Read
- Click Add permissions
The API permissions are added successfully. The next step is to grant admin consent.
3. Grant admin consent
You must grant admin consent for the permissions that you selected in the previous step:
- Click Grant admin consent for EXOIP
- Click Yes
- The green check mark shows that you granted admin consent successfully
4. Create Client Secret
After you register a new application in Microsoft Entra, assign API permissions, and grant admin consent, you need to create a client secret.
To create a Client Secret for your application in Microsoft Entra ID, follow these steps:
- Click Certificates & secrets
- Click Client secrets > New client secret
- Type Description
- Select an Expiration date
- Click Add
Note: The Client Secret expiration date has a maximum of 24 months (2 years). You can always Renew the Client Secret in Microsoft Entra ID with PowerShell.
- Copy the Client Secret value and save it in Notepad
Connect to Microsoft Graph PowerShell with Client Secret
You need to change the below parameters values to connect to MS Graph PowerShell with Client Secret:
- Type the Application Client ID value in line 2
- Type the Directory Tenant ID value in line 3
- Type the Client Secret value value in line 4
Run the below PowerShell script.
# Configuration
$ClientId = "c6787ff5-08ec-4e96-b4d2-1d1782303310"
$TenantId = "eb403171-a4ec-4d98-a08f-1876318c9deb"
$ClientSecret = "6_q8Q~X9e-fjwWhVVP_WWx~ua4JMI.BWkI7Q7b7B"
# Convert the client secret to a secure string
$ClientSecretPass = ConvertTo-SecureString -String $ClientSecret -AsPlainText -Force
# Create a credential object using the client ID and secure string
$ClientSecretCredential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $ClientId, $ClientSecretPass
# Connect to Microsoft Graph with Client Secret
Connect-MgGraph -TenantId $tenantId -ClientSecretCredential $ClientSecretCredential
Search emails on specific user
Get all messages from a specific user.
$User = "Amanda.Morgan@exoip.com"
Get-MgUserMessage -All -UserId "$User" |
Select-Object Subject, InternetMessageId, ReceivedDateTime,
@{Name = "Sender"; Expression = { $_.Sender.EmailAddress.Address } },
@{Name = "Recipients"; Expression = { $_.ToRecipients.EmailAddress.Address -join ', ' } } |
Out-GridView
Get all messages from a specific user that are read.
$User = "Amanda.Morgan@exoip.com"
Get-MgUserMessage -All -UserId "$User" -Filter "IsRead eq true" |
Select-Object Subject, InternetMessageId, ReceivedDateTime,
@{Name = "Sender"; Expression = { $_.Sender.EmailAddress.Address } },
@{Name = "Recipients"; Expression = { $_.ToRecipients.EmailAddress.Address -join ', ' } } |
Out-GridView
Get all messages from a specific user that are unread.
$User = "Amanda.Morgan@exoip.com"
Get-MgUserMessage -All -UserId "$User" -Filter "IsRead eq false" |
Select-Object Subject, InternetMessageId, ReceivedDateTime,
@{Name = "Sender"; Expression = { $_.Sender.EmailAddress.Address } },
@{Name = "Recipients"; Expression = { $_.ToRecipients.EmailAddress.Address -join ', ' } } |
Out-GridView
Search emails on date
Search for emails from a specific user after a specific date.
$User = "Amanda.Morgan@exoip.com"
$Date = "2024-01-01"
Get-MgUserMessage -All -UserId "$User" -Filter "ReceivedDateTime gt $Date" |
Select-Object Subject, InternetMessageId, ReceivedDateTime,
@{Name = "Sender"; Expression = { $_.Sender.EmailAddress.Address } },
@{Name = "Recipients"; Expression = { $_.ToRecipients.EmailAddress.Address -join ', ' } } |
Out-GridView
Search emails on subject
Search for emails that start with a specific subject.
$Subject = "The subject"
$user = "Amanda.Morgan@exoip.com"
Get-MgUserMessage -All -UserId "$User" -Filter "startswith(Subject,'$Subject')" |
Select-Object Subject, InternetMessageId, ReceivedDateTime,
@{Name = "Sender"; Expression = { $_.Sender.EmailAddress.Address } },
@{Name = "Recipients"; Expression = { $_.ToRecipients.EmailAddress.Address -join ', ' } } |
Out-GridView
Search for emails that are equal to the subject.
$Subject = "The specific subject"
$user = "Amanda.Morgan@exoip.com"
Get-MgUserMessage -All -UserId "$user" -Filter "Subject eq '$Subject'" |
Select-Object Subject, InternetMessageId, ReceivedDateTime,
@{Name = "Sender"; Expression = { $_.Sender.EmailAddress.Address } },
@{Name = "Recipients"; Expression = { $_.ToRecipients.EmailAddress.Address -join ', ' } } |
Out-GridView
Search emails from last 30 days
Let’s search for all emails in the organization from the last 30 days, on the recipient and on the sender. The results will appear in an Out-GridView and be exported to a CSV file.
Search for all emails in the organization from the last 30 days.
# Get all users
$users = Get-MgUser -All
# Create an empty array to store the data
$Data = @()
# Determine the date 30 days prior to today
$startDate = (Get-Date).AddDays(-30).ToString("yyyy-MM-dd")
# Loop through each user
foreach ($user in $users) {
# Ensure the user has an associated email address
if ($user.Mail) {
$messages = Get-MgUserMessage -UserId $user.Id -All -Filter "ReceivedDateTime ge $startDate" -ErrorAction SilentlyContinue
foreach ($message in $messages) {
$Data += [PSCustomObject]@{
ReceivedDateTime = $message.ReceivedDateTime
Subject = $message.Subject
Sender = $message.Sender.EmailAddress.Address -join ','
Recipient = $message.ToRecipients.EmailAddress.Address -join ','
InternetMessageId = $message.InternetMessageId
}
}
}
}
# Display and export the data
$Data | Out-GridView
$Data | Export-Csv -Path "C:\temp\All_emails.csv" -NoTypeInformation -Encoding utf8
Search for all emails in the organization that have been sent to a specific recipient in the last 30 days.
# Email address of the recipient you want to filter
$recipientEmailAddress = "amanda.morgan@exoip.com"
# Get all users
$users = Get-MgUser -All
# Create an empty array to store the data
$Data = @()
# Determine the date 30 days prior to today
$startDate = (Get-Date).AddDays(-30).ToString("yyyy-MM-dd")
# Loop through each user
foreach ($user in $users) {
# Ensure the user has an associated email address
if ($user.Mail) {
$messages = Get-MgUserMessage -UserId $user.Id -All -Filter "ReceivedDateTime ge $startDate" -ErrorAction SilentlyContinue
foreach ($message in $messages) {
# Check if the recipient matches the desired email address
if ($message.ToRecipients.EmailAddress.Address -eq $recipientEmailAddress) {
$Data += [PSCustomObject]@{
ReceivedDateTime = $message.ReceivedDateTime
Subject = $message.Subject
Sender = $message.Sender.EmailAddress.Address
Recipient = $message.ToRecipients.EmailAddress.Address
InternetMessageId = $message.InternetMessageId
}
}
}
}
}
# Display and export the data
$Data | Out-GridView
$Data | Export-Csv -Path "C:\temp\Recipient_emails.csv" -NoTypeInformation -Encoding utf8
Search for all emails in the organization that have been sent from a specific sender in the last 30 days.
# Email address of the sender you want to filter
$senderEmailAddress = "john.doe@gmail.com"
# Get all users
$users = Get-MgUser -All
# Create an empty array to store the data
$Data = @()
# Determine the date 30 days prior to today
$startDate = (Get-Date).AddDays(-30).ToString("yyyy-MM-dd")
# Loop through each user
foreach ($user in $users) {
# Ensure the user has an associated email address
if ($user.Mail) {
$messages = Get-MgUserMessage -UserId $user.Id -All -Filter "ReceivedDateTime ge $startDate" -ErrorAction SilentlyContinue
foreach ($message in $messages) {
if ($message.Sender.EmailAddress.Address -eq $senderEmailAddress) {
$Data += [PSCustomObject]@{
ReceivedDateTime = $message.ReceivedDateTime
Subject = $message.Subject
Sender = $message.Sender.EmailAddress.Address
Recipient = ($message.ToRecipients.EmailAddress.Address -join ',')
InternetMessageId = $message.InternetMessageId
}
}
}
}
}
# Display and export the data
$Data | Out-GridView
$Data | Export-Csv -Path "C:\temp\Sender_emails.csv" -NoTypeInformation -Encoding utf8
That’s it!
Read more: Export Entra ID app registrations Certificates and Secrets expiry report »
Conclusion
You learned how to search emails with PowerShell. First, set up an application in Microsoft Entra with the correct permissions. After that, connect with Microsoft Graph PowerShell to the application. As last, run the commands to search for emails with PowerShell.
Did you enjoy this article? You may also like How to block Top-Level Domain (TLD) in Microsoft 365. Don’t forget to follow us and share this article.