Entra / Microsoft 365 · Teams
Report teams channel email addresses
A script to report the email addresses for Teams channels that are mail-enabled.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -AppId $AppId -TenantId $TenantId -ClientSecret $AppSecret -NoWelcome
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
param([string] $TenantId = "",[string] $AppId = "s716b32c-0edb-48be-9385-30a9cfd96155")Clear-Host# Define the values applicable for the application used to connect to the Graph (these are specific to a tenant)$AppSecret = 'j_rkvIn1oZ1cNceUBvJ2or1lrrIsb*:='# Construct URI and body needed for authentication$uri = "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token"$body = @{client_id = $AppIdscope = "https://graph.microsoft.com/.default"client_secret = $AppSecretgrant_type = "client_credentials"}# Get OAuth 2.0 Token$tokenRequest = Invoke-WebRequest -Method Post -Uri $uri -ContentType "application/x-www-form-urlencoded" -Body $body -UseBasicParsing# Unpack Access Token$token = ($tokenRequest.Content | ConvertFrom-Json).access_token# Base URL$uri = "https://graph.microsoft.com/beta/"$headers = @{Authorization = "Bearer $token"}$ctype = "application/json"# Create list of Teams in the tenantWrite-Host "Fetching list of Teams in the tenant"[array]$Teams = Invoke-WebRequest -Method GET -Uri "$($uri)groups?`$filter=resourceProvisioningOptions/Any(x:x eq 'Team')" -ContentType $ctype -Headers $headers | ConvertFrom-Json$TeamsHash = @{}$Teams.Value.ForEach( {$TeamsHash.Add($_.Id, $_.DisplayName) } )$NextLink = $Teams.'@Odata.NextLink'While ($null -ne $Nextlink) {$Teams = Invoke-WebRequest -Method GET -Uri $NextLink -ContentType $ctype -Headers $headers | ConvertFrom-Json$Teams.Value.ForEach( {$TeamsHash.Add($_.Id, $_.DisplayName) } )$NextLink = $Teams.'@odata.NextLink' }# All teams found...Clear-HostWrite-Host "Processing" $TeamsHash.Count "Teams..."# Loop through each team to examine its channels and discover if any are email-enabled$i = 0; $EmailAddresses = 0; $Report = [System.Collections.Generic.List[Object]]::new() # Create output file for report; $ReportLine = $NullForEach ($Team in $TeamsHash.Keys) {$i++$TeamId = $($Team); $TeamDisplayName = $TeamsHash[$Team] #Populate variables to identify the team$ProgressBar = "Processing Team " + $TeamDisplayName + " (" + $i + " of " + $TeamsHash.Count + ")"Write-Progress -Activity "Checking Teams Information" -Status $ProgressBar -PercentComplete ($i/$TeamsHash.Count*100)Try { # Get owners of the team$TeamOwners = Invoke-WebRequest -Method GET -Uri "$($uri)groups/$($TeamId)/owners" -ContentType $ctype -Headers $headers | ConvertFrom-JsonIf ($TeamOwners.Value.Count -eq 1) {$TeamOwner = $TeamOwners.Value.DisplayName}Else { # More than one team owner, so let's split them out and make the string look pretty$Count = 1ForEach ($Owner in $TeamOwners.Value) {If ($Count -eq 1) { # First owner in the list$TeamOwner = $Owner.DisplayName$Count++ }Else { $TeamOwner = $TeamOwner + "; " + $Owner.DisplayName }}}}Catch {Write-Host "Unable to get owner information for team" $TeamDisplayName }Try { # Fetch list of channels for the team$Channels = Invoke-WebRequest -Method GET -Uri "$($uri)teams/$($TeamId)/channels" -ContentType $ctype -Headers $headers | ConvertFrom-JsonForEach ($Channel in $Channels.Value) {If (-Not [string]::IsNullOrEmpty($Channel.Email)) {$EmailAddresses++$ReportLine = [PSCustomObject][Ordered]@{Team = $TeamDisplayNameTeamEmail = $Team.MailOwners = $TeamOwnerChannel = $Channel.DisplayNameChannelDescription = $Channel.DescriptionChannelEmailAddress = $Channel.EmailTeamId = $TeamId }# And store the line in the report object$Report.Add($ReportLine) }}}Catch { Write-Host "Unable to fetch channels for" $Team.DisplayName }}$Report | Sort-Object Team | Export-CSV C:\Temp\TeamsChannelsWithEmailAddress.Csv -NoTypeInformationWrite-Host $EmailAddresses "mail-enabled channels found. Details are in C:\Temp\TeamsChannelsWithEmailAddress.Csv"# Graph SDK version[array]$Teams = Get-MgGroup -Filter "resourceProvisioningOptions/Any(x:x eq 'Team')" -AllIf (!($Teams)) {Write-Host "Can't find any teams - exiting"; break}$Teams = $Teams | Sort-Object DisplayName$ChannelsList = [System.Collections.Generic.List[Object]]::new()[int]$i = 0ForEach ($Team in $Teams) {$i++$ProgressBar = "Processing Team " + $Team.DisplayName + " (" + $i + " of " + $Teams.Count + ")"Write-Progress -Activity "Checking Teams Information" -Status $ProgressBar -PercentComplete ($i/$Teams.Count*100)Try {[array]$Channels = Get-MgTeamChannel -Teamid $Team.Id -ErrorAction SilentlyContinueForEach ($Channel in $Channels) {If ($Channel.Email) {$ChannelLine = [PSCustomObject][Ordered]@{ # Write out details of the private channel and its membersTeam = $Team.DisplayNameChannel = $Channel.DisplayNameDescription = $Channel.DescriptionEMail = $Channel.EmailId = $Channel.Id }$ChannelsList.Add($ChannelLine) }} #End Foreach Channel} Catch {Write-Output ("Whoops - had a problem processing the {0} team" -f $Team.displayName)}} # End ForEach Team# Elminate the General channel$TeamsEmailAddresses = $ChannelsList | Where-Object {$_.Email -Like "*.teams.ms"}$TeamsEmailAddresses | Out-GridView
Parameters
ParameterDefaultNotes
-TenantId""Microsoft Entra tenant ID for app-only Graph authentication.-AppIds716b32c-0edb-48be-9385-30a9cfd96155Application (client) ID for the app registration used to connect.Attribution
Author
Office365itpros