Entra / Microsoft 365 · Users & guests
Find obsolete guest accounts by activity
Find inactive Entra ID guest accounts based on audit log and message trace activity over the last 90 days.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
# Review required modules and connection steps before running.# Connect to Microsoft Graph or Exchange Online as needed for this script.
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([int] $LookbackDays = 90,[string] $StartDate = (Get-Date).AddDays(-$LookbackDays) #For audit log,[string] $EndDate = (Get-Date); $Active = 0; $EmailActive = 0; $Inactive = 0; $AuditRec = 0)$Guests = (Get-AzureADUser -Filter "UserType eq 'Guest'" -All $True| Select Displayname, UserPrincipalName, Mail, RefreshTokensValidFromDateTime)Write-Host $Guests.Count "guest accounts found. Checking their recent activity..."$StartDate2 = (Get-Date).AddDays(-$LookbackDays) #For message trace$Report = [System.Collections.Generic.List[Object]]::new() # Create output fileForEach ($G in $Guests) {Write-Host "Checking" $G.DisplayName$LastAuditAction = $Null; $LastAuditRecord = $Null# Search for audit records for this user$Recs = (Search-UnifiedAuditLog -UserIds $G.Mail, $G.UserPrincipalName -Operations UserLoggedIn, SecureLinkUsed, TeamsSessionStarted -StartDate $StartDate -EndDate $EndDate -ResultSize 1)If ($Recs.CreationDate -ne $Null) { # We found some audit logs$LastAuditRecord = $Recs[0].CreationDate; $LastAuditAction = $Recs[0].Operations; $AuditRec++Write-Host "Last audit record for" $G.DisplayName "on" $LastAuditRecord "for" $LastAuditAction -Foregroundcolor Green }Else { Write-Host "No audit records found in the last 90 days for" $G.DisplayName "; account created on" $G.RefreshTokensValidFromDateTime -Foregroundcolor Red }# Check message trace data because guests might receive email through membership of Outlook Groups. Email address must be valid for the check to workIf ($G.Mail -ne $Null) {$EmailRecs = (Get-MessageTrace –StartDate $StartDate2 –EndDate $EndDate -Recipient $G.Mail)If ($EmailRecs.Count -gt 0) {Write-Host "Email traffic found for" $G.DisplayName "at" $EmailRecs[0].Received -foregroundcolor Yellow$EmailActive++ }}# Write out report line$ReportLine = [PSCustomObject][Ordered]@{Guest = $G.MailName = $G.DisplayNameCreated = $G.RefreshTokensValidFromDateTimeEmailCount = $EmailRecs.CountLastConnectOn = $LastAuditRecordLastConnect = $LastAuditAction}$Report.Add($ReportLine) }$Active = $AuditRec + $EmailActive$Report | Export-CSV -NoTypeInformation c:\temp\GuestActivity.csvWrite-Host ""Write-Host "Statistics"Write-Host "----------"Write-Host "Guest Accounts " $Guests.CountWrite-Host "Active Guests " $ActiveWrite-Host "Audit Record foun " $AuditRecWrite-Host "Active on Email " $EmailActiveWrite-Host "InActive Guests " ($Guests.Count - $Active)
Parameters
ParameterDefaultNotes
-LookbackDays90Number of days back to evaluate guest account activity.-StartDate(Get-Date).AddDays(-90)Start of the audit log search window.-EndDate(Get-Date)End of the audit log search window.Attribution
Author
Office365itpros