Simplify user tasks like bulk creation, updates, password resets, deletions, license checks & more — all from one place.
🚀 Launch ToolkitNew Teams pop up fast—project kickoffs, department pilots, ad-hoc collaboration. Without visibility into what’s been created recently, admins can miss duplication, unchecked sprawl, or Teams that should be branded/governed before they scale. This script gives you a clean, automated snapshot of all Teams created in the last 30 days, dropped in your inbox as a CSV so you can act quickly.
# ===== Recently Created Microsoft Teams (Last 30 Days) -> CSV -> Email =====
# Requires: Microsoft.Graph module
# Scopes: Group.Read.All, Mail.Send
# --- Email variables ---
$FromUser = "admin@contoso.com" # Sender (must have mailbox)
$To = "it-ops@contoso.com" # Recipient
$Subject = "Recently Created Microsoft Teams (Last 30 Days)"
$CsvOutDir = "$env:TEMP"
# --- Connect to Microsoft Graph ---
Import-Module Microsoft.Graph -ErrorAction Stop
Connect-MgGraph -Scopes "Group.Read.All","Mail.Send"
# --- Build 30-day window ---
$since = (Get-Date).AddDays(-30)
# --- Get ALL Teams-backed groups (cannot filter by createdDateTime on server) ---
$teamsAll = Get-MgGroup -All -Filter "resourceProvisioningOptions/Any(x:x eq 'Team')" `
-Property "id,displayName,description,visibility,createdDateTime,mailNickname"
# --- Filter client-side to last 30 days ---
$recentTeams = $teamsAll | Where-Object {
$_.CreatedDateTime -and ([datetime]$_.CreatedDateTime) -ge $since
}
# --- Shape rows for CSV ---
$rows = $recentTeams | ForEach-Object {
[PSCustomObject]@{
TeamId = $_.Id
TeamName = $_.DisplayName
Description = $_.Description
Visibility = $_.Visibility
CreatedDate = $_.CreatedDateTime
}
}
# --- Export to CSV ---
if (-not (Test-Path -Path $CsvOutDir)) { New-Item -ItemType Directory -Path $CsvOutDir | Out-Null }
$ts = Get-Date -Format "yyyyMMdd_HHmmss"
$csvPath = Join-Path $CsvOutDir ("Recently_Created_Teams_{0}.csv" -f $ts)
$rows | Sort-Object CreatedDate -Descending | Export-Csv -Path $csvPath -NoTypeInformation -Encoding UTF8
# --- Prepare HTML Body ---
$totalTeams = $rows.Count
$summaryHtml = @"
<html>
<body style='font-family:Segoe UI,Arial,sans-serif'>
<h3>Recently Created Microsoft Teams (Last 30 Days)</h3>
<p>Total new Teams: <b>$totalTeams</b></p>
<p>The full list (TeamId, Name, Visibility, CreatedDate) is attached as a CSV.</p>
</body>
</html>
"@
# --- Prepare Attachment ---
$fileBytes = [System.IO.File]::ReadAllBytes($csvPath)
$base64Content = [System.Convert]::ToBase64String($fileBytes)
$csvFileName = [System.IO.Path]::GetFileName($csvPath)
$attachment = @{
"@odata.type" = "#microsoft.graph.fileAttachment"
name = $csvFileName
contentBytes = $base64Content
contentType = "text/csv"
}
# --- Prepare and Send Email ---
$mail = @{
message = @{
subject = "$Subject"
body = @{
contentType = "HTML"
content = $summaryHtml
}
toRecipients = @(@{ emailAddress = @{ address = $To } })
attachments = @($attachment)
}
saveToSentItems = $true
}
Send-MgUserMail -UserId $FromUser -BodyParameter $mail
Write-Host "Done. CSV saved at: $csvPath" -ForegroundColor Green
Uses Group.Read.All to read Teams-backed groups and Mail.Send to email the CSV.
Retrieves Microsoft 365 groups where resourceProvisioningOptions includes "Team".
Because createdDateTime isn’t filterable server-side, the script filters client-side to Teams created within the last 30 days.
Shapes each result into a row containing TeamId, TeamName, Description, Visibility, CreatedDate.
Exports the rows to a timestamped CSV, attaches it, and sends an HTML summary to the admin.
Error | Cause | Solution |
---|---|---|
Authorization_RequestDenied | Missing scopes or consent | Reconnect with Group.Read.All and Mail.Send; ensure admin consent. |
Get-MgGroup not recognized | Module not installed | Install-Module Microsoft.Graph -Scope CurrentUser, then import. |
Empty CSV | No Teams created in last 30 days | Validate base Teams retrieval by removing the date filter temporarily. |
Email not sent | $FromUser isn’t mailbox-enabled | Use a licensed mailbox-enabled account as sender. |
Slow/large tenants | Many Teams returned before local filtering | Acceptable tradeoff for reliability; if needed, add paging or pre-sorting later. |
New Teams should be welcomed—not lost in the noise. This script gives you timely visibility into every Team created in the last 30 days, packaged as a CSV and delivered to your inbox. Schedule it, extend it with ownership and activity signals, and you’ll keep your Microsoft 365 landscape tidy, compliant, and ready for scale.
© m365corner.com. All Rights Reserved. Design by HTML Codex