How I Cleaned Up Stale Guest Accounts in Microsoft Entra ID — And Why It Matters

During a recent engagement with a client, I was tasked with reviewing their Microsoft Entra ID tenant as part of a broader identity security assessment. One of my first observations was the presence of a significant number of inactive guest accounts.

For context, guest accounts are typically assigned to external users invited to collaborate with an organization. In this case, many of these accounts were months—or even years—old and had either never signed in or had long since stopped accessing the tenant.

This is a surprisingly common issue. Guest accounts are simple to create but often forgotten, and when left unmanaged, they present an unnecessary attack surface. Dormant accounts could potentially be compromised and exploited to gain access to internal resources.

The client needed an efficient way to identify, review, and clean up these accounts—without manually checking each one. In this write-up, I will outline how I approached this project and offer actionable strategies for managing inactive guest accounts in your own environment.

The Approach

Instead of performing a one-time manual cleanup, I created a reusable PowerShell script that connects to the tenant using the Microsoft Graph API and automates the entire process.

Scripts like this not only save time but also ensure standardized implementation of such processes, allowing new team members to easily reuse the script in the future.

The script:

  • Identifies all guest users in the tenant. This includes all users with the guest userType attribute.
  • Checks when each one last signed in using audit logs
  • Flags anyone inactive beyond a configurable threshold (for this project, we used 90 days)
  • Exports a CSV report for review
  • Deletes stale accounts when approved — controlled by a dry run flag for safety

Using the dry run flag was crucial in this process. It allowed the client to first review a comprehensive report and verify that the list of guest users was correct. Only after confirming the accuracy of this list did we proceed to live mode, which executed the deletion of stale accounts.

Prerequisites

To replicate this in your own environment you will need:

  • PowerShell 7.0 or higher
  • Microsoft Graph PowerShell module
  • An Entra ID app registration with the following API permissions:
    • User.Read.All — This gives the script read access to all users in the tenant
    • User.ReadWrite.All — Provides the script read and write access to all users (it’s what makes deletion possible)
    • AuditLog.Read.All — Allows the script to access the tenants audit logs

The Script

The full script is available on GitHub: github.com/tmugema1/stale-guest-user-cleanup

Here is the core logic:

# Get all guest users
$guestUsers = Get-MgUser -Filter "userType eq 'Guest'" -All -Property "displayName,mail,userPrincipalName,createdDateTime,id"

# Check sign-in activity and flag stale users
$today = Get-Date
$staleUsers = foreach ($guest in $guestUsers) {
    $signIns = Get-MgAuditLogSignIn -Filter "userId eq '$($guest.Id)'" -Top 1 | Select-Object -First 1

    if ($signIns) {
        $lastSignIn      = $signIns.CreatedDateTime
        $daysSinceSignIn = ($today - $lastSignIn).Days
    } else {
        $lastSignIn      = "Never"
        $daysSinceSignIn = 999
    }

    if ($daysSinceSignIn -ge $thresholdDays) {
        [PSCustomObject]@{
            Id           = $guest.Id
            DisplayName  = $guest.DisplayName
            Email        = $guest.Mail
            LastSignIn   = $lastSignIn
            DaysInactive = $daysSinceSignIn
        }
    }
}

The Output

The script exports a CSV report listing every stale guest account, their last sign-in date, and how many days they have been inactive. This gave the client a clear, auditable record of exactly who was removed and why. You could further customize the script to export the CSV file to a shared location such as SharePoint or OneDrive, automatically email it to an administrator. 

What We Did Next

After the initial cleanup, I recommended the client put in place ongoing governance practices to prevent the problem from recurring. These include: 

  • Access Reviews: These should include scheduled quarterly or monthly reviews of all guest accounts using Microsoft Entra ID Governance
  • Lifecycle policies: Automatically disabling guests who haven’t signed in within 90 days using Entra ID Lifecycle Workflows to ensure stale accounts are actioned consistently without manual intervention.
  • Entitlement Management: Controlling how guests are invited and setting expiry on their access packages using Entra ID Entitlement Management. This approach ensures external users only retain access for as long as it is needed and are automatically removed when their access period expires.

My Final Thoughts

Stale guest accounts pose a common yet often overlooked security risk for many organizations. Fortunately, with the right tools, identifying and cleaning up these accounts can be straightforward. Automating this process ensures that it does not get neglected over time.

A critical point to remember is that when automating with your script, you should always include a step to review the results before deleting any accounts. This reduces the already slim risk of accidentally removing active guest accounts that users may still rely on.

If your organization has ungoverned guest access or has recently flagged inactive external users in a security audit, I can help you assess the problem and implement a long-term solution. Connect with me on tom@helpdesq.tech to discuss how I can help.

Share your love
Tom Sankara
Tom Sankara
Articles: 19

Newsletter Updates

Enter your email address below and subscribe to our newsletter