Entra / Microsoft 365 · Exchange Online
Report dl memberships counts
Report the membership and counts for distribution lists in Exchange Online.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-AzureAD
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
Function Get-RecursiveAzureAdGroupMemberUsers{[cmdletbinding()]# Modified from the code on https://saemundsson.se/?p=734param([parameter(Mandatory=$True,ValueFromPipeline=$true)]$AzureGroup)[array]$Members = Get-AzureADGroupMember -ObjectId $AzureGroup.ObjectId -All $true[array]$GroupMembers = $Members | ? {$_.ObjectType -eq 'Group'} | Select ObjectId, DisplayName, Mail, @{Name="Type"; e={$_.ObjectType}}[array]$UserMembers = $Members | ? {$_.ObjectType -ne 'Group'} | Select ObjectId, DisplayName, Mail, @{Name="Type"; e= {$_.UserType}}If($GroupMembers) {[array]$ExtractedMembers = $Members | Where-Object{$_.ObjectType -eq 'Group'} | ForEach-Object{ Get-RecursiveAzureAdGroupMemberUsers -AzureGroup $_}$UserMembers += $ExtractedMembers }# Figure out what mix of user (including mail contacts and other recipients) and group members we have[array]$ReturnMembers = $NullIf ($UserMembers) { $ReturnMembers = $UserMembers}If ($GroupMembers) { $ReturnMembers += $GroupMembers }# Remove duplicates if found in multiple (nested) DLs$ReturnMembers = $ReturnMembers | Sort ObjectId -UniqueReturn $ReturnMembers}# Check we have the right modules loaded$Modules = Get-ModuleIf ("ExchangeOnlineManagement" -notin $Modules.Name) {Write-Host "Please connect to Exchange Online Management before continuing...";break}If ("AzureADPreview" -notin $Modules.Name) {Write-Host "Please connect to Azure AD before continuing...";break}# Find all distribution listsWrite-Host "Finding Exchange Online Distribution Lists..."# Find distribution lists, excluding room lists$DLs = Get-DistributionGroup -ResultSize Unlimited -Filter {RecipientTypeDetails -ne "Roomlist"} | Select DisplayName, ExternalDirectoryObjectId, ManagedByIf (!($DLs)) { Write-Host "No distribution lists found... sorry! "; break }Else { Write-Host ("{0} distribution lists found" -f $DLs.count) }CLS; $DLNumber = 0$Report = [System.Collections.Generic.List[Object]]::new()$DLCSVOutput = "c:\temp\DLMemberCounts.CSV"ForEach ($DL in $DLs) {$DLNumber++$ProgressBar = "Processing distribution list " + $DL.DisplayName + " (" + $DLNumber + " of " + $DLs.Count + ")"Write-Progress -Activity "Analzying membership of distribution list " -Status $ProgressBar -PercentComplete ($DLNumber/$DLs.Count*100)[array]$Members = Get-AzureADGroup -ObjectId $DL.ExternalDirectoryObjectId | Get-RecursiveAzureAdGroupMemberUsers | Sort DisplayNameIf (!($Members)) { # For whatever reason, no members in this group, so we zeroize everything to prepare for the next group$CountOfMembers = 0[array]$TenantMembers = @()[array]$GroupMembers = @()[array]$GuestMembers = @()[array]$OtherMembers = @()$MemberNames = $Null }Else {[int]$CountOfMembers = $Members.Count[array]$TenantMembers = ( $Members | ? {$_.Type -eq "Member" })[array]$GroupMembers = ( $Members | ? {$_.Type -eq "Group" })[array]$GuestMembers = ( $Members | ? {$_.Type -eq "Guest" })[array]$OtherMembers = ( $Members | ? {$_.Type -eq $Null })$MemberNames = $Members.DisplayName -join ", " | Out-String}[string]$OutputNames = $MemberNames$ReportLine = [PSCustomObject][Ordered]@{DLName = $DL.DisplayNameManagedBy = $DL.ManagedBy -join ", ""Members" = $CountOfMembers"Tenant Users" = $TenantMembers.Count"Groups" = $GroupMembers.Count"Guest members" = $GuestMembers.Count"Other Recipients" = $OtherMembers.Count"Member names" = $OutputNames}$Report.Add($ReportLine)}Write-Host ("All done. {0} distribution lists analyzed. Output is in {1}" -f $DLs.Count, $DLCSVOutput)$Report | Out-GridView$Report | Export-CSV -NoTypeInformation $DLCSVOutput
Attribution
Author
Office365itpros