Public/Get-ADPeerGroupStatistics.ps1
|
function Get-ADPeerGroupStatistics { <# .SYNOPSIS Finds active directory peers of a user (matching Department and Title) and outputs common group memberships with statistics. .DESCRIPTION Analyzes the target user along with their peers in the specified OU tree. Aggregates group memberships, filters out specified exclusion patterns, applies a minimum threshold percentage, and outputs structured objects sorted by match percentage. .PARAMETER Identity The target AD user object (accepts pipeline input). Must contain or evaluate Department, Title, and SamAccountName properties. .PARAMETER ExcludeGroup An array of group names or wildcard patterns to ignore (e.g., "*VPN*", "Domain Users"). .EXAMPLE Get-ADUser "jdoe" -Properties Department, Title | Get-ADPeerGroupStatistics .EXAMPLE Get-ADPeerGroupStatistics -Identity $NewHire -ExcludeGroup "*Temp*", "Domain Users" #> [CmdletBinding()] param( [Parameter(Mandatory = $true)] [string]$Identity, [Parameter(Mandatory = $false)] [string[]]$ExcludeGroup = @( "Domain Users", "VPN_Users", "VMWare Notifications" # Add any default exclusions here ), [Parameter(Mandatory = $false)] [int]$MinimumPeers = 3, [Parameter(Mandatory = $false)] [ValidateRange(0,100)] [int]$MinimumPercentage = 75 ) # Ensure Active Directory module is available if (-not (Get-Module -ListAvailable -Name ActiveDirectory)) { Write-Error "The ActiveDirectory PowerShell module is required but not installed." return } # 1. Get the target user and their attributes Write-Host "Fetching details for target user: $Identity..." -ForegroundColor Cyan $targetUser = Get-ADUser -Identity $Identity -Properties Department, Title if (-not $targetUser) { Write-Error "User '$Identity' not found in Active Directory." return } $department = $targetUser.Department $title = $targetUser.Title if (-not $department -or -not $title) { Write-Warning "Target user is missing a Department or Title attribute. Results may be empty." Write-Host "Department: '$department' | Title: '$title'" -ForegroundColor Yellow } # 2. Find all peers within the target OU and sub-OUs Write-Host "Finding peers in OU and sub-OUs with Department: '$department' and Title: '$title'..." -ForegroundColor Cyan $targetOU = "OU=Accounts,DC=tcu,DC=ad,DC=local" $filter = "Department -eq '$department' -and Title -eq '$title' -and sAMAccountName -ne '$($targetUser.sAMAccountName)'" $peers = Get-ADUser -Filter $filter -SearchBase $targetOU -SearchScope Subtree -Properties MemberOf | Where-Object { $_.Enabled -eq $true } if ($peers.count -lt $MinimumPeers) { $peersCount = $peers.Count $filter = "Title -eq '$title' -and sAMAccountName -ne '$($targetUser.sAMAccountName)'" $peers = Get-ADUser -Filter $filter -SearchBase $targetOU -SearchScope Subtree -Properties MemberOf | Where-Object { $_.Enabled -eq $true } Write-Host "Only $peersCount peer(s) found matching Department '$department' and Title '$title'." -ForegroundColor Yellow Write-Host "Minimum peer threshold is $MinimumPeers. Falling back to Title-only matching..." -ForegroundColor Yellow } $totalPeers = @($peers).Count if ($totalPeers -eq 0) { Write-Host "No active peers found sharing the exact Department and Title in the specified OU or its sub-OUs." -ForegroundColor Yellow return } Write-Host "Found $totalPeers active peer(s). Analyzing group memberships..." -ForegroundColor Green # 3. Aggregate group memberships across all peers` $groupCounter = @{} foreach ($peer in $peers) { foreach ($groupDN in $peer.MemberOf) { if ($groupCounter.ContainsKey($groupDN)) { $groupCounter[$groupDN]++ } else { $groupCounter[$groupDN] = 1 } } } # 4. Process results, fetch the full AD group object, and filter out excluded groups $results = foreach ($groupDN in $groupCounter.Keys) { $count = $groupCounter[$groupDN] $percentage = [Math]::Round(($count / $totalPeers) * 100, 2) $groupObj = Get-ADGroup -Identity $groupDN -Properties Description, DisplayName, GroupScope, GroupCategory -ErrorAction SilentlyContinue if ($groupObj) { # Check if the group name matches any item in the exclusion list $isExcluded = $false foreach ($pattern in $ExcludeGroup) { if ($groupObj.Name -like $pattern) { $isExcluded = $true break } } # Only process/output the group if it's NOT excluded if (-not $isExcluded) { $groupObj | Add-Member -NotePropertyName "PeerMatchPercentage" -NotePropertyValue $percentage -Force $groupObj | Add-Member -NotePropertyName "PeerCountWithGroup" -NotePropertyValue $count -Force $groupObj | Add-Member -NotePropertyName "TotalPeersAnalyzed" -NotePropertyValue $totalPeers -Force $groupObj } } } # 5. Return sorted results cleanly down the pipeline Write-Host "Analysis complete. Outputting filtered AD group objects..." -ForegroundColor Green $results | Where-Object {$_.PeerMatchPercentage -ge $MinimumPercentage} | Sort-Object PeerMatchPercentage -Descending } |