As a Microsoft 365 administrator, managing ” teams sprawl” is one of the biggest challenges. Over time, users create dozens of teams, invite external guests, and change ownership. Keeping tabs on who has access to what is critical for both security and license optimization.
Microsoft provides several ways to view this information. The Teams admin center works well when reviewing individual teams. However, PowerShell is more practical when you need a single report covering every team and its members. This guide explains each method and shows how to export a complete Microsoft Teams membership report.
Prerequisites to List All Microsoft Teams and Their Members
Before running the commands, ensure that you:
- Have an appropriate Microsoft Entra role, such as Directory Reader, Teams Administrator, or Global Administrator.
- Install the Microsoft Graph PowerShell module.
- Connect with the Group.Read.All, GroupMember.Read.All, and Team.ReadBasic.All permissions.
Directory Reader is the recommended least-privileged role for this read-only report.
How to List All Microsoft Teams and Their Members
You can use the following methods to view or export Microsoft Teams membership report.
Method 1: View Team Members in the Microsoft Teams Admin Center
The Microsoft Teams admin center provides a central view of the teams in your organization. It is useful when you want to review the configuration or membership of a specific team without running commands.
To view team membership, do the following.
- Sign in to the Microsoft Teams admin center.
- Go to Teams > Manage teams.
- Search for and select the required team.
- Open the Members or membership section on the team details page.
- Review the owners, members, and guests associated with the team.
The Teams admin center is convenient for checking individual teams, but it is less suitable for tenant-wide membership analysis. To see the actual users, administrators must open each team separately. Therefore, reviewing dozens or hundreds of teams becomes time-consuming.
Method 2: Get the List of All Teams and Team Members Using PowerShell
MS Teams uses Microsoft 365 groups to maintain its main team membership. Microsoft Graph PowerShell can identify Teams-enabled groups and retrieve their owners and members.
Before proceeding further, install Microsoft Graph PowerShell using the following command.
Install-Module Microsoft.Graph -Scope CurrentUser
Connect-MgGraph -Scopes "Group.Read.All", "GroupMember.Read.All", "Team.ReadBasic.All" After connecting to MS Graph PowerShell module, run the below.
#Retrieve all Microsoft 365 groups provisioned as Teams
Get-MgGroup -Filter "resourceProvisioningOptions/Any(x:x eq 'Team')" -Property Id, DisplayName, Visibility ` -All | Select-Object DisplayName, Id, Visibility Copy the ID of the required team and use it with the following commands.
#Get the team's members
Get-MgGroupMemberAsUser -GroupId "your-team-group-id-here" -Property Id, DisplayName, UserPrincipalName, UserType ` -All
#Get the team's owners
Get-MgGroupOwnerAsUser -GroupId "your-team-group-id-here" -Property Id, DisplayName, UserPrincipalName, UserType ` -All This method works well when you only need to check one or two teams. The basic commands also do not provide a consolidated report or clearly record teams whose membership could not be retrieved. For a tenant-wide review, an automated script is more practical.
Method 3: Export All Microsoft Teams and Their Members Using PowerShell Script
The following script retrieves every team, obtains its owners and members, and exports the results to a CSV file.
# Connect to Microsoft Graph
Connect-MgGraph -Scopes `
"Group.Read.All", `
"GroupMember.Read.All", `
"Team.ReadBasic.All"
# Set the export location
$ReportPath = ".\MicrosoftTeamsMembershipReport.csv"
# Retrieve all Microsoft 365 groups provisioned as Teams
$Teams = Get-MgGroup `
-Filter "resourceProvisioningOptions/Any(x:x eq 'Team')" `
-Property Id, DisplayName, Visibility `
-All
$Report = foreach ($Team in $Teams) {
Write-Host "Processing: $($Team.DisplayName)" -ForegroundColor Cyan
try {
# Retrieve the Teams-specific archived status
$TeamDetails = Get-MgTeam -TeamId $Team.Id -ErrorAction Stop
# Retrieve team owners
$Owners = @(
Get-MgGroupOwnerAsUser `
-GroupId $Team.Id `
-Property Id, DisplayName, UserPrincipalName, UserType `
-All `
-ErrorAction Stop
)
# Retrieve all team members
$Members = @(
Get-MgGroupMemberAsUser `
-GroupId $Team.Id `
-Property Id, DisplayName, UserPrincipalName, UserType `
-All `
-ErrorAction Stop
)
$OwnerIds = @($Owners | ForEach-Object { $_.Id })
if ($Owners.Count -eq 0 -and $Members.Count -eq 0) {
[PSCustomObject]@{
TeamName = $Team.DisplayName
GroupId = $Team.Id
Visibility = $Team.Visibility
Archived = $TeamDetails.IsArchived
MemberName = ""
UserPrincipalName = ""
UserId = ""
UserType = ""
Role = ""
RetrievalStatus = "No members returned"
}
continue
}
# Add owners to the report
foreach ($Owner in $Owners) {
[PSCustomObject]@{
TeamName = $Team.DisplayName
GroupId = $Team.Id
Visibility = $Team.Visibility
Archived = $TeamDetails.IsArchived
MemberName = $Owner.DisplayName
UserPrincipalName = $Owner.UserPrincipalName
UserId = $Owner.Id
UserType = $Owner.UserType
Role = "Owner"
RetrievalStatus = "Success"
}
}
# Add users who are not owners
foreach ($Member in $Members) {
if ($Member.Id -notin $OwnerIds) {
[PSCustomObject]@{
TeamName = $Team.DisplayName
GroupId = $Team.Id
Visibility = $Team.Visibility
Archived = $TeamDetails.IsArchived
MemberName = $Member.DisplayName
UserPrincipalName = $Member.UserPrincipalName
UserId = $Member.Id
UserType = $Member.UserType
Role = "Member"
RetrievalStatus = "Success"
}
}
}
}
catch {
[PSCustomObject]@{
TeamName = $Team.DisplayName
GroupId = $Team.Id
Visibility = $Team.Visibility
Archived = ""
MemberName = ""
UserPrincipalName = ""
UserId = ""
UserType = ""
Role = ""
RetrievalStatus = "Failed: $($_.Exception.Message)"
}
}
}
# Export the report
$Report |
Sort-Object TeamName, Role, MemberName |
Export-Csv -Path $ReportPath -NoTypeInformation -Encoding UTF8
Write-Host "Report exported to: $ReportPath" -ForegroundColor Green The generated CSV contains one row for each user in each team. If a user belongs to multiple teams, the user appears once for every team membership.
The report includes the following attributes:
- TeamName: Display name of the team.
- GroupId: Unique ID of the Microsoft 365 group connected to the team.
- Visibility: Indicates whether the team is Public, Private, or HiddenMembership.
- Archived: Shows whether the team is currently archived.
- MemberName: Display name of the user.
- UserPrincipalName: Sign-in name or UPN of the user.
- UserId: Unique Microsoft Entra ID of the account.
- UserType: Identifies whether the account is an internal member or guest.
- Role: Shows whether the user is an Owner or Member.
- RetrievalStatus: Indicates whether the team’s membership was retrieved successfully.
Including RetrievalStatus makes it easier to identify teams that failed during the scan. The script also retains teams for which no users were returned, preventing them from disappearing from the final report.
Regularly reviewing this report helps administrators identify unnecessary access, verify team ownership, locate guest memberships, and maintain better control over Microsoft Teams access.