Simplify user tasks like bulk creation, updates, password resets, deletions, license checks & more β all from one place.
π Launch ToolkitWhen managing Microsoft Teams environments, keeping track of archived teams is essential β especially public ones that remain visible but inactive. These teams can accumulate over time, leading to clutter, unnecessary data retention, or potential compliance risks. This Graph PowerShell script automatically identifies all public archived Teams within your tenant, generates a detailed report, and emails it to administrators for review or cleanup planning.
Import-Module Microsoft.Graph -ErrorAction Stop
Connect-MgGraph -Scopes "Group.Read.All","Team.ReadBasic.All","Mail.Send"
$FromUser = "admin@contoso.com"
$ToList = "it-ops@contoso.com;teams-admin@contoso.com"
$Subject = "Public Archived Teams Report"
$CsvOutDir = "$env:TEMP"
$teamsGroups = Get-MgGroup -All -Property Id,DisplayName,Visibility,CreatedDateTime,ResourceProvisioningOptions `
-Filter "resourceProvisioningOptions/Any(x:x eq 'Team')"
$publicArchived = @()
foreach ($g in $teamsGroups) {
if ($g.Visibility -ne "Public") { continue }
$team = Get-MgTeam -TeamId $g.Id -ErrorAction SilentlyContinue
if ($null -ne $team -and $team.IsArchived -eq $true) {
$ownerObjs = Get-MgGroupOwner -GroupId $g.Id -All -ErrorAction SilentlyContinue
$ownerNames = @()
$ownerMails = @()
foreach ($o in ($ownerObjs | Where-Object { $_ })) {
$name = $o.AdditionalProperties['displayName']
$mail = $o.AdditionalProperties['mail']
if ($name) { $ownerNames += $name }
if ($mail) { $ownerMails += $mail }
}
$publicArchived += [PSCustomObject]@{
TeamId = $g.Id
DisplayName = $g.DisplayName
Visibility = $g.Visibility
IsArchived = $team.IsArchived
CreatedDate = $g.CreatedDateTime
Owners = ($ownerNames -join "; ")
OwnerEmails = ($ownerMails -join "; ")
}
}
}
if (-not (Test-Path -Path $CsvOutDir)) { New-Item -ItemType Directory -Path $CsvOutDir | Out-Null }
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
$csvPath = Join-Path $CsvOutDir ("Public_Archived_Teams_{0}.csv" -f $ts)
$publicArchived | Sort-Object DisplayName | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $csvPath
$total = $publicArchived.Count
$summaryHtml = @"
<html>
<body style='font-family:Segoe UI,Arial,sans-serif'>
<h3>Public Archived Teams Report</h3>
<p>Total public archived teams: <b>$total</b></p>
<p>Attached CSV includes: TeamId, DisplayName, Visibility, IsArchived, CreatedDate, Owners, OwnerEmails.</p>
</body>
</html>
"@
$fileBytes = [System.IO.File]::ReadAllBytes($csvPath)
$base64Content = [System.Convert]::ToBase64String($fileBytes)
$attachment = @{
"@odata.type" = "#microsoft.graph.fileAttachment"
name = [System.IO.Path]::GetFileName($csvPath)
contentBytes = $base64Content
contentType = "text/csv"
}
$recipients = @()
$ToList.Split(@(';', ','), [System.StringSplitOptions]::RemoveEmptyEntries) | ForEach-Object {
$addr = $_.Trim()
if ($addr) { $recipients += @{ emailAddress = @{ address = $addr } } }
}
$mail = @{
message = @{
subject = "$Subject"
body = @{ contentType = "HTML"; content = $summaryHtml }
toRecipients = $recipients
attachments = @($attachment)
}
saveToSentItems = $true
}
Send-MgUserMail -UserId $FromUser -BodyParameter $mail
Write-Host "Done. CSV saved at: $csvPath" -ForegroundColor Green
The script uses the Connect-MgGraph cmdlet with Group.Read.All, Team.ReadBasic.All, and Mail.Send scopes to access Teams and send emails.
It retrieves all Microsoft 365 Groups provisioned as Teams by filtering on resourceProvisioningOptions.
It checks each teamβs Visibility and IsArchived properties, selecting only those that are both Public and Archived.
The script calls Get-MgGroupOwner for each team to list owners and their email addresses.
It compiles the team details β including Team ID, Display Name, Visibility, IsArchived status, Created Date, and Owners β and exports them to a CSV file in the temp directory.
A brief HTML summary is created, and the CSV file is sent as an attachment to designated recipients using Send-MgUserMail.
| Error | Cause | Solution |
|---|---|---|
| Request_UnsupportedQuery | Filter syntax issue | Ensure Graph query syntax matches resourceProvisioningOptions/Any(x:x eq 'Team'). |
| Access Denied | Missing permissions | Reconnect with Group.Read.All, Team.ReadBasic.All, and Mail.Send scopes. |
| Email not delivered | Sender has no mailbox | Ensure $FromUser has a valid Exchange mailbox. |
| Empty CSV | No public archived teams found | Verify that your tenant actually has archived public teams. |
| Get-MgTeam returns null | Team object may not yet exist or permissions insufficient | Wait a few minutes or verify app permissions. |
This Graph PowerShell script provides administrators with an automated way to identify and report all public archived Teams in the tenant. By regularly running this script, IT admins can keep their environment organized, reclaim storage, and maintain visibility into inactive collaboration spaces. Itβs a simple yet effective step toward better Teams lifecycle management in Microsoft 365.
© m365corner.com. All Rights Reserved. Design by HTML Codex