All scripts
Microsoft 365 621

Viva Engage Community Membership Report

Pulls every Viva Engage (Yammer) community, its membership count, and current admins using Microsoft Graph, so you can spot communities with no active admin or an unusually large membership before they become a governance headache.

Get-VivaEngageCommunityMembershipReport.ps1
<#
.SYNOPSIS
    Reports on Viva Engage (Yammer) community membership and admin coverage.

.DESCRIPTION
    Connects to Microsoft Graph and pulls every Viva Engage community, its
    member count, and the current list of community admins. Communities
    with zero admins or an unusually high member count are flagged, so you
    can catch ownerless communities and oversized ones before they turn
    into a support problem. Requires the Microsoft.Graph module and an
    account with Community.Read.All (or Community.ReadWrite.All)
    permissions. This uses the beta Graph endpoint since Viva Engage
    communities are not yet in v1.0.

.AUTHOR
    Shehryar Hassan

.EXAMPLE
    .\Get-VivaEngageCommunityMembershipReport.ps1 -LargeCommunityThreshold 500 -OutputPath .\communities.csv

    Runs the report, flags communities with more than 500 members, and
    writes the results to communities.csv.
#>

[CmdletBinding()]
param(
    [int]$LargeCommunityThreshold = 500,
    [string]$OutputPath = ".\VivaEngageCommunityReport.csv"
)

if (-not (Get-Module -ListAvailable -Name Microsoft.Graph.Authentication)) {
    Write-Error "Microsoft.Graph module is not installed. Run: Install-Module Microsoft.Graph -Scope CurrentUser"
    return
}

Import-Module Microsoft.Graph.Authentication -ErrorAction Stop

Connect-MgGraph -Scopes "Community.Read.All" -NoWelcome

$results = @()
$uri = "https://graph.microsoft.com/beta/employeeExperience/communities?`$top=50"

while ($uri) {
    $response = Invoke-MgGraphRequest -Method GET -Uri $uri

    foreach ($community in $response.value) {
        $communityId = $community.id
        $memberCount = 0
        $adminNames = @()

        try {
            $adminUri = "https://graph.microsoft.com/beta/employeeExperience/communities/$communityId/owners?`$select=displayName,mail"
            $admins = Invoke-MgGraphRequest -Method GET -Uri $adminUri
            $adminNames = $admins.value | ForEach-Object { $_.displayName }
        }
        catch {
            Write-Warning "Could not read admins for community '$($community.displayName)': $($_.Exception.Message)"
        }

        try {
            $memberUri = "https://graph.microsoft.com/beta/employeeExperience/communities/$communityId/members/`$count"
            $countResponse = Invoke-MgGraphRequest -Method GET -Uri $memberUri -Headers @{ "ConsistencyLevel" = "eventual" }
            $memberCount = [int]$countResponse
        }
        catch {
            Write-Warning "Could not read member count for community '$($community.displayName)': $($_.Exception.Message)"
        }

        $results += [PSCustomObject]@{
            CommunityName  = $community.displayName
            CommunityId    = $communityId
            Privacy        = $community.privacy
            MemberCount    = $memberCount
            AdminCount     = $adminNames.Count
            Admins         = ($adminNames -join "; ")
            NoAdminFlag    = ($adminNames.Count -eq 0)
            LargeGroupFlag = ($memberCount -gt $LargeCommunityThreshold)
        }
    }

    $uri = $response.'@odata.nextLink'
}

$results | Sort-Object MemberCount -Descending | Export-Csv -Path $OutputPath -NoTypeInformation

$noAdminCount = ($results | Where-Object { $_.NoAdminFlag }).Count
$largeCount = ($results | Where-Object { $_.LargeGroupFlag }).Count

Write-Host "Report saved to $OutputPath"
Write-Host "$($results.Count) communities checked, $noAdminCount with no admin, $largeCount over $LargeCommunityThreshold members"

Disconnect-MgGraph | Out-Null

Read it before you run it, and test in a safe tenant first.