reporting
5 TopicsFrom hours to minutes: Rethinking Microsoft Intune compliance reporting with the Export API
By: Daniel Gerrity – Principal Product Manager | Microsoft Intune If you manage a large device fleet with Microsoft Intune, you’ve almost certainly needed to get reporting data out of the service at scale — compliance state, device inventory, app status, endpoint analytics, or one of the many other reports admins rely on for operations and audit evidence. Intune supports this pattern through the export API, which generates supported reports as asynchronous export jobs instead of requiring you to retrieve the same data through thousands of operational Graph calls. You can see the full list of reports available through the export API in Intune reports and properties available using Graph API documentation. In the illustrative scenario below, moving one nightly job from operational Graph reporting endpoints to the Intune export API (exportJobs) cuts the work from roughly 100,000 API calls to about 15 while producing the same report data. The runtime drops from ~2.5 hours to ~15 minutes. Here’s how, and why the pattern holds up as your fleet grows. Note on the numbers The figures below are a representative example for a hypothetical 50,000-device enterprise, “Contoso,” and are rounded for clarity. Your results may vary based on fleet size, policy count, and how many compliance settings you evaluate. The scenario Contoso runs a nightly job that answers a deceptively simple question: For each device, across every compliance policy assigned to it, what is the state of each individual setting? This is a classic per-device, per-compliance-policy, per-setting state export. It’s the raw material behind compliance dashboards, audit evidence, remediation targeting, and “why is this device noncompliant” investigations. In Intune’s reporting catalog, this is the DeviceStatusSummaryByCompliancePolicySettingsReportV3 report. Contoso has ~50,000 managed devices, and the job runs once a day. The old way: Operational Graph APIs The intuitive approach treats compliance data as something you fetch, per device, right now. The script: Enumerates the fleet (managedDevices). Loops over every device, and for each one calls the operational reporting or setting-state endpoints (such as managedDevices detail and settingStates) to pull that device’s per-policy, per-setting results. Pages through the results in small JSON pages (often 50 rows at a time), reassembling everything client-side. It works. It just doesn’t scale because the number of calls is a function of the number of devices. At roughly two operational calls per device, 50,000 devices is on the order of ~100,000 Graph calls per run. That volume brings its own tax: Throttling. You hit service protection limits and have to implement retry/back-off logic. Threading. To finish inside the window at all, you parallelize which means concurrency bugs, partial failures, and harder debugging. Fragility. A run that makes 100,000 calls has 100,000 chances to fail, and a mid-run failure often means starting over. Time. End=to-end, the job lands around ~2.5 hours. Every time Contoso onboards more devices, this job gets slower and more expensive - the worst possible scaling direction for something that runs every night. The new way: Export API (exportJobs) The export API flips the model. Instead of asking Graph to compute results device-by-device in real time, you ask Intune to generate the entire report once, server-side, and hand you back a single file. The flow is a short, asynchronous handshake: 1. POST /deviceManagement/reports/exportJobs { "reportName": "DeviceStatusSummaryByCompliancePolicySettingsReportV3", "format": "csv", ...optional filter/select... } → returns a jobId, status: "notStarted" 2. GET /deviceManagement/reports/exportJobs('{jobId}') → poll until status: "completed" (a handful of polls while it builds) → response includes a short-lived download URL 3. GET {download URL} → one zipped CSV containing every device × policy × setting row That’s the whole pattern: request → poll → download → unzip → load. One report, one file, the entire fleet inside it. Count the calls: one POST to start the job, a handful of GET polls while Intune builds the file, and one GET to download it - call it ~15 calls total. Not ~15 per device. ~15 for the whole 50,000-device run. And that number barely moves whether Contoso has 50,000 devices or 150,000. Runtime drops to about ~15 minutes, most of which is simply waiting for the export to finish - cheap poll calls, not active compute. Most importantly, the output schema is identical. The CSV columns match what the old per-device loop assembled, so nothing downstream; dashboards, warehouse tables, alerting, has to change. You swap the acquisition layer and leave everything else alone. Side by side Comparison Operational Graph APIs Recommended Export API ( exportJobs ) Pattern Per-device loop plus paging Async export → download one file API calls per run ~100,000 ~15 Calls scale with Number of devices Nothing. The handshake remains fixed. Runtime ~2.5 hours ~15 minutes Concurrency Threading required None needed Output schema — Unchanged and drop-in compatible Net result — ~6,000× fewer API calls ~10× faster runtime Why it scales: Roundtrips, not bytes Here’s the subtlety worth internalizing, because it’s easy to get wrong. There are two different costs in this job, and they scale on different axes: The number of API calls - round-trips across the wire. The volume of data - the actual compliance rows you move. The data volume is the same either way. 50,000 devices × N settings is 50,000 × N rows, whether you assemble them from 100,000 little paged responses or receive them in one CSV. The export doesn’t move less data - it moves the same data. And yes, that file grows with both device count and setting count. More devices, bigger file; more settings, bigger file. So the win isn’t fewer bytes. The win is fewer round-trips. Every one of those 100,000 operational calls relies on authentication, TLS setup, network latency, and service-protection (throttling) accounting regardless of how much data it returns. Multiply that fixed overhead by 100,000 and it dominates everything. The export only pays that tax twice: once to start the job, once to download the file. Intune does the assembly server-side and streams you the result in a single bulk transfer. That reframes the scaling story: Call count is essentially constant - it doesn’t grow with devices or settings. It’s one job and one download. Data volume grows with devices and settings but a bigger CSV is a bigger single download, not more calls. Bulk transfer is exactly what HTTP is good at. Runtime has a mild data dependency: a larger fleet takes Intune a little longer to build the file. But you absorb that as a few extra seconds of poll-waiting, not as thousands of extra calls you have to orchestrate, retry, and throttle-manage. What the IT admin actually gets Beyond the raw speed, here’s the value that shows up in day-to-day operations: Your maintenance window comes back. A 15-minute job leaves room for everything else. Fewer moving parts to maintain. No custom throttling handler, no thread pool, no resumability logic. Less code is less to break at 2 a.m. Reliability by design. Two roundtrips means two failure points, and the server does the heavy lifting of assembling a consistent snapshot. Lower cost and lower service impact. Eliminating ~100,000 calls is easier on your tenant’s throttling limits and a better citizen for the Intune service overall. Room to grow. Because call count is decoupled from device count, doubling the fleet doesn’t double the job, you just download a somewhat larger file. No downstream disruption. Same schema for the output means the migration is contained to the ingestion step which is a low-risk swap, not a re-platforming. When to use which The export API isn’t a universal replacement, it’s best used for bulk, point-in-time snapshots: Reach for exportJobs when you need the whole fleet’s state (or a large, filtered slice) on a schedule such as nightly compliance loads, audit exports, warehouse hydration. Stick with the operational endpoints when you need a single device right now, an interactive “check this one device” lookup, or a real-time remediation trigger where waiting on an async job doesn’t make sense. The two are complementary. The mistake isn’t using the operational APIs, it’s using them in a loop to reconstruct something the export API will hand you in one file. The takeaway The per-device loop feels natural because it mirrors how we think about devices, one at a time. But at fleet scale, the question isn’t “what’s the state of this device?” a hundred thousand times over. It’s “give me the state of everything,” once. The export API is built for exactly that question, and answering it the right way turned a multi-hour nightly grind into a coffee break - from ~100,000 calls to about 15, ~10× faster, with zero downstream changes. If you have any questions, leave a comment below or reach out to us on X: @IntuneSuppTeam!83Views0likes0CommentsCreate historical reports using Azure Log Analytics and Microsoft Intune diagnostic data
By: Janusz Gal – Sr Product Manager | Microsoft Intune Azure Log Analytics gives Intune admins a flexible way to create custom reports from diagnostic data, especially when you need longer history or tailored calculations that go beyond what the Microsoft Intune admin center’s built-in reports provide. By using the Intune diagnostic data you’re already collecting, you can customize reporting for your organization’s unique requirements. In this post, you’ll walk through the steps to create a 30-day device compliance trend report. The resultant report can be run automatically, used in dashboards, or even further customized for a longer period or with additional data. Before we begin, if you haven’t configured a Log Analytics workspace in your tenant, review the following detailed information on the pre-requisites and costs on Microsoft Learn: Route logs to Azure Monitor using Microsoft Intune. In the Microsoft Intune admin center, navigate to Reports > Diagnostic settings, and add a new Diagnostic setting policy to send data to a Log Analytics workspace. Figure 1 Reports > Diagnostic settings, used to configure new or existing diagnostic settings. For a device compliance trend report, ensure the Devices log category is selected: Figure 2 Reports > Diagnostic settings > Selected configuration; Devices log selected. After configuring the setting, navigate to Reports > under Azure monitor, Log Analytics. Figure 3 Reports > Log Analytics; used to query log Analytics workspaces. In the New Query window, enter the following query: IntuneDevices | where TimeGenerated > ago(30d) | summarize Total = count(), Compliant = countif(CompliantState == "Compliant"), NonCompliant = countif(CompliantState == "Noncompliant"), InGracePeriod = countif(CompliantState == "InGracePeriod"), NotEvaluated = countif(CompliantState == "Not Evaluated" or CompliantState == ""), ConfigManager = countif(CompliantState == "ConfigManager") by bin(TimeGenerated, 1d) | extend ComplianceRate = round(100.0 * Compliant / Total, 2) | order by TimeGenerated asc This query will return daily device compliance trends over the past 30 days, from the IntuneDevice table. Figure 4 Reports > Log Analytics; results after running query. Select Chart > Chart type > Stacked Area to show a visual of the trending device state over time. Figure 5 Reports > Log Analytics > Chart > Stacked Area. If you’d like to create other reports but aren’t sure of the schema, one trick you can use is to run the following query in the above Log Analytics workspace to get all the column names: IntuneDevices | getschema Then to get all the values from those columns, you can modify the query to return the distinct values from a specific column such as CompliantState: IntuneDevices | distinct CompliantState Now that you have the query created in Log Analytics, you can save it to run anytime, pin it to a dashboard, or even create a new alert rule to let you know if compliance has gone below a certain threshold. To pin it as a dashboard, on the Query pane select the ellipsis (…) > Pin to > Azure dashboard. Figure 6 Reports > Log Analytics; pin query to dashboard flow. Then select the dashboard you’d like to use. Figure 7 Reports > Log Analytics; select dashboard to pin. Once pinned, simply navigate to Dashboard within the Intune admin center, and you’ll see the query pinned on the selected dashboard. Figure 8 Dashboard showing Log Analytics query. To show more than the past 24-hours, select the Customize Tile button and select Override the dashboard time settings at the tile level, with Timespan set to Past 30 days. Figure 9 Dashboard > Selected Query > Customize Tile button. If you’d like to always see the data in a chart form, select the edit icon on the pinned dashboard item and append the following to the end of the query: | render areachart with (kind=stacked) Figure 10 Dashboard > Selected query > Edit > modified query to show chart. After clicking Apply, the dashboard shows the following: Figure 11 Dashboard showing updated historical device compliance query as a stacked area chart. You’ve now seen end-to-end how to turn Intune diagnostic data into a 30-day device compliance trend report with diagnostic data and Log Analytics. From here, the next step is to operationalize it - save the query, extend the timeframe, join in additional diagnostic tables, or set an alert so you’re notified when compliance drops below your threshold. Better yet, see if you can pick one reporting gap your team is living with today and build it using this pattern. With the right tooling, Intune data can be shaped into views and insights that reflect your organization’s unique needs. Let us know if you have any questions by leaving a comment below or reach out on X @IntuneSuppTeam!2.6KViews0likes0Comments