PowerShell – Locate Inactive Users in Active Directory / Exchange On-Prem

Another short article with little context today.

The PowerShell script below will produce a report showing the Last Logon time of all enabled Active Directory users, it will also connect to Exchange On-Premise and request the last logon date of the mailbox. This can be useful to identify user accounts which are no longer in active use, even in organisations where mailboxes may have been retained once a user left.

There’s also a nifty status update built in that will tell you exactly how far the script has progressed and show an estimated time to completion.

The Script

# Locate all users that have not logged in within 12 months
$InactiveMonths = 12
$ExchangePowerShellEndpoint = "https://*Server*/PowerShell/"
$ExchangeAuthenticationModel = "Kerberos"
$UserCredential = Get-Credential -Message "Enter your credentials used to log into the Exchange Admin Portal"

$Months = (Get-Date).Addmonths(-($InactiveMonths))
$Users = Get-ADUser -Filter {LastLogonTimeStamp -lt $Months -and enabled -eq $true} -Properties LastLogonTimeStamp, mail |
select-object Name,@{Name="LastLogon"; Expression={[DateTime]::FromFileTime($_.lastLogonTimestamp).ToString('dd-MM-yyyy')}},SamAccountName,UserPrincipalName, mail

Write-Host "Located $($Users.count) users"

# Connect to Exchange
$Session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri $ExchangePowerShellEndpoint -Authentication $ExchangeAuthenticationModel -Credential $UserCredential
Import-PSSession $Session -DisableNameChecking -AllowClobber

# For each user, get the last mailbox login time
$currentIndex = 1
$startTime = Get-Date
foreach ($user in $users) {

    # Estimate time to completion
    $estimation = " "
    $now = Get-Date
    if ($currentIndex -gt 0) {
        $elapsed = $now - $startTime # how much time has been spent
        $average = $elapsed.TotalSeconds / $currentIndex # how many seconds per site
        $totalSecondsToGo = ($users.Count - $currentIndex) * $average # seconds left
        $span = New-TimeSpan -Seconds $totalSecondsToGo # time left
        $estimatedCompletion = $now + $span # when it will be complete
        $estimation = $estimatedCompletion.ToString() # readable estimation

    # Show progress and estimated completion
    Write-Progress -Id 0 -Activity "Retrieving Exchange Mailbox Stats" -Status "$currentIndex of $($Users.Count), Est Completion - $($estimation)" -PercentComplete (($currentIndex / $Users.Count) * 100)

    # Get the mailboxes last logon time
    try {
        $mailboxStats = Get-MailboxStatistics -Identity $user.mail -ErrorAction Stop
        $lastLogon = $mailboxStats.LastLogonTime
        if($lastLogon -ne $null) {
            $lastLogon = (Get-Date $lastLogon).ToShortDateString()
            $user | Add-Member -Name 'mailboxLastAccess' -Type NoteProperty -Value $lastLogon
    } catch {
        $user | Add-Member -Name 'mailboxLastAccess' -Type NoteProperty -Value $null
Write-Progress -Id 0 -Activity " " -Status " " -Completed

# Export to CSV
$Users | export-csv C:\temp\LastLogOn_Users.csv -notypeinformation -noclobber

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.