Entra / Microsoft 365 · Groups
Find groups with no owners or members
Find and report Microsoft 365 groups, security groups, and distribution lists that have no owners or no members.
Connect & set up
Run these once per session. All scopes are read-only unless the script makes changes.
Connect-ExchangeOnline -SkipLoadingCmdletHelpConnect-MgGraph -NoWelcome -Scopes Group.Read.All
Run it
The main script. Copy it, or download the .ps1 and run it from your console.
$Modules = Get-Module | Select-Object -ExpandProperty NameIf ("ExchangeOnlineManagement" -notin $Modules) {Write-Host "Connecting to Exchange Online..."Connect-ExchangeOnline -SkipLoadingCmdletHelp}# Connect to the Microsoft GraphConnect-MgGraph -NoWelcome -Scopes Group.Read.All$NoOwnersCSVFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\GroupsWithNoOwners.CSV"# Find groups and expand owners. Only one property can be expanded at a time[array]$NoOwners = Get-MgGroup -All -PageSize 999 -ExpandProperty "owners(`$select=id)" `-Property Owners, Id, displayName, groupTypes, CreatedDateTime, mailEnabled, Mail, SecurityEnabled | `Select-Object Owners, Id, displayName, groupTypes, CreatedDateTime, mailEnabled, Mail, SecurityEnabled | `Where-Object {($_.Owners.count) -eq 0} | Sort-Object DisplayNameIf ($NoOwners.Count -eq 0) {Write-Host "No groups without owners found"} Else {Write-Host ("Found {0} ownerless groups" -f $NoOwners.Count)$NoOwnersReport = [System.Collections.Generic.List[Object]]::new()ForEach ($G in $NoOwners) {$DistributionList = $false# Check if the group is a distribution listIf ($G.GroupTypes.count -eq 0 -and $G.MailEnabled -eq $true) {$TestDL = Get-DistributionGroup -Identity $G.Id -ErrorAction SilentlyContinueIf ($TestDL) {$DistributionList = $true}}$ReportLine = [PSCustomObject][Ordered]@{ID = $G.IdDisplayName = $G.displayNameCreated = Get-Date($G.CreatedDateTime).ToLocalTime()groupTypes = ($G.groupTypes -join ", ")Mail = $G.MailmailEnabled = $G.mailEnabledSecurityEnabled = $G.SecurityEnabled'Distribution list' = $DistributionList}$NoOwnersReport.Add($ReportLine)}$NoOwnersReport | Export-Csv -Path $NoOwnersCSVFile -NoTypeInformation -Encoding utf8Write-Host ("Report for groups with no owners written to {0}" -f $NoOwnersCSVFile)}# Now check groups with no members...$NoMembersCSVFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\GroupsWithNoMembers.CSV"Write-Host "Checking for groups with no members..."[array]$NoMembers = Get-MgGroup -All -PageSize 999 -ExpandProperty "members(`$select=id)" `-Property Members, Id, displayName, groupTypes, CreatedDateTime, mailEnabled, Mail, SecurityEnabled | `Select-Object Members, Id, displayName, groupTypes, CreatedDateTime, mailEnabled, Mail, SecurityEnabled | `Where-Object {($_.Members.count) -eq 0} | Sort-Object DisplayNameIf ($NoMembers.Count -eq 0) {Write-Host "No groups without members found"} Else {Write-Host ("Found {0} memberless groups" -f $NoMembers.Count)$NoMembersReport = [System.Collections.Generic.List[Object]]::new()ForEach ($G in $NoMembers) {$DistributionList = $false# Check if the group is a distribution listIf ($G.GroupTypes.count -eq 0 -and $G.MailEnabled -eq $true) {$TestDL = Get-DistributionGroup -Identity $G.Id -ErrorAction SilentlyContinueIf ($TestDL) {$DistributionList = $true}}$ReportLine = [PSCustomObject][Ordered]@{ID = $G.IdDisplayName = $G.displayNameCreated = Get-Date($G.CreatedDateTime).ToLocalTime()groupTypes = ($G.groupTypes -join ", ")Mail = $G.MailmailEnabled = $G.mailEnabledSecurityEnabled = $G.SecurityEnabled'Distribution list' = $DistributionList}$NoMembersReport.Add($ReportLine)}$NoMembersReport | Export-Csv -Path $NoMembersCSVFile -NoTypeInformation -Encoding utf8Write-Host ("Report for groups with no members written to {0}" -f $NoMembersCSVFile)}
Attribution
Author
Office365itpros