All scripts
Automation 199
Disable-InactiveEntraGuestUsers
Finds Entra ID guest accounts that have not signed in for a set number of days and disables them, so you can clean up stale guest access without deleting anything outright. Writes a CSV report of everything it touches.
Disable-InactiveEntraGuestUsers.ps1
<#
.SYNOPSIS
Disables Entra ID guest accounts that have not signed in for a set number of days.
.DESCRIPTION
Connects to Microsoft Graph, pulls every guest account (userType eq 'Guest'), checks
each one's last sign in date from the sign in activity, and disables any guest that
has been inactive longer than the threshold you set. Accounts are disabled, not
deleted, so you can review and re-enable anyone flagged by mistake. Writes a CSV
report of everything the script found and touched.
.PARAMETER InactiveDays
Number of days since last sign in before a guest is considered inactive. Defaults to 90.
.PARAMETER WhatIf
Run the script without making any changes, just report what would be disabled.
.PARAMETER ReportPath
Path to write the CSV report to. Defaults to the current folder.
.EXAMPLE
.\Disable-InactiveEntraGuestUsers.ps1 -InactiveDays 120 -WhatIf
.EXAMPLE
.\Disable-InactiveEntraGuestUsers.ps1 -InactiveDays 90 -ReportPath "C:\Reports\guests.csv"
.AUTHOR
Shehryar Hassan
#>
[CmdletBinding()]
param(
[int]$InactiveDays = 90,
[switch]$WhatIf,
[string]$ReportPath = ".\InactiveGuestUsers_$(Get-Date -Format 'yyyyMMdd').csv"
)
Import-Module Microsoft.Graph.Users -ErrorAction Stop
Connect-MgGraph -Scopes "User.ReadWrite.All", "AuditLog.Read.All" -NoWelcome
$cutoffDate = (Get-Date).AddDays(-$InactiveDays)
Write-Host "Looking for guest accounts inactive since before $($cutoffDate.ToString('yyyy-MM-dd'))" -ForegroundColor Cyan
$guests = Get-MgUser -Filter "userType eq 'Guest'" -All `
-Property "Id,DisplayName,Mail,UserPrincipalName,AccountEnabled,SignInActivity,CreatedDateTime" `
-ConsistencyLevel eventual -CountVariable guestCount
Write-Host "Found $($guests.Count) guest accounts to check." -ForegroundColor Cyan
$results = @()
foreach ($guest in $guests) {
$lastSignIn = $guest.SignInActivity.LastSignInDateTime
$createdDate = $guest.CreatedDateTime
if (-not $lastSignIn) {
# Never signed in, use account creation date as the reference point instead.
$referenceDate = $createdDate
$reason = "Never signed in"
}
else {
$referenceDate = $lastSignIn
$reason = "Last sign in $($lastSignIn.ToString('yyyy-MM-dd'))"
}
$isInactive = $referenceDate -lt $cutoffDate
if ($isInactive -and $guest.AccountEnabled) {
if ($WhatIf) {
Write-Host "Would disable: $($guest.DisplayName) ($($guest.Mail)) - $reason" -ForegroundColor Yellow
}
else {
try {
Update-MgUser -UserId $guest.Id -AccountEnabled:$false
Write-Host "Disabled: $($guest.DisplayName) ($($guest.Mail)) - $reason" -ForegroundColor Red
}
catch {
Write-Warning "Failed to disable $($guest.DisplayName): $($_.Exception.Message)"
}
}
$results += [PSCustomObject]@{
DisplayName = $guest.DisplayName
Mail = $guest.Mail
UserPrincipalName = $guest.UserPrincipalName
LastSignIn = $lastSignIn
CreatedDateTime = $createdDate
Reason = $reason
Action = if ($WhatIf) { "Would disable" } else { "Disabled" }
}
}
}
if ($results.Count -gt 0) {
$results | Export-Csv -Path $ReportPath -NoTypeInformation
Write-Host "`n$($results.Count) inactive guest accounts found. Report saved to $ReportPath" -ForegroundColor Green
}
else {
Write-Host "`nNo inactive guest accounts found past the $InactiveDays day threshold." -ForegroundColor Green
}
Disconnect-MgGraph | Out-Null
Read it before you run it, and test in a safe tenant first.