Teams sprawl is a real problem in any tenant that’s been running a while — project Teams that outlived the project, one-off Teams nobody remembers creating, Teams with external guests still sitting in them long after anyone used the channel. Finding which ones are actually dead (not just quiet) is the first step before archiving or deleting anything.
In this post: Prerequisites · Pulling the activity report · Best practices · When would you actually use this? · Related reading
Prerequisites
- At least the Reports Reader role in Microsoft 365 — you don’t need Global Admin just to pull activity reports.
- The Microsoft.Graph.Reports PowerShell module installed, connected with the
Reports.Read.Allscope. - Audit logging matters less here than you’d think — the Teams activity report is a separate, purpose-built dataset, not derived from the unified audit log (which has its own, shorter retention window).
Pulling the activity report
Microsoft Graph has a purpose-built report for exactly this — Get-MgReportTeamActivityDetail returns a per-team CSV with a Last Activity Date column, so you’re not reconstructing activity from raw audit log entries:
# Install Microsoft Graph Reports module if not already installed
Install-Module Microsoft.Graph.Reports -Scope CurrentUser
# Connect with reporting scope
Connect-MgGraph -Scopes "Reports.Read.All"
# Pull the team activity report -- period options are D7, D30, D90, D180
$reportPath = "$env:TEMP\TeamsActivity.csv"
Get-MgReportTeamActivityDetail -Period "D90" -OutFile $reportPath
# Load it and find teams with no activity inside the window
$report = Import-Csv -Path $reportPath
$inactiveThresholdDays = 90
$cutoffDate = (Get-Date).AddDays(-$inactiveThresholdDays)
$inactiveTeams = $report | Where-Object {
[string]::IsNullOrEmpty($_.'Last Activity Date') -or
[datetime]$_.'Last Activity Date' -lt $cutoffDate
}
$inactiveTeams | Select-Object 'Team Name', 'Team Id', 'Last Activity Date' |
Export-Csv -Path "$env:TEMP\InactiveTeams.csv" -NoTypeInformation
Write-Host "Found $($inactiveTeams.Count) inactive teams. Exported to InactiveTeams.csv"
The -Period parameter takes D7, D30, D90, or D180 — there’s no arbitrary date range shorter than that, and a specific -Date only works for dates inside the last 28 days. If you’ve seen older scripts that try to determine Teams inactivity by searching the unified audit log for message and file-access events and matching them to a team ID, that approach is fragile and not how Microsoft’s own reporting does it — this report endpoint exists specifically so you don’t have to reconstruct activity from raw audit entries yourself.
Best practices
- Don’t delete on the first pass. Notify owners and give a grace period before archiving or removing anything the report flags.
- Tag Teams with metadata (project, department, creation date) if you’re doing this regularly — it turns a raw inactivity list into something you can actually triage by owner.
- Run it on a schedule (quarterly is common) rather than as a one-off, since Teams sprawl accumulates continuously.
- Log what the report flagged and what action was taken — if a “dead” Team turns out to matter to someone, you want a record of when it was flagged and who was notified.
The Teams activity report is a purpose-built Graph endpoint with its own Last Activity Date column — don’t reconstruct it from audit log searches when Microsoft already did the work.
When would you actually use this?
- A quarterly governance review needs a list of stale Teams to send to owners before anything gets archived.
- You’re auditing external guest access and want to prioritize Teams that are both inactive and have guests still in them.
- Licensing or storage costs are climbing and inactive Teams are a suspect worth ruling in or out with real data instead of guessing.
Related reading
- Teams Management with PowerShell — the broader set of Teams admin tasks this activity report is one piece of.
- Exporting Inactive Users in SharePoint — the same “find what’s gone stale” problem, applied to users instead of Teams.
That should get you moving. Let me know in the comments if it doesn’t.
App Catalog Authentication Automation Backup Compliance Content Type CSS Flows Google Javascript Limitations List Metadata MFA Microsoft Node NodeJs O365 OneDrive Permissions PnP PnPJS Policy PowerApps Power Automate PowerAutomate PowerPlatform PowerShell React ReactJs Rest API Rest Endpoint Security Send an HTTP Request to SharePoint SharePoint SharePoint List SharePoint Modern SharePoint Online SPFX SPO Sync Tags Teams Termstore Versioning



As I site possessor I believe the content material here is rattling great , appreciate it for your efforts. You should keep it up forever! Good Luck.