Advanced Dynamic Autopilot Group Queries for Production (Autopilot v1)
- Florian Salzmann
- Posted on 07 Sep, 2026
- 05 Mins read
- Microsoft Intune,Windows Autopilot
Table of Contents
Open Table of Contents
- Why the Single-Tag Rule Stops Being Enough
- Multiple Tags in a Dynamic Autopilot Group Query
- Narrow the Query with a Second Condition (AND)
- Match Prefix Families with
-startsWith - Exclusions and the Mistake Almost Everyone Makes
- Match Tag Patterns with
-match - Quick Reference
- Keep It Simple: Maintenance Is the Real Cost
- A Note on Autopilot v2
Why the Single-Tag Rule Stops Being Enough
I have written dozens of dynamic Autopilot group queries over the years, and almost every one starts the same way:
(device.devicePhysicalIds -any (_ -eq "[OrderID]:scloud"))
One group tag. One dynamic group. One Autopilot profile. That works well for a single site or a single customer. It breaks down fast once you manage more than a handful of locations, business units, or hardware batches. At that point you end up with dozens of near-identical groups. Or you start bending the single-tag rule into something it was never meant to do.
I ran into this exact problem while rolling out Autopilot for a client with twelve retail branches. A single tag per branch would have meant twelve dynamic groups and twelve profiles to keep in sync. That is when I started building a proper dynamic Autopilot group query instead of one rule per tag.
This post walks through the query patterns I actually use in production. First, I will show you how to match multiple tags. Then I will cover how to exclude tags correctly, since there is a real gotcha here. Finally, I will show you how to match whole families of tags by prefix. Everything below applies to Windows Autopilot v1, the classic deployment profile model built on Azure AD and Entra ID dynamic device groups. You set group tags at hash upload or at registration time. If you are rolling out Autopilot v2 (device preparation), jump to the note at the end. The grouping model works differently there.
Multiple Tags in a Dynamic Autopilot Group Query
The most common request I get is simple: put every device with any of these tags into one group. You can chain conditions with -or:
(device.devicePhysicalIds -any (_ -eq "[OrderID]:HQ")) -or
(device.devicePhysicalIds -any (_ -eq "[OrderID]:Branch01")) -or
(device.devicePhysicalIds -any (_ -eq "[OrderID]:Branch02"))
Or match against a list with -in. This is more compact:
(device.devicePhysicalIds -any (_ -in ["[OrderID]:HQ","[OrderID]:Branch01","[OrderID]:Branch02"]))
My tip: switch to the -in form once you pass two or three tags. It is shorter to write. More importantly, it is easier to scan and extend six months later, when someone asks you to add a fourth site.
Narrow the Query with a Second Condition (AND)
Sometimes a tag alone is not specific enough. You want devices with a given tag, but only if they also match a second signal, like a specific OS SKU or device category. Combine both with -and:
(device.devicePhysicalIds -any (_ -eq "[OrderID]:Kiosk")) -and
(device.deviceOSType -eq "Windows")
I reach for this pattern when a tag gets reused for more than one purpose. Then I need a second condition to tell devices apart. It is not a substitute for choosing a more specific tag in the first place. More on that below.
Match Prefix Families with -startsWith
If your naming convention already encodes a hierarchy in the tag, you rarely need to enumerate every value. Say every managed-service customer gets a tag like Cust-Contoso or Cust-Fabrikam. Match the whole family with -startsWith:
(device.devicePhysicalIds -any (_ -startsWith "[OrderID]:Cust-"))
I use this pattern for a “master” group. It applies a baseline profile or compliance policy to every managed customer at once. Each individual Cust-<Name> group still gets its own dynamic group and its own Autopilot profile.
Exclusions and the Mistake Almost Everyone Makes
Here is the one that catches almost everyone, myself included, the first time. The instinct is to exclude a tag with -any (_ -ne "…"):
(device.devicePhysicalIds -any (_ -eq "[OrderID]:HQ")) -and
(device.devicePhysicalIds -any (_ -ne "[OrderID]:Decommissioned")) ❌ almost always true
This looks correct, and it passes validation. It does not do what you expect, though. devicePhysicalIds is a multi-valued property. The clause -any (_ -ne "X") asks whether at least one value in the array is not X. That is true for almost every device. A device carries many physical IDs: serial number, hardware hash reference, ZTDID, and the order or group tag itself. So the -ne clause silently matches everyone, exclusion tag or not.
I only caught this myself after auditing an “exclusion” rule that turned out to exclude nothing. The correct way to exclude a value from a multi-valued property is -all with -ne, not -any:
(device.devicePhysicalIds -any (_ -eq "[OrderID]:HQ")) -and
(device.devicePhysicalIds -all (_ -ne "[OrderID]:Decommissioned")) ✅ correct
-all (_ -ne "X") means every value in the array is not X, so none of them is X. That is the actual exclusion you want. It is worth double-checking any exclusion rule you already run in production. A rule that “validates fine” in the portal is not the same as a rule that does what you meant.
My advice: if you find yourself excluding by tag at all, stop and ask a question first. Would a separate static group, like “decommissioned” or “do-not-deploy”, excluded at the assignment level, be simpler? It is usually easier to audit than baking the exclusion into the dynamic rule. Excluding dynamic groups from assignments has its own caveats. I cover those in Mastering Assignments in Intune.
Match Tag Patterns with -match
For naming conventions that are not simple prefixes, -match with a regular expression can help. Say your tags embed a region code in the middle, like EU-Retail-HQ versus US-Retail-HQ:
(device.devicePhysicalIds -any (_ -match "^\[OrderID\]:EU-.*-HQ$"))
Use this sparingly. Regex rules are powerful, but they are also the hardest pattern on this page to read at a glance. They are the easiest to get subtly wrong, too. The ^ and $ anchors matter: an unanchored pattern can match more than you intend. If a -startsWith or -in combination gets the job done, use that instead.
Quick Reference
| Scenario | Membership rule pattern | When to use it |
|---|---|---|
| Single tag | (device.devicePhysicalIds -any (_ -eq "[OrderID]:X")) | One site, one customer, one profile: the default case |
| Multiple tags (OR) | (device.devicePhysicalIds -any (_ -in ["[OrderID]:A","[OrderID]:B"])) | Several sites or tags sharing one Autopilot profile or policy |
| Narrow with a second signal (AND) | tag rule -and (device.deviceOSType -eq "Windows") | A tag is reused for more than one purpose and needs disambiguation |
| Prefix family | (device.devicePhysicalIds -any (_ -startsWith "[OrderID]:Cust-")) | A naming convention already encodes the grouping you need |
| Exclude a tag | tag rule -and (device.devicePhysicalIds -all (_ -ne "[OrderID]:X")) | Rare: prefer a static exclusion group over baking this into the rule |
| Pattern or region match | (device.devicePhysicalIds -any (_ -match "^\[OrderID\]:EU-.*-HQ$")) | Naming convention is not a simple prefix, and -startsWith/-in cannot express it |
Keep It Simple: Maintenance Is the Real Cost
Every clause you add to a dynamic membership rule is something a future admin has to understand first. That admin might be you, in eight months, with no memory of why the clause is there. They need to understand it before they can safely rename a tag, add a site, or debug why a device landed in the wrong group. A five-line rule with three -or branches and a -match regex is not hard to write once. It is hard to maintain forever.
A few habits pay for themselves over time:
- Document intent next to the group. Do not rely on a wiki nobody opens. A one-line description on the group itself, like “all EU retail HQ devices, tag prefix
EU-Retail-HQ”, saves the next person from reverse-engineering the regex. - Prefer several well-named, simple groups over one clever mega-rule. Dynamic group evaluation is fast enough at typical fleet sizes. So “more groups” rarely costs you anything real. Readability is worth more than cleverness here.
- Re-validate exclusion rules periodically, especially for the
-anyversus-allmistake above. It is easy to copy an old rule forward without checking whether it still does what it says.
A Note on Autopilot v2
Everything above is specific to Autopilot v1. A device’s group tag lives on devicePhysicalIds, and dynamic membership rules route devices to profiles. Autopilot v2 (device preparation) skips this model entirely. Instead, the device preparation policy groups devices at enrollment time, through its own account or group assignment during OOBE. No group tag exists for a dynamic rule to pattern-match afterward. If you are building a new v2 rollout, do not replicate these group-tag patterns. Use enrollment-time grouping as designed instead. The dynamic-rule patterns in this post apply to v1 only.


