If you work for any sort of medium or large company you know that it is not uncommon for email accounts to sometimes not yet shut down properly when someone exits. After a few years someone will eventually ask to see a list of all inactive Exchange users, and then you have some work to do.

Well it turns out it’s actually not very difficult to do and we have a very simple script below that you can either save as a .PS1 file to run all commands in one fell swoop or as you can see in the screenshot below you can enter one by one:

powershell to list inactive email accounts in Exchange Online

Note: We have slightly doctored this screenshot to strip out long winded alerts and notices which may be useful to you but are not directly related to what we’re trying to achieve.

Also in case it’s not obvious, yes you can easily change the date range you were looking for to be longer or shorter than one year by simply changing the -365 to however many days you want in the $startDate = (Get-Date).AddDays(-365) line

# Install MSOline Module
Install-Module -Name MSOnline -AllowClobber -Force -Verbose
Import-Module -Name MSOnline

# Connect to Microsoft 365

# Install the ExchangeOnlineManagement module
Install-Module -Name ExchangeOnlineManagement -Force -Verbose -AllowClobber
Import-Module ExchangeOnlineManagement

# Connect to Exchange Online  **** MUST change admin@yourdomain.com to your admin account
Connect-ExchangeOnline -UserPrincipalName yourname@domain.com

# Set admin UPN  **** MUST change admin@yourdomain.com to your admin account
$UPN = 'admin@yourdomain.com' 

# Time range
$startDate = (Get-Date).AddDays(-365).ToString('MM/dd/yyyy')
$endDate = (Get-Date).ToString('MM/dd/yyyy')

# Get all active users
$allUsers = @()
$allUsers = Get-MsolUser -All -EnabledFilter EnabledOnly | Select UserPrincipalName

# Search for users who have logged in within the time range
$loggedOnUsers = @()
$loggedOnUsers = Search-UnifiedAuditLog -StartDate $startDate -EndDate $endDate -Operations UserLoggedIn, PasswordLogonInitialAuthUsingPassword, UserLoginFailed -ResultSize 5000

# Cross-reference the two lists to get your answer
$inactiveInLastYearUsers = @()
$inactiveInLastYearUsers = $allUsers.UserPrincipalName | where {$loggedOnUsers.UserIds -NotContains $_}

# Output the result
Write-Output "Results Output to c:\Temp\InactiveUsers.csv - The following users have no logged in for the last 365 days:"
Write-Output $inactiveInLastYearUsers

# Export list to CSV
$inactiveInLastYearUsers > "C:\\Temp\\InactiveUsers.csv"

# Disconnect the session
Disconnect-ExchangeOnline -Confirm:$false

An important note here that we tried to highlight in the name of the file we are saving, is that this list is of users who have not interactively logged in. That means people who have manually typed in some data to log in. That means it will also list users that have not logged in for one year programmatically, like scanners, so be careful. Just because there has not been an interactive logon within the last years, does not guarantee the account is dormant.


Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *