Fetch Private Microsoft Teams Using Microsoft Graph PowerShell

Microsoft Teams provides a secure and collaborative workspace for organizations, but tracking private Teams across a tenant can be challenging. Private Teams restrict access to only invited members, making it essential for IT administrators to monitor their existence, membership, and status. This article presents a Graph PowerShell script that retrieves all private Microsoft Teams in a tenant and displays:

  • Team Name
  • Team Description
  • Member Count
  • Owner Count
  • Archive Status

Script to Fetch Private Teams

Below is the PowerShell script that retrieves all private Teams and their details.

# Install & Import Graph Module (if not already installed)
Install-Module Microsoft.Graph -Scope CurrentUser
Import-Module Microsoft.Graph
                                
# Connect to Microsoft Graph
Connect-MgGraph -Scopes "Group.Read.All", "Team.ReadBasic.All"
                                
# Fetch all Teams (no direct filter for 'visibility', so we filter later)
$AllTeams = Get-MgGroup -Filter "resourceProvisioningOptions/any(x:x eq 'Team')" -Property Id, DisplayName, Description, Visibility -All
                                
# Filter out only Private Teams
$PrivateTeams = $AllTeams | Where-Object { $_.Visibility -eq "Private" }
                                
if ($PrivateTeams.Count -eq 0) {
    Write-Host "No private Microsoft Teams found in the tenant." -ForegroundColor Yellow
} else {
$TeamDetails = @()
                                
foreach ($Team in $PrivateTeams) {
    # Fetch Team Members
    $Members = Get-MgGroupMember -GroupId $Team.Id -All
    $MemberCount = ($Members | Measure-Object).Count
                                    
    # Fetch Team Owners
    $Owners = Get-MgGroupOwner -GroupId $Team.Id -All
    $OwnerCount = ($Owners | Measure-Object).Count
                                    
    # Fetch Team Archive Status
    $TeamData = Get-MgTeam -TeamId $Team.Id -Property IsArchived
    $ArchiveStatus = if ($TeamData.IsArchived -eq $true) { "Archived" } else { "Active" }
                                
    # Store details in custom object
        $TeamDetails += [PSCustomObject]@{
        "Team Name"        = $Team.DisplayName
        "Team Description" = $Team.Description
        "Member Count"     = $MemberCount
        "Owner Count"      = $OwnerCount
        "Archive Status"   = $ArchiveStatus
    }
}
                                
# Display Results in Table Format
    $TeamDetails | Format-Table -AutoSize
}
                                
# Disconnect from Graph
Disconnect-MgGraph

How the Script Works

  1. Connects to Microsoft Graph
    • The script starts by authenticating with Microsoft Graph using Group.Read.All and Team.ReadBasic.All permissions.
  2. Retrieves All Teams
    • The script fetches all Teams using Get-MgGroup with resourceProvisioningOptions/any(x:x eq 'Team').
  3. Filters Only Private Teams
    • Since visibility cannot be filtered via Graph API, the script filters private teams in PowerShell using:
    • $PrivateTeams = $AllTeams | Where-Object { $_.Visibility -eq "Private" }
  4. Fetches Team Details
  5. Displays the Results in a Table Format
    • A structured table with all necessary details is displayed.
  6. Disconnects from Graph
    • Ensures the Graph session is terminated after execution.

Further Enhancements

Here are some improvements that can be made to the script:

  • Export Data to CSV for further analysis:
  • $TeamDetails | Export-Csv -Path "PrivateTeamsReport.csv" -NoTypeInformation
  • Filter Teams by Creation Date using an additional -Filter parameter.
  • Include Channel Count by fetching Get-MgTeamChannel -TeamId $Team.Id.
  • Automate with Task Scheduler to generate reports periodically.

Use Cases

  • Security Audits: Identify private teams that need monitoring or cleanup.
  • Compliance Checks: Ensure that sensitive Teams comply with governance policies.
  • Membership Review: Assess member and owner distribution within private Teams.
  • Inactive Team Management: Detect and manage archived or underused Teams.

Possible Errors & Solutions

Error Cause Solution
Error: No private Microsoft Teams found in the tenant No private teams exist in the tenant. Verify that private teams exist before running the script.
Get-MgGroupMember: Access Denied The account lacks permissions. Ensure Group.Read.All and Team.ReadBasic.All are granted and admin consented.
Visibility filter error The visibility property cannot be filtered directly in Graph API. The script correctly filters teams after retrieving all Teams.
Get-MgTeam: Not Found The team may not be fully provisioned or accessible. Ensure the team exists and is accessible via Microsoft Graph.
💡 Use visibility eq 'Private' to Retrieve Private Teams

The Get-MgGroup cmdlet filters Microsoft 365 groups (including Teams) based on visibility. To fetch only private Teams, use the following filter:

-Filter "resourceProvisioningOptions/Any(x:x eq 'Team') and visibility eq 'Private'"
🔍 Private Teams Are Backed by Microsoft 365 Groups

Every private Microsoft Team is backed by a private M365 group. This means filtering M365 groups using "Team" and "Private" attributes helps list all private Teams — whether created directly in Teams or via apps like Planner or SharePoint.

Conclusion

This PowerShell script provides an efficient and automated way to retrieve private Microsoft Teams from a Microsoft 365 tenant. It allows administrators to monitor team members, owners, and archive status, ensuring better governance and compliance. With additional enhancements like CSV exports and scheduled execution, this script can become a powerful tool in Microsoft Teams administration.


© m365corner.com. All Rights Reserved. Design by HTML Codex