Fine-Tuning Groups for Phased Deployments in Intune
Can we improve upon our attempts to control the deployment of updates, new policies, and updated applications across our managed Intune devices once again?

You must either be living under a rock, or just using Windows Autopatch to manage the delivery of Windows updates, if you aren’t aware about using Dynamic Security groups for phased update delivery.
You might not realise that you could and should be using these same groups for the deployment of controlled changes across your device estate, in a test, pilot, pre-production, production type approach whether this is for Windows, macOS, or mobile devices.

Now we’re no stranger to using Dynamic Security groups in Entra to split our device estate in phased collections, having touched upon the subject a, few, times, already, but we may as well flog this horse for all it’s worth and see if we can improve upon our existing logic.
Broad Phasing
Previously we’ve used the device.deviceId attribute on computer objects in Entra, which is just a GUID/UUID, to group devices based on the start of this string whether its 0-9 or a-f.
As there are sixteen potential characters (I counted for you) this GUID can start with (a-f, 0-9), each one of these should in theory equal 6.25% of all devices. You can then use this to create some bulky looking dynamic groups to split your device estate into chunks.
Sample Groups
Using this calculation we can combine devices where their device.deviceId starts with differing characters to give us a set of groups that contain for example 6.25%, 18.75%, 31.25%, and 43.75% of all, in the below example, corporate owned, managed, Windows devices.
| Phase | Device Percentage | Rule |
|---|---|---|
| 1 | 6.25% | (device.deviceManagementAppId -ne null) and (device.deviceOwnership -eq "Company") and (device.deviceOSType -eq "Windows") and (device.deviceId -startsWith "0") |
| 2 | 18.75% | (device.deviceManagementAppId -ne null) and (device.deviceOwnership -eq "Company") and (device.deviceOSType -eq "Windows") and ((device.deviceId -startsWith "1") or (device.deviceId -startsWith "2") or (device.deviceId -startsWith "3")) |
| 3 | 31.25% | (device.deviceManagementAppId -ne null) and (device.deviceOwnership -eq "Company") and (device.deviceOSType -eq "Windows") and ((device.deviceId -startsWith "4") or (device.deviceId -startsWith "5") or (device.deviceId -startsWith "6") or (device.deviceId -startsWith "7") or (device.deviceId -startsWith "8")) |
| 4 | 43.75% | (device.deviceManagementAppId -ne null) and (device.deviceOwnership -eq "Company") and (device.deviceOSType -eq "Windows") and ((device.deviceId -startsWith "9") or (device.deviceId -startsWith "a") or (device.deviceId -startsWith "b") or (device.deviceId -startsWith "c") or (device.deviceId -startsWith "d") or (device.deviceId -startsWith "e") or (device.deviceId -startsWith "f")) |
Now these multiples of 6.25 phase groups might work for you, and you might want to use the smallest percentage as a pilot or test group…but ~6% of 10000 is 600 devices (quick maths) which isn’t that small a test or pilot.
Can we use a similar approach using Entra groups to create fine-tuned deployment groups?
Accurate Phased Groups
How about instead of the above 16 available characters to query in the start of the device.deviceId attribute, we extend that to the next character i.e., device.deviceId -startsWith "01" device.deviceId -startsWith "02", device.deviceId -startsWith "03" etc., which would give us a massive 256 options – each one corresponding to about 0.4% of devices.
So now instead of grouping devices in blocks of 6% we can group them in roughly 0.4% chunks. Yeah I think that might be granular enough 😅.
Calculating Group Membership
Now the concept is all well and good, and I’m OK enough with PowerShell to give it a go myself, but there are times when coffee and caffeine don’t cut it to get you the results you need, so we can lean on the new C-word in our lives nope Copilot.
So with a half decent prompt and some tweaks along the way:
This gave me something to start with, but the results of the rules were way too long, and didn’t allow me to actually save a group in Entra without it throwing a wobbly.
This just changed the logic and didn’t shorten the rule length, as the rule just used the regex equivalent of startsWith.
This produced something workable, but it still needed tweaking, and updating to use the correct syntax for the rules 🫠.
Testing the Function
Not sure Copilot like my sassy opener 🤐, but we got there in the end…a PowerShell function that will accept an array of values and kick out some basic Group rules.
function Get-PhasedDynamicGroups {
param (
[int[]]$percentages
)
# Validate total percentage
$total = ($Percentages | Measure-Object -Sum).Sum
if ($total -ne 100) {
throw "Total percentage must equal 100. Current total: $total"
}
$hexValues = 0..255
$groupSizes = $Percentages | ForEach-Object { [math]::Round($_ * 256 / 100) }
# Adjust rounding to ensure total is exactly 256
$diff = 256 - ($groupSizes | Measure-Object -Sum).Sum
if ($diff -ne 0) {
$groupSizes[0] += $diff
}
$startIndex = 0
$groupRules = @()
for ($i = 0; $i -lt $groupSizes.Count; $i++) {
$size = $groupSizes[$i]
$prefixes = $hexValues[$startIndex..($startIndex + $size - 1)] | ForEach-Object {
$_.ToString('x2')
}
$startIndex += $size
# Group prefixes by first hex digit
$grouped = $prefixes | Group-Object { $_.Substring(0, 1) }
$ruleParts = $grouped | ForEach-Object {
$firstChar = $_.Name
$secondChars = $_.Group | ForEach-Object { $_.Substring(1, 1) }
$uniqueSecondChars = $secondChars | Sort-Object -Unique
if ($uniqueSecondChars.Count -eq 16) {
# All hex digits present, use startsWith
"(device.deviceId -startsWith `"$firstChar`")"
}
else {
# Use regex match
$charClass = $uniqueSecondChars -join ''
"(device.deviceId -match `"^$firstChar[$charClass]`")"
}
}
$rule = $ruleParts -join ' or '
$groupRules += [PSCustomObject]@{
group = "$($i + 1)"
Rule = $rule
}
}
return $groupRules
}
You can try it yourself, throw an array of numbers that adds up to 100 at it and see what it kicks out.
$groups = @(1, 4, 10, 35, 50)
Get-PhasedDynamicGroups -percentages $groups
Using the function and the above example in a PowerShell console:

Great that’s half the battle, a list of rules for each of the five groups. But can we make it a little more user friendly?
Expanding the Script
Back to using my actual brain 🧠 and not Copilot 🧙♂️, we can take the function and lob it into a more complete script giving us some parameters and a way to be specific in our group use.
With the following as options when running the script to create Operating System and/or Ownership specific rules:
- operatingSystem: Options from
Windows,macOS,Android,iOS, andAll - ownership: Options from
Corporate,Personal, andBoth - groups: How many group rules you want to create from
2to10
We can go ahead and run the script to create some rules.
Example 1 - Five Groups of Corporate Windows Devices
./Get-PhasedGroupRules.ps1 -operatingSystem Windows -ownership Corporate -groups 5
Seeing it in action.
With generated group rules.
| Phase | Percentage | Rule |
|---|---|---|
| 1 | 1% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "Windows") and (device.deviceOwnership -eq "Company") and ((device.deviceId -match "^0[012]")) |
| 2 | 4% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "Windows") and (device.deviceOwnership -eq "Company") and ((device.deviceId -match "^0[3456789abc]")) |
| 3 | 15% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "Windows") and (device.deviceOwnership -eq "Company") and ((device.deviceId -match "^0[def]") or (device.deviceId -startsWith "1") or (device.deviceId -startsWith "2") or (device.deviceId -match "^3[012]")) |
| 4 | 30% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "Windows") and (device.deviceOwnership -eq "Company") and ((device.deviceId -match "^3[3456789abcdef]") or (device.deviceId -startsWith "4") or (device.deviceId -startsWith "5") or (device.deviceId -startsWith "6") or (device.deviceId -startsWith "7")) |
| 5 | 50% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "Windows") and (device.deviceOwnership -eq "Company") and ((device.deviceId -startsWith "8") or (device.deviceId -startsWith "9") or (device.deviceId -startsWith "a") or (device.deviceId -startsWith "b") or (device.deviceId -startsWith "c") or (device.deviceId -startsWith "d") or (device.deviceId -startsWith "e") or (device.deviceId -startsWith "f")) |
Example 2 - Four Groups of All macOS Devices
./Get-PhasedGroupRules.ps1 -operatingSystem macOS -ownership Both -groups 4
More demos.
Different group rules.
| Phase | Percentage | Rule |
|---|---|---|
| 1 | 5% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "macmdm") and ((device.deviceId -match "^0[0123456789abc]")) |
| 2 | 15% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "macmdm") and ((device.deviceId -match "^0[def]") or (device.deviceId -startsWith "1") or (device.deviceId -startsWith "2") or (device.deviceId -match "^3[012]") |
| 3 | 30% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "macmdm") and ((device.deviceId -match "^3[3456789abcdef]") or (device.deviceId -startsWith "4") or (device.deviceId -startsWith "5") or (device.deviceId -startsWith "6") or (device.deviceId -startsWith "7")) |
| 4 | 50% | (device.deviceManagementAppId -ne null) and (device.deviceOSType -eq "macmdm") and ((device.deviceId -startsWith "8") or (device.deviceId -startsWith "9") or (device.deviceId -startsWith "a") or (device.deviceId -startsWith "b") or (device.deviceId -startsWith "c") or (device.deviceId -startsWith "d") or (device.deviceId -startsWith "e") or (device.deviceId -startsWith "f")) |
Example 3 - Three Groups of Personal iOS/iPadOS Devices
./Get-PhasedGroupRules.ps1 -operatingSystem iOS -ownership Personal -groups 3
Once more with feeling.
More group rules.
| Phase | Percentage | Rule |
|---|---|---|
| 1 | 10% | (device.deviceManagementAppId -ne null) and ((device.deviceOSType -eq "iPhone") or (device.deviceOSType -eq "iPad")) and (device.deviceOwnership -eq "Personal") and ((device.deviceId -startsWith "0") or (device.deviceId -match "^1[012345678]")) |
| 2 | 30% | (device.deviceManagementAppId -ne null) and ((device.deviceOSType -eq "iPhone") or (device.deviceOSType -eq "iPad")) and (device.deviceOwnership -eq "Personal") and ((device.deviceId -match "^1[9abcdef]") or (device.deviceId -startsWith "2") or (device.deviceId -startsWith "3") or (device.deviceId -startsWith "4") or (device.deviceId -startsWith "5") or (device.deviceId -match "^6[012345]")) |
| 3 | 60% | (device.deviceManagementAppId -ne null) and ((device.deviceOSType -eq "iPhone") or (device.deviceOSType -eq "iPad")) and (device.deviceOwnership -eq "Personal") and ((device.deviceId -match "^6[6789abcdef]") or (device.deviceId -startsWith "7") or (device.deviceId -startsWith "8") or (device.deviceId -startsWith "9") or (device.deviceId -startsWith "a") or (device.deviceId -startsWith "b") or (device.deviceId -startsWith "c") or (device.deviceId -startsWith "d") or (device.deviceId -startsWith "e") or (device.deviceId -startsWith "f")) |
These rules can be used to create your granular phased dynamic device deployment groups in Entra to be used for Windows updates, macOS updates, new application deployments etc.

Summary
You really should be making the most of the tools you have available for managing devices in Intune, and leveraging Dynamic Groups in this way to ensure controlled deployments of updates or new policies or applications, using these very granular dynamic groups is a great place to start.
If you want to see examples of where these phased groups can be used, Peter Klapwijk has a post detailing exactly how they’ve been using them.