All scripts
Governance 795

Get-TeamsGuestAccessReport

Audits every guest account in the tenant, which Teams they can reach, and how long ago they last signed in. Built for the periodic external-access review.

Get-TeamsGuestAccessReport.ps1
<#
.SYNOPSIS
    Get-TeamsGuestAccessReport.ps1 - Audits guest access across Microsoft Teams.

.DESCRIPTION
    Lists every guest account in the tenant, which Teams they belong to, and how
    long ago they last signed in. Built for the periodic external-access review
    most compliance frameworks ask for. Requires Graph scope: User.Read.All,
    Team.ReadBasic.All, TeamMember.Read.All

.AUTHOR
    Shehryar Hassan

.EXAMPLE
    .\Get-TeamsGuestAccessReport.ps1 -OutputPath ".\GuestAccessReport.csv"
#>

param(
    [Parameter(Mandatory=$false)]
    [string]$OutputPath = ".\GuestAccessReport.csv"
)

Write-Host "=============================================" -ForegroundColor Cyan
Write-Host "  Teams Guest Access Report" -ForegroundColor Cyan
Write-Host "=============================================" -ForegroundColor Cyan

if (-not (Get-MgContext)) {
    Write-Host "[INFO] Connecting to Microsoft Graph..." -ForegroundColor Yellow
    Connect-MgGraph -Scopes "User.Read.All", "Team.ReadBasic.All", "TeamMember.Read.All"
}

Write-Host "[INFO] Pulling guest users..." -ForegroundColor Gray
$guests = Get-MgUser -Filter "userType eq 'Guest'" -All -Property Id, DisplayName, Mail, CreatedDateTime, SignInActivity

Write-Host "[INFO] Pulling teams and matching guest membership (this takes a while on large tenants)..." -ForegroundColor Gray
$teams = Get-MgTeam -All

$report = foreach ($guest in $guests) {
    $memberOf = foreach ($team in $teams) {
        $isMember = Get-MgTeamMember -TeamId $team.Id -Filter "microsoft.graph.aadUserConversationMember/userId eq '$($guest.Id)'" -ErrorAction SilentlyContinue
        if ($isMember) { $team.DisplayName }
    }

    [PSCustomObject]@{
        DisplayName  = $guest.DisplayName
        Email        = $guest.Mail
        CreatedOn    = $guest.CreatedDateTime
        LastSignIn   = $guest.SignInActivity.LastSignInDateTime
        TeamsAccess  = ($memberOf -join "; ")
    }
}

$report | Export-Csv -Path $OutputPath -NoTypeInformation

Write-Host "[SUCCESS] $($guests.Count) guest account(s) written to: $OutputPath" -ForegroundColor Green
$stale = $report | Where-Object { -not $_.LastSignIn -or ([datetime]$_.LastSignIn -lt (Get-Date).AddDays(-90)) }
if ($stale) {
    Write-Host "[WARNING] $($stale.Count) guest(s) with no sign-in in 90+ days, candidates for removal:" -ForegroundColor Red
}

Read it before you run it, and test in a safe tenant first.