Entra / Microsoft 365 · Teams
Generate Teams directory (Graph)
Generate a list of Teams with deep links using Microsoft Graph that can be turned into a Teams directory with clickable hyperlinks.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-MgGraph -Scopes Group.Read.All, Directory.Read.All, GroupMember.Read.All, Team.ReadBasic.All, TeamSettings.Read.All
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
Connect-MgGraph -Scopes Group.Read.All, Directory.Read.All, GroupMember.Read.All, Team.ReadBasic.All, TeamSettings.Read.AllSelect-MgProfile Beta$Tenant = Get-MgOrganization$Today = (Get-Date)$Date = Get-Date($Today) -format f$ReportHeading = "Teams Organizational Directory for " + $Tenant.DisplayName$DeepLinkPrefix = "https://teams.microsoft.com/l/team/"$ReportFile = "c:\temp\TeamsDirectory.html"$ExcelFile = "c:\temp\Teams Directory.xlsx"$htmlhead="<!DOCTYPE html><html><style>BODY{font-family: Arial; font-size: 8pt;}H1{font-size: 22px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}H2{font-size: 18px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}H3{font-size: 16px; font-family: 'Segoe UI Light','Segoe UI','Lucida Grande',Verdana,Arial,Helvetica,sans-serif;}TABLE{border: 1px solid black; border-collapse: collapse; font-size: 8pt;}TH{border: 1px solid #969595; background: #dddddd; padding: 5px; color: #000000;}TD{border: 1px solid #969595; padding: 5px; }td.pass{background: #B7EB83;}td.warn{background: #FFF275;}td.fail{background: #FF2626; color: #ffffff;}td.info{background: #85D4FF;}</style><body><div align=center><p><h1>$ReportHeading</h1></p><p><h3>Generated: " + $date + "</h3></p></div>"Write-Host "Fetching List of Teams"[array]$Teams = Get-MgTeam -All | Sort DisplayNameIf (!($Teams)) { Write-Host "No teams found - exiting" ; break}Else {Write-Host ("Processing {0} teams" -f $Teams.count) }[int]$i = 0; [int]$Public = 0 ; [int]$Private = 0; [int]$HiddenMembership = 0$Report = [System.Collections.Generic.List[Object]]::new() # Create output file$ReportHTML = [System.Collections.Generic.List[Object]]::new() # Create output fileWrite-Host ("Processing {0} teams" -f $Teams.count)ForEach ($T in $Teams) {$i++Write-Host ("Processing team {0} {1}/{2}" -f $t.displayname, $i, $teams.count)$InternalId = Get-MgTeam -TeamId $T.Id | Select-Object -ExpandProperty InternalId$DeepLinkHTML = '<p><a href="' + $DeepLinkPrefix + $InternalId + "/conversations?groupId=" + $T.Id + "&tenantId=" + $Tenant.Id + '">Link to team</a></p>'$DeepLink = $DeepLinkPrefix + $InternalId + "/conversations?groupId=" + $T.Id + "&tenantId=" + $Tenant.Id# Find team owners$Data = [System.Collections.Generic.List[Object]]::new()[array]$Owners = Get-MgGroupOwner -GroupId $T.Id | Select-Object -ExpandProperty IdForEach ($Owner in $Owners) {$ON = Get-MgUser -UserId $Owner$DataLine = [PSCustomObject] @{Owner = $ON.DisplayNameEmail = $ON.Mail}$Data.Add($Dataline)}$OwnerDisplayNames = $Data.Owner -join ", "$OwnerSMTPAddress = $Data.Email -join ", "[array]$GroupMembers = Get-MgGroupMember -GroupId $T.Id | Select-Object -ExpandProperty Id$GroupMemberCount = $GroupMembers.Count$MemberCount = 0; $ExternalMemberCount = 0ForEach ($User in $GroupMembers) {$GM = Get-MgUser -UserId $UserIf ($GM.UserType -eq "member") { $MemberCount++ } Else { $ExternalMemberCount++ }}Switch ($T.visibility) {"Public" { $Public++ }"Hiddenmembership" { $HiddenMembership++ }"Private" { $Private++ }}# Generate a line for this group for our Excel worksheet$ReportLine = [PSCustomObject][Ordered]@{Team = $T.DisplayNameDescription = $T.Description'Link to access team' = $DeepLinkOwners = $OwnerDisplayNames'Owner Email' = $OwnerSMTPAddressMembers = $GroupMemberCount'Tenant Members' = $MemberCount'External Members' = $ExternalMemberCountAccess = $T.visibility }# And store the line in the report object$Report.Add($ReportLine)# Generate a line for this group for our HTML report$ReportHTMLLine = [PSCustomObject][Ordered]@{Team = $T.DisplayNameDescription = $T.Description'Link to access team' = $DeepLinkHTMLOwners = $OwnerDisplayNames'Owner Email' = $OwnerSMTPAddressMembers = $GroupMemberCount'Tenant Members' = $MemberCount'External Members' = $ExternalMemberCountAccess = $T.visibility }# And store the line in the report object$ReportHTML.Add($ReportHTMLLine)} # End Foreach Teams#End of processing teams - now create the HTML report and CSV file$htmlbody = $ReportHTML | ConvertTo-Html -Fragment$htmltail = "<p>Report created for: " + $Tenant.DisplayName + "</p><p>Number of teams scanned : " + $Teams.Count + "</p>" +"<p>Number of private teams : " + $Private + "</p>" +"<p>Number of teams with hidden membership: " + $HiddenMembership + "</p>" +"<p>Number of public teams: " + $Public + "</p></html>"$htmlreport = $htmlhead + $htmlbody + $htmltail# Make sure that we output a working hyperlink for the deeplinkAdd-Type -AssemblyName System.Web[System.Web.HttpUtility]::HtmlDecode($htmlreport) | Out-File $ReportFile -Encoding UTF8$Report | Export-Excel -Path $ExcelFile -WorksheetName "Teams Directory" -Title "Teams Directory" -TitleBold -TableName "TeamsDirectory" -TableStyle Dark1Write-Host ("Output files are available in {0} (CSV) and {1} (HTML)" -f $ExcelFile, $ReportFile)
Attribution
Author
Office365itpros