Managing devices and applications efficiently is crucial for any organization, and Microsoft Intune helps streamline this process. Reporting is a key part of this management, but sometimes the built-in reports in Intune might not meet all your needs. This is where the Graph API becomes valuable.

The Graph API allows you to access raw data from Microsoft services, including Intune. With it, you can create custom reports that provide more specific insights compared to the default reports in Intune. In this blog post, we’ll discuss what Graph API reports are, the benefits of using raw data, how to retrieve these reports, and how to build the Graph API body to specify which report and what information you want from that report.

Advantages of Accessing Raw Data

Accessing raw data from Intune reports using the Graph API offers many advantages. You can create custom reports that fit your specific needs and integrate this data with tools like Power BI and Excel for deeper insights. It also allows you to automate data extraction, perform detailed analysis, spot trends, and handle large data sets more efficiently. Overall, this leads to smarter decision-making, better resource management, and greater efficiency.

Understanding the Difference Between Standard- and Report Graph API Calls

When working with Microsoft Graph API, it’s important to understand the differences between normal API calls and report calls, as they serve different purposes and offer distinct advantages.

Standard Graph API Calls

Normal Graph API calls are used to retrieve specific pieces of information from Microsoft services. They are typically straightforward and used to fetch details about users, devices, applications, and other resources.

  1. Purpose:
    • Real-Time Data Retrieval: These calls are designed for quick, real-time data access. They fetch specific pieces of information as needed, without retrieving large data sets at once.
  2. Data Processing:
    • Client-Side Processing: The data retrieved through normal API calls is processed on the client side. Your application handles the aggregation, filtering, and analysis of this data.
  3. Performance:
    • Immediate Results: These calls provide immediate results, making them ideal for situations where you need up-to-date information quickly.

Graph API Report Calls

Graph API report calls are designed to generate comprehensive and aggregated data reports. These calls offload much of the data processing to Microsoft’s servers, offering significant advantages for handling large data sets.

  1. Purpose:
    • Comprehensive Data Aggregation: Report calls are used to compile large sets of data into a single report. They provide a complete snapshot of the data at once, rather than fetching it piece by piece.
  2. Data Processing:
    • Server-Side Processing: When you request a report, Microsoft’s servers handle the heavy lifting of data aggregation and processing. This reduces the computational burden on your local systems.
  3. Performance:
    • Asynchronous and Efficient: Report generation is handled asynchronously. You submit a request for a report, and Microsoft’s servers process it. You periodically check if the report is ready for download. This approach is efficient for handling large and complex data sets, as it offloads intensive processing tasks to the server.

Example Workflow:

  1. Submit a Report Request:
    • Specify the parameters for the report you need, such as the report name, desired columns, and format.
  2. Server-Side Processing:
    • Microsoft’s servers handle the data aggregation and processing tasks, compiling the report based on your specifications.
  3. Check Report Status:
    • Periodically check the status of the report to see if it is ready.
  4. Download the Report:
    • Once the report is ready, download it for further analysis and use.

By understanding these differences, you can better leverage the capabilities of Graph API to meet your reporting and data analysis needs efficiently. Normal API calls are great for real-time data retrieval, while report calls are ideal for obtaining comprehensive, aggregated data sets with minimal impact on your local resources.

Technical Overview on How to Retrieve Reports

Retrieving reports using the Graph API involves a few key steps to set up and execute your requests efficiently. Here’s a step-by-step guide to get you started:

Setting Up Your Environment

Before you can retrieve reports, you need to set up the necessary environment using PowerShell:

  • Install the Microsoft Graph PowerShell Module: Open PowerShell and run the following command to install the module:
Install-Module Microsoft.Graph -Scope CurrentUser
  • Authenticate with Microsoft Graph: Use the following command to sign in and authenticate
Connect-MgGraph -Scopes "DeviceManagementManagedDevices.Read.All"

Defining the Report Request

When making a report request, you’ll use several parameters to define what you need:

  • reportName: Specify the name of the report you want to generate. This is a mandatory parameter.
    • Here is the list of all the possible reports.
  • filter: (Optional) Use this to filter the data within the report.
  • select: (Optional) Specify which columns you want in the report.
  • format: By default, data is returned in CSV format. You can specify JSON if preferred.
  • localizationType: (Optional)
    • When creating reports with the Graph API, you have the option to control how localized values are handled using the localizationType parameter. This parameter helps you manage how language-specific data is presented in your reports. There are two main options you can choose from:
      • LocalizedValuesAsAdditionalColumn (Default)
        • This option is the default if you do not specify the localizationType parameter. When you use this setting, the report will include two columns for each piece of data that can be localized:
          • Enum Value Column: This column contains raw strings or numeric values that do not change based on the locale. These values are consistent regardless of the language settings.
          • Localized String Value Column: This column contains the human-readable string values that are locale-specific. The column name will have _loc appended to it.
  • ReplaceLocalizableValues
    • With this option, the original columns are replaced directly with the localized string values. There is no additional column; instead, the values in the original columns are localized based on the specified language settings.

Example of defining the report request body in PowerShell:

$body = @"
    "reportName": "Devices",
    "filter": "(OwnerType eq '1')",
    "localizationType": "LocalizedValuesAsAdditionalColumn",
    "format": "csv",
    "select": [

Submitting the Report Request

This step details how to submit a report request request using the Graph API with PowerShell. The function Get-Reports handles the process of sending the request, checking the status, and downloading the completed report. Here’s a detailed breakdown:

Define Parameters and Initiate the Export Job

The function Get-Reports starts by accepting a parameter $body, which contains the JSON request body with the report parameters.

function Get-Reports {
    param (
        [Parameter(Mandatory = $true)]

    # The URL to initiate the export job
    $reportsUrl = ""

    try {
        # Attempt to initiate the export job by sending a POST request
        $response = Invoke-MgGraphRequest -Uri $reportsUrl -Method POST -Body $body -ContentType "application/json"
    } catch {
        Write-Error "Failed to initiate report export job: $_"
  • Parameters: The function accepts a mandatory parameter $body, which is a string representing the JSON payload that defines the report request.
  • reportsUrl: This is the endpoint for initiating the export job. It’s specific to the beta version of the Graph API for Intune.
  • Invoke-MgGraphRequest: This command sends a POST request to the specified URL with the JSON payload in the body. The -ContentType parameter specifies that the content type is JSON.

If the POST request fails, the function catches the error, displays an error message, and exits.

Construct the URL to Check the Status of the Report

After successfully initiating the export job, the function constructs a URL to check the status of the report using the response ID from the initial request.

    # Construct the URL to check the status of the report
    $reportResponseUrl = "$reportsUrl/$($"
    $sleepDuration = 30  # Duration to wait before checking the status again
  • reportResponseUrl: This variable holds the URL to check the status of the report. It appends the unique report ID received from the response of the initial POST request.
  • sleepDuration: This defines how long the function waits before checking the report status again. In this case, it’s set to 30 seconds.

Check the Report Status in a Loop

The function enters a loop to periodically check the status of the report until it is completed.

    do {
        try {
            # Attempt to get the current status of the report by sending a GET request
            $report = Invoke-MgGraphRequest -Uri $reportResponseUrl -Method GET
        } catch {
            Write-Error "Failed to get report status: $_"
  • Invoke-MgGraphRequest: This sends a GET request to the reportResponseUrl to check the current status of the report.
  • Error Handling: If the GET request fails, the function catches the error, displays an error message, and exits.

Handle Report Completion and Download

If the report status is “completed,” the function proceeds to download the report. If not, it waits for the specified duration and checks again.

        if ($report.status -eq "completed") {
            # If the report is completed, proceed to download and extract it
            $currentDate = (Get-Date).ToString("ddMMyyyy")
            $localZipPath = ".\reports\$($report.reportName)-$"

            try {
                # Attempt to download the report as a zip file
                .\azcopy.exe copy $report.url $localZipPath
                # Attempt to extract the zip file to the destination folder
                Expand-Archive -Path $localZipPath -DestinationPath ".\reports\$($currentDate)\" -Force

                # Clean up by removing the downloaded zip file
                Remove-Item -Path $localZipPath -Force
                Write-Output "File downloaded successfully and saved to $localFilePath"
                return $report
            } catch {
                Write-Error "Failed to download or extract report: $_"
        } else {
            # If the report is not yet completed, wait for a while before checking again
            Write-Output "Waiting for completed report..."
            Start-Sleep -Seconds $sleepDuration

    } while ($report.status -ne "completed")  # Continue checking until the report is completed

Checking the Report Status

Since report generation is asynchronous, you need to periodically check if the report is ready. The function above handles this with a loop that continues checking the status until the report is completed.

Downloading the Report

Once the report is ready, the function downloads it and extracts it to the specified directory. It uses azcopy for downloading and Expand-Archive for extraction, ensuring that the report is saved and ready for use. You can download azcyopy Here place the azcopy.exe in your root folder of the script.

Calling Get-Reports Function

After you have connected to Graph api and loaded the Body and function you can call on that function to retrieve the report you specified in you body.

Get-Reports -body $body


Here are examples of our report API call outputs from our demo, available in both JSON and CSV formats.


"Device name","Managed by","Ownership","Compliance","OS","OS version","Last check-in","Primary user UPN","Device ID"
"CF-WIN11-04","Intune","Corporate","Compliant","Windows","10.0.22631.3593","2024-06-09 15:52:08.0000000","","d6a5d774-3ceb-4be5-a9b5-21022f63a852"
"CF-11593","Intune","Corporate","Compliant","Windows","10.0.22631.3737","2024-06-13 17:03:05.9184364","","7de08935-d727-456a-aad8-08ca76175d79"


"columns": ["Device name","Managed by","Ownership","Compliance","OS","OS version","Last check-in","Primary user UPN","Device ID"],
"values": [
{"DeviceName":"CF-WIN11-04","ManagedBy":"Intune","Ownership":"Corporate","CompliantState":"Compliant","OS":"Windows","OSVersion":"10.0.22631.3593","LastContact":"2024-06-09 15:52:08.0000000","UPN":"","DeviceId":"d6a5d774-3ceb-4be5-a9b5-21022f63a852"},
{"DeviceName":"CF-11593","ManagedBy":"Intune","Ownership":"Corporate","CompliantState":"Compliant","OS":"Windows","OSVersion":"10.0.22631.3737","LastContact":"2024-06-13 17:03:05.9184364","UPN":"","DeviceId":"7de08935-d727-456a-aad8-08ca76175d79"}


Using the Graph API for Intune reports offers several advantages over standard reports. It allows you to create customized reports that meet your specific needs, specifying exactly what data to include and how to filter it. This level of customization isn’t possible with standard reports.

Graph API report calls also process large data sets more efficiently by offloading the heavy lifting to Microsoft’s servers. This reduces the burden on your local systems and allows you to focus on analyzing the data rather than preparing it.

Another benefit is the ability to integrate raw data with tools like Power BI and Excel. This makes it easier to perform advanced analyses and create detailed visualizations, which can lead to better insights and decisions.

Overall, the Graph API provides greater flexibility, efficiency, and integration capabilities, helping you get the most out of your Intune data.

For the full script and further details, check out my GitHub repository.

Feel free to explore and experiment with different report parameters. Happy reporting!
If you have any questions I’m here to help 😉


Leave a Reply

Your email address will not be published. Required fields are marked *