๐ฌ Recipe ยท Microsoft Teams
List all Microsoft 365 Groups and Teams in the tenant
Inventory every Microsoft 365 Group and identify which ones are Teams-enabled
Complexity
Beginner
Impact
inventory + governance + reporting + read-only
Context
Why This Matters
Microsoft 365 Groups are the membership backbone for Teams, SharePoint sites, Planner, Outlook distribution, and Yammer communities. Over time, tenants accumulate hundreds or thousands of groups โ some created deliberately by admins, others auto-provisioned when users spin up a new Team or Planner board. Without periodic inventory, it becomes hard to answer basic governance questions: How many Teams do we have? Which groups are orphaned? Are there duplicates?
This recipe produces a complete inventory of every Microsoft 365 Group in your tenant and flags which ones are Teams-enabled (vs. Outlook-only groups or SharePoint-only groups). Run it as a starting point for lifecycle cleanup, license chargeback, security reviews, or migration planning.
Expected Outcomes
After completing this recipe, you will have:
- A complete list of all Microsoft 365 Groups in the tenant, with display name, description, and group type
- A clear distinction between Teams-enabled groups and other group types (Outlook, Security, Distribution)
- Group IDs that can be fed into follow-up scripts (membership audits, archival, deletion)
- An exportable CSV suitable for sharing with governance, security, or compliance stakeholders
Risks & Considerations
Things to watch for
- Permissions: You need
Group.Read.All(delegated or application). Without it, the Graph call returns HTTP 403. - Paging: Tenants with more than 100 groups will return an
@odata.nextLink. You must follow it or you will miss groups. The sample script handles this automatically. - Throttling: Very large tenants (10k+ groups) may hit Graph throttling. Add retry-with-backoff or use
$top=999to reduce round trips. - Soft-deleted groups: This query does not return deleted groups. To include them, query
/directory/deletedItems/microsoft.graph.groupseparately. - Privacy: Group names and descriptions can contain sensitive project codenames. Treat the export as confidential.
Required Permissions
| Permission | Why It's Needed |
|---|---|
| Group.Read.All | Required to list all Microsoft 365 Groups and read their properties, including groupTypes and resourceProvisioningOptions which identifies Teams. |
| Directory.Read.All | Alternative broader permission that also grants read access to all directory objects including groups. |
The fastest way to get this done: just ask Dex. Copy the prompt below and paste it into your Dex conversation.
For IT Admins
Paste into Dex Pro
List groups and Teams via the admin centers
The Microsoft 365 admin center and Teams admin center both surface group/team lists in the browser โ useful for a quick view, but limited for large tenants.
Option A โ Microsoft 365 admin center (all group types)
- Sign in to https://admin.microsoft.com as a Global Administrator or Groups Administrator.
- In the left navigation, expand .
- Use the tabs at the top to filter by type: Teams, Microsoft 365, Distribution list, Mail-enabled security, Security.
- Click Export (top of the list) to download the current view as a CSV.
Option B โ Teams admin center (Teams only)
- Sign in to https://admin.teams.microsoft.com.
- Navigate to .
- Review the list of Teams, including channel count, member count, and privacy setting.
- Click Export to CSV in the toolbar.
Tip: The admin center UI is fine for under a few hundred groups. For larger tenants or recurring audits, use the Graph API or PowerShell approach below.
List groups via Microsoft Graph
The Graph /groups endpoint returns every group in the directory. Select resourceProvisioningOptions to identify Teams โ a group is Teams-enabled when this collection contains the string "Team".
Request
GET https://graph.microsoft.com/v1.0/groups?$select=id,displayName,description,groupTypes,resourceProvisioningOptions,mail,visibility&$top=999
Authorization: Bearer <access_token>
ConsistencyLevel: eventualSample response
{
"@odata.context": "https://graph.microsoft.com/v1.0/$metadata#groups",
"@odata.nextLink": "https://graph.microsoft.com/v1.0/groups?$skiptoken=...",
"value": [
{
"id": "a1b2c3d4-...",
"displayName": "Marketing Team",
"description": "Marketing collaboration space",
"groupTypes": ["Unified"],
"resourceProvisioningOptions": ["Team"],
"mail": "marketing@contoso.com",
"visibility": "Private"
}
]
}Interpreting the result
groupTypes = ["Unified"]โ Microsoft 365 Group (has mailbox, SharePoint site)groupTypes = ["Unified", "DynamicMembership"]โ Dynamic M365 GroupgroupTypes = []withsecurityEnabled = trueโ Security groupresourceProvisioningOptionscontains"Team"โ Teams-enabled
Paging
Follow the @odata.nextLink URL until it is no longer returned. Each page holds up to 999 items when $top=999.
Filter to Teams only
GET /v1.0/groups?$filter=resourceProvisioningOptions/Any(x:x eq 'Team')&$count=true
ConsistencyLevel: eventualThe ConsistencyLevel: eventual header is required for advanced queries ($filter on resourceProvisioningOptions, $count, $search).
List groups and Teams with PowerShell
The Microsoft Graph PowerShell SDK wraps the Graph endpoints shown above and handles paging and token refresh automatically.
Prerequisites
- Install the module (one-time):
Install-Module Microsoft.Graph -Scope CurrentUser - Connect with the required scope:
Connect-MgGraph -Scopes "Group.Read.All"
List all groups and flag Teams
# Get every group, requesting only the fields we need
$groups = Get-MgGroup -All -Property Id,DisplayName,Description,GroupTypes,ResourceProvisioningOptions,Mail,Visibility
# Project into a flat report with an IsTeam column
$report = $groups | ForEach-Object {
[pscustomobject]@{
Id = $_.Id
DisplayName = $_.DisplayName
Description = $_.Description
GroupType = if ($_.GroupTypes -contains 'Unified') { 'Microsoft 365' } else { 'Security/Distribution' }
IsTeam = $_.ResourceProvisioningOptions -contains 'Team'
Mail = $_.Mail
Visibility = $_.Visibility
}
}
$report | Format-Table -AutoSize
$report | Export-Csv -Path ".\Groups-Inventory.csv" -NoTypeInformationQuick counts
$report | Group-Object GroupType | Select Name,Count
"Teams: " + ($report | Where IsTeam).Count
"Total groups: " + $report.CountNext steps