Public/Test-EGIDynamicGroupRule.ps1
|
function Test-EGIDynamicGroupRule { <# .SYNOPSIS Simulates a dynamic group membership rule against many users at once. .DESCRIPTION Microsoft Entra's own "Validate rules" tab only checks up to 20 users/devices per run. This function evaluates a rule against an arbitrary number of user objects (e.g. your whole tenant) locally, so you can answer "who would join or leave this group if I change the rule this way" before saving anything. Supports the common comparison operators and a best-effort '-any(...)' handling. Does NOT support: direct-reports rules, the memberOf (preview) operator, or employeeHireDate date-math against system.now - such leaves raise a clear error instead of a silently wrong result. .PARAMETER Rule The raw dynamic membership rule string to test. .PARAMETER Users An array of user objects ([pscustomobject] or hashtable). Property names must match the Graph attribute names used in the rule (department, jobTitle, otherMails, employeeId, ...), case-insensitive. Typically produced with: Get-MgUser -All -Property Id,DisplayName,Department,JobTitle,UserType,Country .PARAMETER PassThru Return the original user objects that match the rule (with all their properties), instead of the full pass/fail table. .EXAMPLE $users = Get-MgUser -All -Property Id,DisplayName,Department,Country Test-EGIDynamicGroupRule -Rule '(user.department -eq "Sales") -and (user.country -eq "DE")' -Users $users #> [CmdletBinding()] param( [Parameter(Mandatory)] [string] $Rule, [Parameter(Mandatory)] [object[]] $Users, [switch] $PassThru ) $tree = ConvertFrom-EGIRuleString -Rule $Rule $results = [System.Collections.Generic.List[pscustomobject]]::new() $matched = [System.Collections.Generic.List[object]]::new() $errorCount = 0 foreach ($user in $Users) { $id = Get-EGIUserProperty -Obj $user -Name 'Id' $displayName = Get-EGIUserProperty -Obj $user -Name 'DisplayName' try { $match = if (Test-EGIRuleTreeNode -Node $tree -User $user) { $true } else { $false } if ($match) { $matched.Add($user) } $results.Add([pscustomobject]@{ Id = $id DisplayName = $displayName Matches = $match Error = $null }) } catch { $errorCount++ $results.Add([pscustomobject]@{ Id = $id DisplayName = $displayName Matches = $null Error = $_.Exception.Message }) } } if ($errorCount -gt 0) { Write-Warning "$errorCount of $($Users.Count) user(s) could not be evaluated - see the Error column (unsupported rule constructs)." } if ($PassThru) { return $matched.ToArray() } return $results } |