Automating Intune with PowerShell & Microsoft Graph
Intune's admin center is a front end for the Microsoft Graph API. Once you understand that, you can script anything you can click β bulk changes, custom compliance, and reporting that the portal can't produce.
The Intune admin center is just a Graph client
Every button in the Intune portal sends a web request behind the scenes. Graph is that request.
When you click βCreate policyβ, the portal quietly posts your settings to an address like β¦/deviceManagement/deviceConfigurations. PowerShell can send exactly the same request. So anything you can do by clicking 400 times, you can do once in a script.
Why the exam cares
The July 2026 blueprint added a whole skill area for automation, monitoring and reporting. The exam is no longer satisfied that you can configure Intune β it wants to know you can operate it at scale, and at scale means scripted.
The two PowerShell paths
| Feature | Microsoft Graph PowerShell SDK | Invoke-MgGraphRequest / REST |
|---|---|---|
| What it is | Purpose-built cmdlets (Get-MgDeviceManagementManagedDevice) | You call the API endpoint directly |
| Best for | Everyday tasks with a supported cmdlet | Beta endpoints or anything the SDK hasn't wrapped |
| Discoverability | Tab completion, Get-Help, typed objects | You must know the URL and payload shape |
| Install | Install-Module Microsoft.Graph | Ships inside the SDK β no extra module |
| Auth | Connect-MgGraph -Scopes ... | Reuses the same Connect-MgGraph session |
Both paths authenticate the same way. The SDK is a convenience layer over the REST call β it is not a different permission model.
A minimal, honest example
# 1. Connect with only the scopes you need (least privilege)
Connect-MgGraph -Scopes "DeviceManagementManagedDevices.Read.All"
# 2. Use a purpose-built cmdlet
Get-MgDeviceManagementManagedDevice -All |
Where-Object { $_.ComplianceState -ne 'compliant' } |
Select-Object DeviceName, UserPrincipalName, ComplianceState
# 3. Or call the endpoint directly when no cmdlet exists yet
Invoke-MgGraphRequest -Method GET `
-Uri "https://graph.microsoft.com/beta/deviceManagement/managedDevices?`$top=50"
Exam tip: consent and scopes are the usual trap
A very common exam framing is βthe script fails with Insufficient privilegesβ. The answer is almost never βmake them Global Administratorβ.
Work through it in this order:
- Was the right scope requested?
Connect-MgGraph -Scopesmust include the permission the call needs β a.Read.Allscope cannot create a policy. - Was admin consent granted? Application permissions, and many delegated ones, need an admin to consent once for the tenant.
- Does the signed-in admin hold an Intune RBAC role that allows it? Graph permission and Intune role are both evaluated. Passing one does not bypass the other.
Least privilege is the expected answer. Global Administrator is the distractor.
Delegated vs application permissions
| Delegated | Application | |
|---|---|---|
| Runs as | A signed-in user | The app itself, no user present |
| Typical use | An admin running a script interactively | Unattended automation, scheduled jobs, Azure Automation |
| Effective rights | Intersection of user rights and the granted scope | Exactly the granted app role |
| Exam signal | βan administrator runs the script" | "runs nightly with no user signed inβ |
If a question says scheduled, unattended, or service principal, it is pointing at application permissions.
Extending device compliance with PowerShell
Built-in compliance settings cover common ground β encryption, OS version, password rules. Custom compliance covers everything else.
Custom compliance is you teaching Intune a new thing to check.
You write a small script that answers a question about the device (βis our agent installed?β), and a JSON file that says what a good answer looks like. Intune runs the script, compares the answer to your rules, and marks the device compliant or not.
The two required pieces
| Piece | What it does | Gotcha |
|---|---|---|
| Discovery script (PowerShell) | Collects the facts and returns them as JSON | Must write JSON to stdout with -Compress; only one output object |
| JSON rules file | Declares expected value, operator, data type, and the user-facing message | SettingName must match the scriptβs key exactly, including case |
# Discovery script β returns one compressed JSON object
$agent = Get-Service -Name 'ContosoAgent' -ErrorAction SilentlyContinue
$result = @{
AgentInstalled = [bool]($null -ne $agent)
AgentVersion = if ($agent) { '4.2.1' } else { '0.0.0' }
}
return $result | ConvertTo-Json -Compress
Where custom compliance goes wrong in real life
Three failures account for most support tickets, and all three are examinable:
- Key name mismatch.
AgentInstalledin the script andagentInstalledin the JSON rules will never match. It is case-sensitive. - The script writes more than one thing. A stray
Write-Host, a warning, or a secondreturnbreaks JSON parsing, and the device reports an error rather than non-compliance. - Script runs in the wrong context. Custom compliance scripts run as SYSTEM by default, and in the 32-bit PowerShell host by default. A registry key under
HKCU, or a per-user install path, will not be visible because of the SYSTEM context. Separately, the 32-bit default means a read ofHKLM\Softwareis silently redirected toHKLM\Software\WOW6432Node, so a 64-bit application can appear to be missing. Both behaviours are opt-out settings: set Run this script using the logged on credentials to Yes for user context, and Run script in 64 bit PowerShell Host to Yes for the 64-bit host.
Compliance is not the same as configuration: compliance reports a state, it does not fix it. If the question wants the issue fixed automatically, the answer is a remediation script, not custom compliance.
Compliance, remediation or configuration?
This distinction is heavily tested, and the wording of the question is the tell.
| The question says⦠| The answer is | Because |
|---|---|---|
| βreport which devices lack Xβ | Custom compliance | Reports state; can drive Conditional Access |
| βdetect and automatically fix Xβ | Remediation (Scripts and remediations) | Detection + remediation script pair |
| βenforce this setting on the deviceβ | Configuration profile | Sets and maintains the setting |
| βblock access until itβs fixedβ | Compliance + Conditional Access | Compliance is the signal; CA is the enforcement |
An administrator needs a nightly unattended script that exports all non-compliant devices to a file share. Which permission type should the app registration use?
A custom compliance policy always returns an error rather than a compliant or non-compliant result, yet the discovery script works correctly when run manually. What is the most likely cause?