๐Ÿ”ง New: User Management Graph PowerShell Toolkit

Simplify user tasks like bulk creation, updates, password resets, deletions, license checks & more โ€” all from one place.

๐Ÿš€ Launch Toolkit

Email HiddenMembership Teams Report Using Graph PowerShell

In Microsoft Teams, some groups have HiddenMembership visibility enabled โ€” meaning their member lists are concealed for confidentiality or security reasons. These teams are often used for sensitive projects or executive collaboration. Keeping track of them helps administrators maintain oversight, ensure compliance, and prevent accidental misconfiguration.

This Graph PowerShell script retrieves all Teams in your tenant with HiddenMembership visibility, generates a detailed CSV report, and automatically emails it to administrators.


i) The Script


Import-Module Microsoft.Graph -ErrorAction Stop
Connect-MgGraph -Scopes "Group.Read.All","Team.ReadBasic.All","Mail.Send"

$FromUser  = "admin@contoso.com"
$ToList    = "it-ops@contoso.com;teams-admin@contoso.com"
$Subject   = "HiddenMembership Teams Report"
$CsvOutDir = "$env:TEMP"

$teamsGroups = Get-MgGroup -All -Property Id,DisplayName,Visibility,CreatedDateTime,ResourceProvisioningOptions `
  -Filter "resourceProvisioningOptions/Any(x:x eq 'Team')"

$hiddenTeams = @()

foreach ($g in $teamsGroups) {
    if ($g.Visibility -ne "HiddenMembership") { continue }

    $ownerObjs = Get-MgGroupOwner -GroupId $g.Id -All -ErrorAction SilentlyContinue
    $ownerNames = @()
    $ownerMails = @()
    foreach ($o in ($ownerObjs | Where-Object { $_ })) {
        $name = $o.AdditionalProperties['displayName']
        $mail = $o.AdditionalProperties['mail']
        if ($name) { $ownerNames += $name }
        if ($mail) { $ownerMails += $mail }
    }

    $hiddenTeams += [PSCustomObject]@{
        TeamId       = $g.Id
        DisplayName  = $g.DisplayName
        Visibility   = $g.Visibility
        CreatedDate  = $g.CreatedDateTime
        Owners       = ($ownerNames -join "; ")
        OwnerEmails  = ($ownerMails -join "; ")
    }
}

if (-not (Test-Path -Path $CsvOutDir)) { New-Item -ItemType Directory -Path $CsvOutDir | Out-Null }
$ts      = Get-Date -Format "yyyyMMdd_HHmmss"
$csvPath = Join-Path $CsvOutDir ("HiddenMembership_Teams_{0}.csv" -f $ts)
$hiddenTeams | Sort-Object DisplayName | Export-Csv -NoTypeInformation -Encoding UTF8 -Path $csvPath

$total = $hiddenTeams.Count
$summaryHtml = @"
<html>
  <body style='font-family:Segoe UI,Arial,sans-serif'>
    <h3>HiddenMembership Teams Report</h3>
    <p>Total HiddenMembership teams: <b>$total</b></p>
    <p>Attached CSV includes: TeamId, DisplayName, Visibility, CreatedDate, Owners, OwnerEmails.</p>
  </body>
</html>
"@

$fileBytes     = [System.IO.File]::ReadAllBytes($csvPath)
$base64Content = [System.Convert]::ToBase64String($fileBytes)
$attachment    = @{
  "@odata.type" = "#microsoft.graph.fileAttachment"
  name          = [System.IO.Path]::GetFileName($csvPath)
  contentBytes  = $base64Content
  contentType   = "text/csv"
}

$recipients = @()
$ToList.Split(@(';', ','), [System.StringSplitOptions]::RemoveEmptyEntries) | ForEach-Object {
  $addr = $_.Trim()
  if ($addr) { $recipients += @{ emailAddress = @{ address = $addr } } }
}

$mail = @{
  message = @{
    subject = "$Subject"
    body    = @{ contentType = "HTML"; content = $summaryHtml }
    toRecipients = $recipients
    attachments  = @($attachment)
  }
  saveToSentItems = $true
}

Send-MgUserMail -UserId $FromUser -BodyParameter $mail

Write-Host "Done. CSV saved at: $csvPath" -ForegroundColor Green
                            


ii) How the Script Works

  1. Connects to Microsoft Graph:
  2. The script connects using Connect-MgGraph with the scopes Group.Read.All, Team.ReadBasic.All, and Mail.Send for Teams and mail access.

  3. Retrieves All Teams:
  4. It fetches all Microsoft 365 groups that are provisioned as Teams using the resourceProvisioningOptions property.

  5. Filters HiddenMembership Teams:
  6. The script isolates only those Teams where the Visibility is set to HiddenMembership.

  7. Fetches Ownersโ€™ Details:
  8. For each matching team, it retrieves owner names and email addresses using Get-MgGroupOwner.

  9. Generates and Emails Report:
  10. The script compiles the list into a CSV report and sends it as an email attachment to administrators, along with an HTML summary.


iii) Further Enhancements

  • Include member count or last activity date for usage insights.
  • Add team description and archival status for better context.
  • Schedule this report via Azure Automation or Power Automate.
  • Log results in SharePoint or OneDrive for record-keeping.
  • Integrate an alert if new hidden Teams are detected.

iv) Possible Errors and Solutions

Error Cause Solution
Access Denied Insufficient Graph permissions Use the correct scopes: Group.Read.All, Team.ReadBasic.All, Mail.Send.
Empty CSV No hidden Teams found Confirm whether your tenant contains any Teams with HiddenMembership.
Send-MgUserMail fails Sender mailbox missing Ensure $FromUser has a valid Exchange mailbox.
Request_UnsupportedQuery Incorrect filter syntax Verify the Graph filter syntax exactly matches resourceProvisioningOptions/Any(x:x eq 'Team').
Owners missing Team owners not assigned Verify team ownership in Microsoft Teams admin center.

v) Conclusion

This Graph PowerShell script gives administrators clear visibility into Teams configured with HiddenMembership, often used for confidential collaboration. By automating this report and delivering it via email, IT admins can maintain proper oversight of hidden Teams, ensuring compliance and visibility into sensitive collaboration spaces across Microsoft 365.


Graph PowerShell Explorer Widget

20 Graph PowerShell cmdlets with easily accessible "working" examples.


Permission Required

Example:


                


                


                

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