Featured image of post Test Entra ID Dynamic Group Queries with PowerShell

Test Entra ID Dynamic Group Queries with PowerShell

This blog post includes a code sample to test and validate dynamic Entra ID group membership queries.

Dynamic groups in Entra ID are extremely powerful. That also means that updating a query of an existing group is not always an easy task. Making a mistake in an updated query could lead to really big problems. Especially when dynamic groups are used to assign licenses or control access to certain resources. Imagine making a mistake where suddenly all users lose their license because they’re not included in the group after the query has been changed.

Luckily, something like this never happened to me. And nor should it happen to you. That’s why I’m sharing a script sample to validate rules before you update a query or even create a group for that matter.

Rule Validation in Entra ID

The Entra ID portal already features a rule validation feature which is still in preview. This is great if you just need to check a handful of users. It even gives you detailed results on each of your expressions.

Rule Validation in Entra ID (Preview)

Rule Validation

The Microsoft.Graph.Beta.Groups PowerShell module includes a nice little Cmdlet to test dynamic group queries so you can create your own scripts and potentially check your queries against hundreds of users.

I use two external files for this script. The first one stores the dynamic query in an *.sql file. Technically, dynamic Entra ID groups use their own syntax but I’ve found that the SQL syntax is pretty close to it. That means we’ll also get linting in VS Code and syntax errors such as a missing parenthesis are quite easy to spot.

If you check the screenshot above, the original query was (user.userPrincipalName -match "nocaptech.ch") which also included a user called Admin NCT. This is the content of my DynamicUserGroupRule.sql file which gets imported on line 8:

1
(user.userPrincipalName -match "nocaptech.ch" -and user.userPrincipalName -notmatch "admin")

The DynamicUserGroupTestMembers.txt which is imported on line 10 just contains the IDs of a couple of Entra ID users.

Script Example

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
$localRepoPath = git rev-parse --show-toplevel
$localTestPath = "./.local"

Connect-MgGraph

Import-Module Microsoft.Graph.Beta.Groups

$membershipRule = Get-Content -Path "$localRepoPath/Scripts/EntraID/DynamicGroupResources/DynamicUserGroupRule.sql" | Out-String

$userIds = Get-Content -Path "$localTestPath/DynamicUserGroupTestMembers.txt"

$results = @()

foreach ($userId in $userIds) {

    $params = @{

        MemberId       = $userId
        MembershipRule = $membershipRule
    }

    $evaluation = Test-MgBetaGroupDynamicMembershipRule -BodyParameter $params

    $userProperties = Get-MgUser -UserId $userId -Property City, UserPrincipalName, DisplayName, JobTitle

    $userDetails = New-Object -TypeName psobject

    $userDetails | Add-Member -MemberType NoteProperty -Name UserId -Value $userId
    $userDetails | Add-Member -MemberType NoteProperty -Name UserPrincipalName -Value $userProperties.UserPrincipalName
    $userDetails | Add-Member -MemberType NoteProperty -Name DisplayName -Value $userProperties.DisplayName
    $userDetails | Add-Member -MemberType NoteProperty -Name JobTitle -Value $userProperties.JobTitle
    $userDetails | Add-Member -MemberType NoteProperty -Name Result -Value $evaluation.MembershipRuleEvaluationResult
    $userDetails | Add-Member -MemberType NoteProperty -Name City -Value $userProperties.City

    $results += $userDetails

}

$results | Format-Table -AutoSize

$date = Get-Date -Format "yyyy-MM-dd-HH-mm"

$results | Export-Csv -Path "$localTestPath/DynamicGroupEvaluationReport-$date.csv" -Delimiter ";" -Encoding utf8 -Force

As you can see, there’s not even a reference of any group ID. Therefore you can test dynamic group queries before you even create a group. Or you can test an updated query without the risk of touching a production group.

Result

Because of the updated query, Admin NCT should not be a member of the group any more. Let’s see if that’s the case…

Script Output

Looks good to me. Now I can update my production group with the new query in confidence.

Summary

The code sample uses a function so it can easily be adjusted and you could for example test multiple queries against different sets of user IDs by creating your own for-each loop. If you find this code sample useful, you can also grab it from my GitHub repo.

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
Hosted on GitHub Pages
Built with Hugo
Theme Stack designed by Jimmy