Parsing Intune Remediation JSON Output

Recently we've been discussing Secure Boot Certificate updates a lot. There have been many new tools to help us as administrators report on the status of those updates across our fleets and one of the popular tools has been a remediation script released by Microsoft found here:

Monitoring Secure Boot certificate status with Microsoft Intune remediations
https://support.microsoft.com/en-us/topic/monitoring-secure-boot-certificate-status-with-microsoft-intune-remediations-6696a27b-fa09-4570-b112-124965adc87f

This script runs on a client, checks Secure Boot status and registry keys associated with the update, then outputs to JSON that is then semi-readable in the Intune Admin Center. Why do I say semi-readable? The JSON is pretty much a single string, as seen below:

The best tool for me to make this a bit more readable is PowerShell.

Option 1: Export CSV

The first option is to export the device status results from the Intune Admin Center, which will download a ZIP file that contains a CSV named DeviceRunStatesByProactiveRemediation_$GUID.csv. We can extract that CSV from the ZIP file, import it into PowerShell, and convert the JSON-formatted data (stored in PreRemediationDetectionScriptOutput) into a PSCustomObject.

$remediationExport = Import-CSV "C:\temp\DeviceRunStatesByProactiveRemediation_965562bc-4539-46b6-b32e-3199e3c5a609.csv"
$remediationExport.PreRemediationDetectionScriptOutput | ConvertFrom-Json | Select-Object -Property Hostname,UEFICA2023Status,SecureBootEnabled,CollectionTime

This only takes a couple of PowerShell commands and it works as we can see above, but it requires a lot of clicks to get to the information.

Option 2: Use Microsoft Graph

Rather than clicking around, we can use pure PowerShell to connect to Microsoft Graph and parse the JSON output of a named Intune remediation using the deviceManagement/deviceHealthScripts endpoint. In the script below, we specify the display name of the remediation to automatically grab the same PreRemediationDetectionScriptOutput field shown in the CSV above, and output it directly as a PSCustomObject that we can manipulate with Where-Object, Select-Object, and other standard cmdlets.

# Query Intune remediation results for Secure Boot status.
# Reference:
# https://support.microsoft.com/en-us/topic/monitoring-secure-boot-certificate-status-with-microsoft-intune-remediations-6696a27b-fa09-4570-b112-124965adc87f

#Set the name of the remediation you want to query. This should be the display name of the remediation in Intune. You can use wildcards (*) to match multiple remediations, but if multiple remediations match, only the first one will be used.
$RemediationName = "Secure Boot Inventory Data Collection script"

Connect-MgGraph -NoWelcome -Scopes "DeviceManagementManagedDevices.Read.All", "DeviceManagementConfiguration.Read.All", "DeviceManagementScripts.Read.All"

$scriptsResponse = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/deviceManagement/deviceHealthScripts"
$scriptMatches = @($scriptsResponse.value | Where-Object { $_.displayName -like "*$RemediationName*" })

if (-not $scriptMatches) {
    Write-Host "Remediation not found: $RemediationName" -ForegroundColor Red
    return
}

if (@($scriptMatches).Count -gt 1) {
    Write-Host "Multiple remediations matched. Using the first one:" -ForegroundColor Yellow
    $scriptMatches | Select-Object id, displayName | Format-Table -AutoSize
}

$script = $scriptMatches | Select-Object -First 1
$resultsResponse = Invoke-MgGraphRequest -Method GET -Uri "https://graph.microsoft.com/beta/deviceManagement/deviceHealthScripts/$($script.id)/deviceRunStates"
$results = @($resultsResponse.value)

$output = foreach ($result in $results) {
    try {
        $parsed = if ($result.preRemediationDetectionScriptOutput) {
            $result.preRemediationDetectionScriptOutput | ConvertFrom-Json
        }
        else {
            [PSCustomObject]@{}
        }
    }
    catch {
        $parsed = [PSCustomObject]@{}
    }

    $obj = [ordered]@{
        DeviceName              = $parsed.Hostname
        RemediationState        = $result.remediationState
        DetectionState          = $result.detectionState
        LastSyncDateTime        = $result.lastSyncDateTime
        LastStateUpdateDateTime = $result.lastStateUpdateDateTime
    }

    foreach ($prop in $parsed.PSObject.Properties) {
        $obj[$prop.Name] = $prop.Value
    }

    [PSCustomObject]$obj
}

$output

#Output example that reduces the amount of extra data
#$output | select-object DeviceName, DetectionState, LastSyncDateTime, UEFICA2023Status, SecureBootEnabled, HighConfidenceOptOut, MicrosoftUpdateManagedOptIn, OEMManufacturerName, OEMModelNumber, FirmwareVersion, FirmwareReleaseDate, CanAttemptUpdateAfter, Confidence


Hopefully this saves you some clicks next time you're auditing Secure Boot status across your fleet. You can also find a copy of the script here: https://github.com/DeploymentResearch/DRFiles/blob/master/Scripts/Intune/Get-IntuneRemediationSecureBootStatus.ps1

Additionally, Johan and I recently hosted a webinar around some of these tools and you can view that recording here:
Mini Course – Secure Boot 2026 – What Breaks and How to Fix It
https://academy.viamonstra.com/courses/mini-course-secure-boot-2026

About the author

Andrew Johnson

0 0 votes
Article Rating
Subscribe
Notify of
guest
0 Comments
Newest
Oldest Most Voted

>