Public/Get-IOOwnerlessGroups.ps1
|
function Get-IOOwnerlessGroups { <# .SYNOPSIS Finds Microsoft 365 and Security groups with no owners. .EXAMPLE Get-IOOwnerlessGroups .EXAMPLE Get-IOOwnerlessGroups -GroupType M365 -ToCsv "ownerless-groups.csv" #> [CmdletBinding()] param( [ValidateSet('All', 'M365', 'Security', 'MailEnabled')] [string]$GroupType = 'All', [string]$ToCsv ) $cmdName = $MyInvocation.MyCommand.Name Write-IOLog "Scanning for groups without owners (Type: $GroupType)..." -Level Info -Component $cmdName $results = [System.Collections.Generic.List[PSCustomObject]]::new() # Build filter $filter = switch ($GroupType) { 'M365' { "`$filter=groupTypes/any(g:g eq 'Unified')&" } 'Security' { "`$filter=securityEnabled eq true and mailEnabled eq false&" } 'MailEnabled' { "`$filter=mailEnabled eq true&" } default { '' } } $groups = Invoke-IOGraphRequest -Uri "v1.0/groups?${filter}`$select=id,displayName,groupTypes,securityEnabled,mailEnabled,mail,createdDateTime,membershipRule" $total = ($groups | Measure-Object).Count $counter = 0 if ($total -eq 0) { Export-IOResult -Data @() -ToCsv $ToCsv -CommandName $cmdName return } try { foreach ($grp in $groups) { $counter++ if ($counter % 50 -eq 0) { Write-Progress -Activity 'Checking group owners' -Status "$counter / $total" -PercentComplete (($counter / $total) * 100) } try { $owners = Invoke-IOGraphRequest -Uri "v1.0/groups/$($grp.id)/owners?`$select=id" -NoPagination -SkipConnectionCheck } catch { $owners = @() } if (-not $owners -or $owners.Count -eq 0) { $type = if ($grp.groupTypes -contains 'Unified') { 'Microsoft365' } elseif ($grp.securityEnabled) { 'Security' } elseif ($grp.mailEnabled) { 'MailEnabled' } else { 'Other' } $isDynamic = if ($grp.membershipRule) { $true } else { $false } $created = if ($grp.createdDateTime) { [datetime]::Parse($grp.createdDateTime, [System.Globalization.CultureInfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::AssumeUniversal).ToString('yyyy-MM-dd') } else { 'Unknown' } $results.Add([PSCustomObject]@{ GroupName = $grp.displayName GroupId = $grp.id GroupType = $type Mail = $grp.mail IsDynamic = $isDynamic CreatedDate = $created OwnerCount = 0 }) } } } finally { Write-Progress -Activity 'Checking group owners' -Completed } $sorted = $results | Sort-Object GroupType, GroupName Export-IOResult -Data $sorted -ToCsv $ToCsv -CommandName $cmdName } |