Microsoft 365 Device Management

Mastering Intune Assignment Filters and Ring Deployment: Targeting Logic, Precedence, and Safe Rollouts

Targeting is where most Intune estates quietly rot. The policies are fine, the settings are fine, but the assignment is a tangle of overlapping groups nobody dares touch, and “who actually got this profile” becomes a guessing game. Assignment filters fix the half of that problem that groups were never good at: slicing a population by live device properties at check-in, with no membership-evaluation lag. This guide builds the full targeting model – user vs device targeting, filter authoring, include/exclude semantics, ring construction, the precedence chain that decides conflicts, and how to validate the result instead of hoping.

1. Assignment fundamentals: user vs device targeting and virtual groups

Every Intune assignment targets one of three things: a user group, a device group, or one of the two virtual groupsAll Users and All Devices. Those two are not real Entra groups; they are Intune-side targeting shortcuts evaluated by the service. They are also the single biggest blast-radius lever you have, so treat them with respect.

The user-vs-device distinction is not cosmetic. It changes when a policy applies and what context it applies in:

Target Applies when Best for
User group At user sign-in / per-user check-in App availability, user-scoped config, anything that should follow a person
Device group At device check-in regardless of who signs in Security baselines, compliance, device-restriction profiles, shared/kiosk devices
All Users (virtual) Every licensed user in the tenant Broad user-targeted rollouts
All Devices (virtual) Every enrolled device Broad device-targeted rollouts (baselines, compliance)

The hard rule that bites teams: Intune does not evaluate user-to-device relationships across an assignment. If you target a profile to All Users and try to exclude an All Personal Devices device group, the exclusion is silently ignored and every user gets the profile. Mixing user and device groups in one assignment produces results you did not intend. Keep an assignment’s include and exclude legs the same type – user-with-user, device-with-device.

Assignment filters and dynamic groups solve different problems. Use dynamic groups when you need cross-workload targeting (Conditional Access, licensing, Autopilot profile assignment) or user-based grouping. Use assignment filters when you are scoping Intune apps and policies by device properties – OS, model, manufacturer, ownership, Entra join type. Filters evaluate at check-in with no group-membership processing, so targeting is not affected by group size or rule-evaluation timing. Most mature tenants run both.

2. Authoring assignment filters: device and app filter rule syntax and operators

A filter is a reusable, named rule object scoped to a single platform and one of two management types: managed devices (enrolled in Intune) or managed apps (MAM, app protection and app configuration policies on unenrolled devices). Create them under Tenant administration -> Assignment filters -> Create, pick the management type, pick the platform, then author the rule.

The rule grammar mirrors Entra dynamic-membership syntax: ([entity].[property] [operator] [value]). The entity is device for managed-device filters and app for managed-app filters. Everything is case-insensitive. Parentheses and nested parentheses are supported, and -and / -or join expressions.

A Windows device filter that isolates corporate-owned Surface laptops on Enterprise SKU:

(device.manufacturer -eq "Microsoft") and (device.model -startsWith "Surface") and (device.operatingSystemSKU -eq "Enterprise") and (device.deviceOwnership -eq "Corporate")

The supported operators:

Operator Allowed forms Use on
Equals / NotEquals -eq -ne all value types
StartsWith -startsWith strings
Contains / NotContains -contains -notContains strings
In / NotIn -in -notIn arrays, e.g. ["a","b"]
And / Or -and -or joining expressions

The most useful managed-device properties on Windows:

For OS version, there are two properties and they behave differently. The legacy osVersion is a string match (-eq, -startsWith, -contains). The newer operatingSystemVersion is a version type that unlocks numeric comparison operators – -gt, -ge, -lt, -le – which is what you actually want for “newer than this build”:

(device.operatingSystemVersion -ge 10.0.22631.3235)

osVersion is being deprecated in favor of operatingSystemVersion. When operatingSystemVersion reaches GA, you will no longer be able to create new filters using osVersion, though existing ones keep working. Write new build-gating rules against operatingSystemVersion today so you are not rewriting filters later. Note it is currently in public preview, and Preview Devices will refuse to enumerate preview properties – the rule still evaluates correctly at check-in.

Managed-app (MAM) filters use the app. entity and a smaller property set: app.appVersion, app.deviceManufacturer, app.deviceModel, app.operatingSystemVersion, app.osVersion. App filters only apply to app protection and app configuration policies – not to compliance or device configuration.

Two limits to design around: 200 assignment filters per tenant, and 3,072 characters per filter rule. If you are approaching either, your filter strategy is probably encoding data that belongs in a device attribute or category.

You can also manage filters as code via Microsoft Graph. The resource is deviceAndAppManagementAssignmentFilter under deviceManagement/assignmentFilters:

Connect-MgGraph -Scopes "DeviceManagementConfiguration.ReadWrite.All"

$body = @{
  displayName  = "Win-Corp-Surface-Enterprise"
  description  = "Corp Surface devices on Enterprise SKU"
  platform     = "windows10AndLater"
  assignmentFilterManagementType = "devices"
  rule = '(device.manufacturer -eq "Microsoft") and (device.model -startsWith "Surface") and (device.operatingSystemSKU -eq "Enterprise")'
} | ConvertTo-Json

Invoke-MgGraphRequest -Method POST `
  -Uri "https://graph.microsoft.com/beta/deviceManagement/assignmentFilters" `
  -Body $body -ContentType "application/json"

3. Applying filters in include vs exclude mode and evaluating the result

A filter does nothing until you attach it to an assignment. On the assignment, after you pick the target group, choose Edit filter and one of three modes:

The mental model: the group defines the candidate population; the filter is an AND condition applied to each candidate’s device at check-in. Include keeps matches, Exclude drops matches. A device that is not in the target group is never in scope regardless of what the filter says – the filter cannot add devices, only narrow.

This is why a single filter, written once, replaces a sprawl of bespoke groups. One (device.deviceOwnership -eq "Personal") filter, attached in Exclude mode to a corporate-only restriction profile that targets All Devices, does the work that would otherwise need a curated “all corporate devices” group kept in sync forever.

4. Building deployment rings with dynamic groups and filter-based slices

Rings exist to bound blast radius. A bad payload should land on a pilot cohort first, not the whole fleet. There are two ways to slice a ring, and the strongest designs combine them.

Dynamic groups give you a durable cohort that other workloads can also consume. A ring-0 pilot group keyed off a naming convention or extension attribute:

(device.deviceOSType -eq "Windows") and (device.displayName -startsWith "PILOT-")

Filters give you a property slice with no membership lag, applied at the assignment. The robust pattern is: target the broad dynamic group (or All Devices), then use a filter to carve the ring slice per assignment. Because enrollmentProfileName is a property you control at Autopilot enrollment, it is an excellent ring key – you can stamp ring membership at provisioning time and slice on it later:

(device.enrollmentProfileName -startsWith "Ring1-Pilot")

A workable four-ring model:

Ring Population Slice mechanism Purpose
Ring 0 - Preview IT + volunteers (~1%) Dynamic group PILOT-* Catch breakage on day zero
Ring 1 - Pilot Cross-section of BUs (~5-10%) Filter on enrollmentProfileName Validate on real workloads
Ring 2 - Broad Everyone else All Devices + exclude filter for rings 0/1/3 Bulk of fleet
Ring 3 - Critical Execs, clinical, lab/kiosk Dynamic group, longest leash Devices where an unplanned change is an incident

The discipline that keeps this clean: a payload is assigned to one ring at a time, and you promote by editing the assignment’s filter or group, not by re-authoring the policy. The policy is immutable; the targeting moves.

5. Conflict and precedence rules across profiles, baselines, and compliance

When two payloads touch the same setting on the same device, Intune does not merge them arbitrarily – there is a defined order. Get this wrong and you will chase “why is this device not getting my value” for days.

The precedence chain, highest authority first:

  1. Compliance policy settings beat configuration profile settings. If a setting is evaluated by a compliance policy and set by a configuration profile, compliance wins. This is deliberate – compliance is the security floor.
  2. Within configuration, if two configuration profiles set the same value differently, that is a conflict, and Intune surfaces it as a conflict state rather than silently picking one. You resolve it; the device often ends up with neither value applied for that setting until you do.
  3. Security baselines are configuration profiles for precedence purposes. A baseline and a settings-catalog profile that disagree produce a conflict the same way two ordinary profiles would. Layering a baseline on top of hand-authored profiles without auditing overlap is the most common source of mysterious conflict states.

The takeaway for design: do not set the same setting from two places. Pick one authority per setting – baseline or settings catalog, never both for the same control – and let compliance own the security gates. Conflicts are not resolved by precedence inside the configuration tier; they are flagged for a human.

6. Exclusion-group strategy and avoiding the empty-intersection trap

Exclusions are how you punch holes in broad assignments, and they have their own precedence rule that sits above filters:

Exclude always wins, then filters, then includes.

So on a single assignment, evaluation runs: is the device (or user) in an excluded group of the same type? If yes, it is out – full stop, no filter consulted. If not, apply the include filter, then the include group. That ordering is what makes “target All Devices, exclude the Critical-Ring device group, include a filter for Windows Enterprise” behave predictably.

Three traps to avoid:

The mixed-type empty-intersection trap. As covered in section 1, excluding a device group from a user-targeted assignment does nothing – the exclusion is ignored and everyone gets the payload. Always match the exclusion group type to the include target type.

The over-exclusion trap. Stacking exclusion groups across many assignments creates a population that is in scope nowhere. A device excluded from every ring’s broad assignment receives no baseline at all. Audit for devices that fall through all rings – they are an unmanaged gap, not a safe default.

The same-type exclusion you forgot is global. Excluding a group from an All Users or All Devices assignment is the cleanest pattern, but it is also tenant-wide. An over-broad exclusion group (one with an accidentally loose dynamic rule) silently removes thousands of endpoints from a security baseline. Review exclusion-group membership counts the same way you review include counts.

7. Reporting per-assignment status and validating who actually got the policy

Targeting is a hypothesis until you confirm delivery. Three layers of validation, cheapest first:

Preview Devices on the filter itself, at authoring time, enumerates which enrolled devices currently match the rule. This is your “did I write the rule correctly” check before the filter ever touches an assignment. (Preview properties like operatingSystemVersion will not enumerate here – that is expected, the rule still evaluates live.)

Per-policy device/user status in the admin center: open the policy -> Device status / User status for the success/error/conflict/not-applicable breakdown. Not applicable is the state to read carefully – it usually means the device was in the group but the filter excluded it, or platform did not match. That is your proof the filter narrowed scope as intended.

Per-device “check assignment” view: on an individual device, the per-device policy/app list shows exactly which assignments reached it and the resulting state – the fastest way to answer “why did this machine get / not get the policy.”

For fleet-wide validation, query Graph. Per-device assignment status lives under each policy’s deviceStatuses (and userStatuses) navigation. Example for a configuration profile:

Connect-MgGraph -Scopes "DeviceManagementConfiguration.Read.All"

$policyId = "<deviceConfiguration-id>"
$uri = "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations/$policyId/deviceStatuses"

(Invoke-MgGraphRequest -Method GET -Uri $uri).value |
  Select-Object deviceDisplayName, status, lastReportedDateTime |
  Sort-Object status

Read the status field for compliant / error / conflict / notApplicable, and pivot on notApplicable to confirm your filter exclusions landed on the devices you expected.

8. Staged-rollout patterns for low-risk progressive deployment

Putting it together, the safe-rollout loop for any new payload:

  1. Author once, assign narrow. Create the policy. First assignment: ring-0 pilot group only, no broad target. Validate device status is green.
  2. Promote by editing targeting, not policy. Add ring 1 by attaching the enrollmentProfileName -startsWith "Ring1-" filter to a broader assignment leg. The payload is unchanged; only its reach grows.
  3. Go broad with an exclusion safety net. For ring 2, target All Devices and exclude the critical-ring device group plus any device categories that must stay frozen. Exclude wins, so those devices are protected even though they are technically All Devices.
  4. Bake time between rings. A ring is only a ring if you wait. Watch the error/conflict counts climb or stay flat before promoting. A spike in conflict after a promotion almost always means the new population already had a baseline touching the same setting – pause and reconcile before going wider.
  5. Keep one frozen lane. Ring 3 stays on the longest leash deliberately. These devices still get the payload, just last and most cautiously.

This is release management, not configuration. The policy is the artifact; the rings and filters are the deployment pipeline.

Enterprise scenario

A healthcare platform team ran ~28,000 Windows endpoints across hospitals and back-office sites. They needed to ship a new device-restriction profile that disabled removable storage – mandatory for the clinical fleet under their data-handling controls, but it would brick the back-office teams who imaged machines from USB and the radiology techs whose modalities mounted as USB mass-storage.

Their first instinct was the usual one: build a “Clinical Devices” dynamic group and a “USB-Exempt Devices” group, target the profile to clinical, and curate the exempt group by hand. Within a sprint the exempt group was already stale – new radiology kit kept getting blocked because nobody had added it, and ticket volume spiked every imaging refresh.

The fix was to stop encoding the exemption in a hand-curated group and encode it in a property they already controlled. Every clinical device was provisioned through a dedicated Autopilot profile named Clinical-Standard; radiology and back-office imaging stations used Eng-Imaging. So they targeted the restriction profile to All Devices and attached a single exclude filter:

(device.enrollmentProfileName -startsWith "Eng-Imaging")

Now the exemption was self-maintaining: any device enrolled through the imaging profile was excluded at check-in, no group curation, no lag. They rolled it through rings – pilot clinical ward first (a PILOT-* dynamic group), then All Devices with the exclude filter for ring 2, with the radiology-modality OU as a frozen ring-3 group on a longer leash. Validation was the notApplicable count in Device status: it matched the imaging-station inventory exactly, which was the proof the exclusion was hitting the right machines and only those. Ticket volume on imaging refreshes dropped to zero because the targeting followed the enrollment profile, not a list someone had to remember to update.

Verify

Run these checks before declaring a rollout done:

# 1. Confirm the filter exists and inspect its rule + management type
Connect-MgGraph -Scopes "DeviceManagementConfiguration.Read.All"
(Invoke-MgGraphRequest -Method GET `
  -Uri "https://graph.microsoft.com/beta/deviceManagement/assignmentFilters").value |
  Select-Object displayName, platform, assignmentFilterManagementType, rule

# 2. Pull per-device status for the policy and pivot on the outcome
$policyId = "<deviceConfiguration-id>"
(Invoke-MgGraphRequest -Method GET `
  -Uri "https://graph.microsoft.com/beta/deviceManagement/deviceConfigurations/$policyId/deviceStatuses").value |
  Group-Object status | Select-Object Name, Count

Checklist

IntuneAssignment FiltersTargetingDeployment RingsEndpoint

Comments

Keep Reading