How to Remove Inactive Microsoft 365 Guest Users Using Graph PowerShell

Guest users help organizations collaborate with external vendors, partners, and consultants. However, inactive guest accounts often remain in Microsoft 365 long after they are needed.

These stale guest accounts can:

  • Increase security risks
  • Expand the attack surface
  • Complicate governance reviews
  • Create unnecessary directory clutter

👉 In this guide, you’ll learn how to identify and remove inactive Microsoft 365 guest users using Graph PowerShell safely and efficiently.


What You’ll Learn

By the end of this article, you’ll be able to:

  • Retrieve inactive guest users
  • Filter guests inactive for 30/60/90+ days
  • Export guest cleanup reports
  • Remove inactive guest users in bulk
  • Understand safety precautions before deletion

Prerequisites

✅ Install Microsoft Graph PowerShell

Install-Module Microsoft.Graph -Scope CurrentUser

✅ Required Permissions

The following permissions are required:

  • User.Read.All
  • User.ReadWrite.All
  • Directory.ReadWrite.All
  • AuditLog.Read.All

Admin consent may be required.

Licensing Requirement

This solution uses the signInActivity property to determine inactivity.

✅ Supported Licenses

The signInActivity property is available in:

  • Microsoft Entra ID P1
  • Microsoft Entra ID P2
  • Microsoft 365 E5

❌ Limited or Unavailable In

  • Microsoft 365 Business plans
  • Microsoft 365 E3 without Entra ID P1/P2
  • Free Entra ID tenants

⚠️ Important Notes

  • Newly invited guests may never show sign-in activity
  • Sign-in data may take time to populate
  • Always review reports before deletion

Connect to Microsoft Graph

Connect-MgGraph -Scopes `
"User.Read.All",
"User.ReadWrite.All",
"Directory.ReadWrite.All",
"AuditLog.Read.All"
                                        

Script 1: Retrieve Inactive Guest Users

This script identifies guest users inactive for the last 90 days.

# Define inactivity threshold
$DaysInactive = 90
$ThresholdDate = (Get-Date).AddDays(-$DaysInactive)

# Retrieve guest users
$Guests = Get-MgUser `
-Filter "userType eq 'Guest'" `
-Property DisplayName,UserPrincipalName,SignInActivity `
-All

# Find inactive guests
$InactiveGuests = $Guests | Where-Object {
    $_.SignInActivity.LastSuccessfulSignInDateTime -lt $ThresholdDate
}

# Display results
$InactiveGuests | Select-Object `
DisplayName,
UserPrincipalName,
@{Name="LastSignIn";Expression={$_.SignInActivity.LastSuccessfulSignInDateTime}}
                                        

Sample Output

DisplayName UserPrincipalName LastSignIn
Vendor User vendor@external.com 2025-09-15
Consultant consultant@gmail.com 2025-08-20

Script 2: Export Inactive Guests Before Deletion

⚠️ Always export reports before removing accounts.

$InactiveGuests | Select-Object `
DisplayName,
UserPrincipalName,
@{Name="LastSignIn";Expression={$_.SignInActivity.LastSuccessfulSignInDateTime}} |
Export-Csv "Inactive_Guest_Users.csv" -NoTypeInformation
Write-Host "✅ Guest inactivity report exported successfully!"

Script 3: Remove Inactive Guest Users

This script removes inactive guest accounts.

⚠️ Use carefully.

foreach ($Guest in $InactiveGuests) {    
    Remove-MgUser -UserId $Guest.Id    
    Write-Host "Removed guest user:" $Guest.UserPrincipalName
}

Script 4: Remove Guests Inactive for 180+ Days Only

This approach is safer for production environments.


$CriticalThreshold = (Get-Date).AddDays(-180)

$VeryInactiveGuests = $Guests | Where-Object {    
    $_.SignInActivity.LastSuccessfulSignInDateTime -lt $CriticalThreshold
}
foreach ($Guest in $VeryInactiveGuests) {    
    Remove-MgUser -UserId $Guest.Id    
    Write-Host "Removed highly inactive guest:" $Guest.UserPrincipalName
}
                                        

Script 5: Disable Guest Accounts Before Deletion (Recommended)

Best practice:

  • Disable account first
  • Monitor impact
  • Delete later
foreach ($Guest in $InactiveGuests) {    
    Update-MgUser `    
    -UserId $Guest.Id `    
    -BodyParameter @{        
        accountEnabled = $false    
    }    
    Write-Host "Disabled guest user:" $Guest.UserPrincipalName
}

Real-World Use Cases

  1. Reduce Security Risks
  2. Inactive guest accounts are attractive attack targets.

    👉 Removing them strengthens security posture.

  3. Improve Governance
  4. Organizations often require:

    • quarterly access reviews
    • guest lifecycle management

    This script simplifies cleanup operations.

  5. Remove Expired Vendor Access
  6. Consultants and external vendors often retain access after projects end.

    👉 Prevent unnecessary exposure.

  7. Clean Up Entra ID
  8. Large numbers of stale guest users:

    • clutter the tenant
    • complicate reporting
    • slow governance reviews

Enhancements

  • Automate Monthly Cleanup
  • powershell.exe -File "RemoveInactiveGuests.ps1"

    Use Task Scheduler for automation.

  • Send Approval Report Before Deletion
  • Recommended workflow:

    • Export CSV
    • Send for approval
    • Remove users afterward
  • Build Cleanup Dashboard
  • Track:

    • inactive guests
    • deleted accounts
    • guest trends over time

Cmdlet Tips

  • Always export reports before deletion
  • Disable accounts before permanent removal
  • Use longer inactivity thresholds in production
  • Validate sign-in activity carefully

Common Errors & Solutions

Error Cause solution
Insufficient privileges Insufficient privileges to complete the operation Connect-MgGraph -Scopes `
"User.ReadWrite.All",
"Directory.ReadWrite.All"
Admin consent is required.
signInActivity is empty
  • Missing Entra ID P1/P2
  • Guest never signed in
Verify licensing and review guest invitation history.
User not found Guest account already deleted. Validate existence before removal.
Accidental deletion risk Removing active external users mistakenly.
  • Export reports first
  • Disable before deletion
  • Use approval workflow

Use Cases Summary

Scenario Benefit
Security cleanup Reduce attack surface
Vendor lifecycle management Remove stale access
Governance reviews Simplify audits
Entra hygiene Clean directory environment

Conclusion

Inactive guest users are one of the most overlooked risks in Microsoft 365 environments.

Using Graph PowerShell, you can:

  • identify stale guest accounts
  • export inactivity reports
  • disable or remove unused external users

👉 Regular guest cleanup should be a core part of every Microsoft 365 governance strategy.

Did You Know? Managing Microsoft 365 applications is even easier with automation. Try our Graph PowerShell scripts to automate tasks like generating reports, cleaning up inactive Teams, or assigning licenses efficiently.

Ready to get the most out of Microsoft 365 tools? Explore our free Microsoft 365 administration tools to simplify your administrative tasks and boost productivity.

© Your Site Name. All Rights Reserved. Design by HTML Codex