msgraph-sdk-powershell
msgraph-sdk-powershell copied to clipboard
Unable to find a way to fetch cloud only groups with zero members in it. All examples or graph APIs that are available only provide output of 10-12 groups
Install the Microsoft.Graph PowerShell module
#Install-Module -Name Microsoft.Graph -Force -AllowClobber
Import the module
#Import-Module Microsoft.Graph
Connect to Microsoft Graph (You will be prompted to sign in)
Connect-MgGraph
Get all Microsoft 365 groups
$groups = Get-MgGroup -Filter "mailEnabled eq false and securityEnabled eq true " -Top 100
Iterate through each group and check for zero membersUnified
foreach ($group in $groups) {
$members = Get-MgGroupMember -GroupId $group.Id
if ($members.Count -eq 0) {
Write-Host "Group $($group.DisplayName) has zero members."
# You can perform additional actions here if needed
}
}
Disconnect from Microsoft Graph
Disconnect-MgGraph
Install the Microsoft.Graph PowerShell module if not already installed
Install-Module -Name Microsoft.Graph -Force -AllowClobber
Import the module
Import-Module Microsoft.Graph
Connect to Microsoft Graph (You will be prompted to sign in)
Connect-MgGraph
Variables
$pageSize
100 # Adjust as needed $token
$null
Fetch groups with paging
do {
$groups
Get-MgGroup -Top $pageSize -PageToken $token -Select "id,displayName"
foreach ($group in $groups) {
$members
Get-MgGroupMember -GroupId $group.Id
if ($members.Count -eq 0) {
Write-Host "Group $($group.DisplayName) has zero members."
You can perform additional actions here if needed
}
}
$token
$groups.PageToken } while ($token -ne $null)
Disconnect from Microsoft Graph
Disconnect-MgGraph
Describe the bug
A clear and concise description of what the bug is.
It doesn't give me the full list of groups where members are zero. Also, it doesn't have any option to filter cloud only groups.
To Reproduce Steps to reproduce the behavior: Run any of the above powershell. My tenant has 8k+ groups both on-prem synced & cloud.
Expected behavior
A clear and concise description of what you expected to happen.
Debug Output
Run the problematic command with
-Debugand paste the resulting debug stream below. ⚠ ATTENTION: Be sure to remove any sensitive information that may be in the logs.
Module Version
Please run
Get-Module Microsoft.Graph*after cmdlet execution and paste the output below. If a module cannot be installed or imported, please runGet-Module -ListAvailableand paste the output.
Environment Data
Please run
$PSVersionTableand paste the output below. If running the Docker container image, indicate the tag of the image used and the version of Docker engine.
Screenshots
If applicable, add screenshots to help explain your problem.
Additional context
Add any other context about the problem here.
I raised incident 2402090010003214 with support & they advised to create a github issue
Gidday,
I think I've managed to prepare what you're looking for:
#Get all groups. Filter on Id,DisplayName, and onPremisesSyncEnabled to return results faster
$AllGroups = Get-MgGroup -All -Property Id,DisplayName,onPremisesSyncEnabled
#Optional - filter to cloud groups
$Groups = $AllGroups | Where-Object {$null -eq $_.OnPremisesSyncEnabled}
#Optional - filter to on-prem groups
$Groups = $AllGroups | Where-Object {$null -ne $_.OnPremisesSyncEnabled}
ForEach ($Group in $Groups){
$Temp = $null
$Temp = Get-MgGroupMember -GroupId $Group.Id -Property Id #Only need the ID property to reflect an adequate count
if (($Temp.id).count -eq 0){
Write-Host "Group: $($Group.DisplayName) has no members"
}
}
I have encountered a few problems myself which might be worth having the devs looking into:
- The property onPremisesSyncEnabled doesn't seem to support ne null, when it says it does. This has necessitated requesting all groups, and then filtering on the pipeline: https://learn.microsoft.com/en-us/graph/api/resources/group?view=graph-rest-1.0#properties
So while the following works:
Get-MgGroup -All -Property Id,DisplayName,onPremisesSyncEnabled -filter "onPremisesSyncEnabled eq true"This does not:Get-MgGroup -All -Property Id,DisplayName,onPremisesSyncEnabled -filter "onPremisesSyncEnabled eq null" - CountVar doesn't seem to work for Get-MgGroupMember, which necessitates doing returning all the group members, and then doing a manual count to work around this (some blog posts already talking about it: https://rakhesh.com/azure/graph-and-group-membership-count/) and also https://learn.microsoft.com/en-us/graph/api/group-list-memberof?view=graph-rest-1.0&tabs=http#example-2-get-only-a-count-of-all-memberships
@BHoggs has suggested an improvement to reduce the number of lines, and filtering to cloud groups or on-premise groups on the API side by using the not() operator
Shorter script below:
#Optional - filter to cloud groups. Filter on Id,DisplayName, and onPremisesSyncEnabled to return results faster
$Groups = Get-MgGroup -All -Property Id,DisplayName,onPremisesSyncEnabled -filter "not(onPremisesSyncEnabled eq true)" -ConsistencyLevel eventual -CountVariable CountVar
#Optional - filter to on-prem groups. Filter on Id,DisplayName, and onPremisesSyncEnabled to return results faster
$Groups = Get-MgGroup -All -Property Id,DisplayName,onPremisesSyncEnabled -filter "onPremisesSyncEnabled eq true)"
ForEach ($Group in $Groups){
$Temp = $null
$Temp = Get-MgGroupMember -GroupId $Group.Id -Property Id #Only need the ID property to reflect an adequate count
if (($Temp.id).count -eq 0){
Write-Host "Group: $($Group.DisplayName) has no members"
}
}
As always, there are many ways to acheive this, you might also be able go the other way around and get all groups and group members first, then filter later on:
$Groups = Invoke-MgGraphRequest -Method GET -URI "https://graph.microsoft.com/v1.0/groups?`$select=id,displayName,onPremisesSyncEnabled&`$expand=members(`$select=id)"
ForEach ($Group in $Groups.value){
if (($null -ne $Group.OnPremisesSyncEnabled) -AND ($Group.Members.Id.count -eq 0)){
Write-Host "Group: $($Group.DisplayName) has no members"
}
}
The one above filters to on-premises groups only. If you want to use cloud groups only, you should change the -ne in if statement to -eq i.e. if (($null -eq $Group.OnPremisesSyncEnabled) -AND ($Group.Members.Id.count -eq 0)){
The most efficient way available is this:
$groups = Get-MgGroup -ExpandProperty "members($select=id)" -Property "id,displayName" -PageSize 999 -All | Select-Object Id, DisplayName, Members | Where-Object { $_.Members.Count -eq 0 }
now, this list could still contain false positives (due to a limitation of Expand process, if the first 20 members are soft-deleted, it will incorrectly show 0 members).
To get the actual count of members, you need to execute after:
$groups | ForEach-Object { [PSCustomObject]@{ Id = $_.Id; MembersCount = Get-MgGroupMemberCount -GroupId $_.Id -ConsistencyLevel "Eventual" } } | Where-Object MembersCount -eq 0