Public/Get-GuestAccessReport.ps1

function Get-GuestAccessReport {
    <#
    .SYNOPSIS
        Reviews guest (external) user accounts in the Microsoft 365 tenant.
 
    .DESCRIPTION
        Enumerates all guest accounts and reports on:
        - When they were invited and by whom
        - Last sign-in activity
        - Whether they've redeemed their invitation
        - Group memberships and app access
 
        Stale guest accounts are a common compliance finding and attack surface.
 
    .PARAMETER DaysInactive
        Flag guests who haven't signed in within this many days. Defaults to 90.
 
    .PARAMETER UnredeemedOnly
        Only show guests who never accepted their invitation.
 
    .EXAMPLE
        Get-GuestAccessReport
 
    .EXAMPLE
        Get-GuestAccessReport -DaysInactive 30 | Where-Object StaleGuest -eq $true
 
    .NOTES
        Requires: Microsoft.Graph.Users
        Scopes: User.Read.All, Directory.Read.All
    #>

    [CmdletBinding()]
    param(
        [int]$DaysInactive = 90,

        [switch]$UnredeemedOnly
    )

    $inactiveThreshold = (Get-Date).AddDays(-$DaysInactive)

    $guests = Get-MgUser -Filter "userType eq 'Guest'" -All -Property @(
        'Id', 'DisplayName', 'Mail', 'UserPrincipalName', 'CreatedDateTime',
        'ExternalUserState', 'ExternalUserStateChangeDateTime', 'SignInActivity',
        'AccountEnabled'
    )

    if ($UnredeemedOnly) {
        $guests = $guests | Where-Object ExternalUserState -ne 'Accepted'
    }

    foreach ($guest in $guests) {
        $lastSignIn = $guest.SignInActivity.LastSignInDateTime
        $isStale = if ($lastSignIn) { $lastSignIn -lt $inactiveThreshold } else { $true }
        $daysSinceSignIn = if ($lastSignIn) { [math]::Round(((Get-Date) - $lastSignIn).TotalDays) } else { $null }

        # Get group memberships
        $memberOf = try {
            (Get-MgUserMemberOf -UserId $guest.Id -ErrorAction Stop).AdditionalProperties.displayName -join '; '
        }
        catch { '' }

        [PSCustomObject]@{
            DisplayName      = $guest.DisplayName
            Email            = $guest.Mail
            UPN              = $guest.UserPrincipalName
            InviteState      = $guest.ExternalUserState
            InviteDate       = $guest.CreatedDateTime
            AccountEnabled   = $guest.AccountEnabled
            LastSignIn       = $lastSignIn
            DaysSinceSignIn  = $daysSinceSignIn
            StaleGuest       = $isStale
            Groups           = $memberOf
        }
    }
}