The remediation scripts in Microsoft Intune are a powerful way to remediate issues. We can use a remediation script to automatically fix common Windows issues across managed devices. We can also leverage the Microsoft Graph API to automate remediation script creation and assignment.
In this post, we’ll walk through:
- A common Windows issue to remediate (clearing temp files to free disk space).
- The PowerShell script to fix the issue.
- How to automate the creation of the remediation script in Intune using Microsoft Graph API.
Pre‑requisites for Automating Intune Remediation Scripts with Graph API
- Active Intune license in the tenant.
- Azure AD app registration created for automation.
- Admin consent granted for required Graph API permissions.
- Permissions needed:
DeviceManagementScripts.ReadWrite.All(manage remediation scripts)Directory.ReadWrite.All(manage Entra ID groups)
- Client credentials flow is configured with
https://graph.microsoft.com/.defaultscope. - PowerShell environment with Microsoft Graph modules installed.
- JSON file prepared with script parameters (name, description, detection, remediation paths).
- Access to Entra ID groups for assignment.
Automation Script Workflow for Intune Remediation
To automate Intune remediation script deployment with Microsoft Graph, follow these structured steps:
- Authenticate with Microsoft Graph
Acquire an OAuth 2.0 token using your Entra ID app registration. Ensure the app has the required Graph API permissions (DeviceManagementScripts.ReadWrite.AllandDirectory.ReadWrite.All). This authentication step enables secure access to Intune and Entra ID resources. - Load Script Parameters from JSON File
Store configuration details (script name, description, detection/remediation paths, group name, and group creation flag) in a JSON file. Reading parameters from JSON ensures consistency, scalability, and easier automation across environments. - Gather Detection and Remediation Script Details
Import the PowerShell detection and remediation scripts from the paths defined in the JSON file. Encode the script content in Base64 format, as required by Microsoft Graph API, to ensure proper transmission and execution. - Prepare the Payload
Construct a JSON payload containing metadata (script name, description, publisher, run schedule) and the encoded detection/remediation script content. This payload forms the body of the POST request to the Graph API. - Check for Entra ID Group Existence
Query Entra ID (Azure AD) to verify if the target group exists. Use Graph API filters (displayName eq 'GroupName') for exact matches. This ensures the remediation script is assigned to the correct group. - Create Entra ID Group (If Not Found)
If the group does not exist and the JSON configuration specifiesCreateGroup = Yes, automatically create a new security group in Entra ID. This step guarantees that script assignment won’t fail due to missing groups. - Create Intune Remediation Script
Send a POST request to thedeviceHealthScriptsendpoint with the prepared payload. This creates the remediation script in Intune. Capture the response to retrieve the script ID for subsequent assignment. - Assign the Script to Entra ID Group
Use the script ID and group ID to build an assignment payload. Wrap the target group in adeviceHealthScriptAssignmentsarray with@odata.type = "#microsoft.graph.groupAssignmentTarget". POST this payload to the/assignendpoint to link the remediation script to the group.

Set up Environment
Create Azure App Registration
Register an Entra ID app with the required Graph API permissions, then record the Tenant ID, Application (Client ID), and Client Secret. These credentials will be used later in the Intune automation script.

Core Permissions
- DeviceManagementScripts.ReadWrite.All
Grants full read/write access to Intune scripts, including creating, updating, deleting, and assigning remediation scripts.
This is the mandatory permission for automation scenarios using the Microsoft Graph API and Intune. - Directory.ReadWrite.All
Provides read/write access to directory data in Entra ID (Azure AD).
Required when your automation needs to create, update, or manage Entra ID groups for script assignment.
This ensures seamless integration between Intune remediation scripts and Entra ID group management.

Define the Source (Detection Script, Remediation Script, and JSON File)
We need a detection script, a remediation script, and a JSON file to provide all the required input for the remediation script creation.
We’ll use two PowerShell scripts and a JSON file:
- Detection script: Checks if the disk space on the system drive is less than 5 GB.
- Remediation script: Clears files from the Windows temp folder only if the detection script indicates low disk space.
- JSON file: Provide all arguments, such as detection script name, remediation script name, Entra ID group, etc., to the main automation script.
You need to store all these files in the same folder as your master script (create_intune_remediation_script.ps1)
Detection Script Example
# Check if free disk space on C: drive is less than 5 GB
$freeSpaceGB = (Get-PSDrive -Name C).Free / 1GB
if ($freeSpaceGB -lt 5) {
Write-Output "Disk space is low: $freeSpaceGB GB free."
exit 1 # Indicate detection of issue
} else {
Write-Output "Disk space is sufficient: $freeSpaceGB GB free."
exit 0 # No issue detected
}
Remediation Script Example
# Clear Temp Folder Script
$TempPath = $env:TEMP
Write-Output "Clearing temp files from $TempPath..."
Get-ChildItem -Path $TempPath -Recurse -Force -ErrorAction SilentlyContinue | Remove-Item -Force -Recurse -ErrorAction SilentlyContinue
Write-Output "Temp files cleared successfully."
These scripts can be uploaded to Intune as detection and remediation scripts, respectively, ensuring remediation runs only when disk space is low.
Prepare JSON File
We will use the JSON file to pass all required arguments to the script. This includes:
- ScriptName – Name of the script in Intune.
- Description – Detailed description of the remediation script in Intune. Include scope, functionality, and expected outcome for better indexing.
- DetectionScriptPath – Full file path to the PowerShell detection script. This script checks compliance or identifies issues on devices.
- RemediationScriptPath – Full file path to the PowerShell remediation script. This script resolves issues flagged by the detection script.
- EntraIDGroupName – The Entra ID (Azure AD) group name where the remediation script will be assigned. Use exact group names for targeting.
- CreateGroup – Option to automatically create the Entra ID group if it does not exist. Values:
YesorNo.

The source folder structure is shown below.

The Automation Script
Below is the automation script. Run it manually to create an Intune remediation script.
Ensure you configure Microsoft Graph API credentials to enable Intune remediation automation. Update Tenant ID, Client ID, and Client Secret before running the script.
function Show-Message {
param (
[Parameter(Mandatory = $true)]
[string]$Text,
[ValidateSet("Info","Warning","Error")]
[string]$Type = "Info"
)
switch ($Type) {
"Info" { Write-Host "[INFO] $Text" -ForegroundColor Cyan }
"Warning" { Write-Host "[WARNING] $Text" -ForegroundColor Yellow }
"Error" { Write-Host "[ERROR] $Text" -ForegroundColor Red }
}
}
### Enable Transcript
# Define Logs folder inside the script directory
$LogsFolder = Join-Path $PSScriptRoot "Logs"
# Create Logs folder if it doesn’t exist
if (-not (Test-Path $LogsFolder)) {
New-Item -Path $LogsFolder -ItemType Directory | Out-Null
Show-Message "Logs folder created at $LogsFolder" -Type Info
} else {
Show-Message "Logs folder already exists at $LogsFolder" -Type Info
}
# Define transcript path inside Logs folder
$TranscriptPath = Join-Path $LogsFolder "Transcript_$(Get-Date -Format 'yyyyMMdd_HHmmss').txt"
# Start transcript
Start-Transcript -Path $TranscriptPath -Append
write-host "Transcript started at $TranscriptPath"
#######################################
### Microsoft Graph - Acquire token ###
#######################################
$tenantId = "<Tenant ID>"
$clientId = "<Application ID>"
$clientSecret = "<Client Secret>"
$scope = "https://graph.microsoft.com/.default"
$body = @{
client_id = $clientId
scope = $scope
client_secret = $clientSecret
grant_type = "client_credentials"
}
try {
$tokenResponse = Invoke-RestMethod -Method Post `
-Uri "https://login.microsoftonline.com/$tenantId/oauth2/v2.0/token" `
-Body $body
if (-not $tokenResponse.access_token) {
Show-Message "Token acquisition failed. Exiting script..." -Type Error
exit 1
}
$token = $tokenResponse.access_token
Show-Message "Token acquired successfully." -Type Info
}
catch {
Show-Message "Error acquiring token: $($_.Exception.Message)" -Type Error
exit 1
}
##################################
### Gather script requirements ###
##################################
# Set path to config.json in the current script directory
$JsonFilePath = Join-Path -Path $PSScriptRoot -ChildPath "config.json"
Show-Message "Json File: $JsonfilePath" -Type Info
# Read JSON input file
$jsonContent = Get-Content -Path $JsonFilePath -Raw | ConvertFrom-Json
Show-Message "JSON Parameters:" -Type Info
foreach ($property in $jsonContent.PSObject.Properties) {
Show-Message "$($property.Name): $($property.Value)" -Type Info
}
# Read and encode the detection script content
$detectionScriptContent = Get-Content -Path $jsonContent.DetectionScriptPath -Raw
$encodedDetectionScript = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($detectionScriptContent))
# Read and encode the remediation script content
$remediationScriptContent = Get-Content -Path $jsonContent.RemediationScriptPath -Raw
$encodedRemediationScript = [System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($remediationScriptContent))
# Prepare payload
$payload = @{
displayName = $jsonContent.ScriptName
description = $jsonContent.Description
publisher = "IT Admin"
runSchedule = @{ interval = "PT24H" } # Run every 24 hours
detectionScriptContent = $encodedDetectionScript
remediationScriptContent = $encodedRemediationScript
}
#############################
### Create Entra ID Group ###
#############################
Show-Message "Creating Entra ID Group" -Type Info
$groupName = $jsonContent.EntraIDGroupName
$createGroup = $jsonContent.CreateGroup
Show-Message "Entra ID Group Name: >$groupName<"
try {
#$uri = "https://graph.microsoft.com/v1.0/groups?`$filter=startswith(displayName,'$groupName')"
$uri = "https://graph.microsoft.com/v1.0/groups?`$filter=displayName eq '$groupName'"
$group = Invoke-RestMethod -Method Get `
-Uri $uri `
-Headers @{ Authorization = "Bearer $token" }
}
catch {
Show-Message "❌ Failed to query group" -Type Info
if ($_.Exception.Response) {
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
$responseBody = $reader.ReadToEnd()
Write-Host "Status Code:" $_.Exception.Response.StatusCode.value__
Write-Host "Response Body:" $responseBody
}
throw $_
}
if ($group.value.Count -eq 0 -and $createGroup -eq 'Yes') {
Show-Message "Group '$groupName' not found. Creating group..." -Type Info
$groupPayload = @{
displayName = $groupName
mailEnabled = $false
mailNickname = $groupName.Replace(' ', '')
securityEnabled = $true
}
try {
$group = Invoke-RestMethod -Method Post `
-Uri "https://graph.microsoft.com/v1.0/groups" `
-Headers @{
Authorization = "Bearer $token"
"Content-Type" = "application/json"
} `
-Body ($groupPayload | ConvertTo-Json -Depth 5)
Show-Message "✅ Group created successfully: $($group.id)" -Type Info
}
catch {
Show-Message "❌ Failed to create group" -Type Error
if ($_.Exception.Response) {
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
$responseBody = $reader.ReadToEnd()
Write-Host "Status Code:" $_.Exception.Response.StatusCode.value__
Write-Host "Response Body:" $responseBody
}
throw $_
}
}
elseif ($group.value.Count -eq 0) {
throw "Group '$groupName' not found and CreateGroup is set to 'No'. Aborting."
}
else {
$group = $group.value[0]
Write-Host "ℹ️ Group already exists: $($group.id)"
Write-Host "ℹ️ Group already exists: $($group.displayname)"
}
#################################################
####### Create Remediation script in Intune #####
#################################################
Show-Message "Creating Intune remediation script" -Type Info
try {
$script = Invoke-RestMethod -Method Post `
-Uri "https://graph.microsoft.com/beta/deviceManagement/deviceHealthScripts" `
-Headers @{Authorization = "Bearer $token"; "Content-Type" = "application/json"} `
-Body ($payload | ConvertTo-Json -Depth 5 -Compress)
Show-Message "✅ Remediation script created successfully: $($script.id)" -Type Info
}
catch {
Write-Error "❌ Failed to create remediation script"
if ($_.Exception.Response) {
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
$responseBody = $reader.ReadToEnd()
Write-Host "Status Code:" $_.Exception.Response.StatusCode.value__
Write-Host "Response Body:" $responseBody
}
throw $_
}
#######################################
####### Assign script to group ########
#######################################
Show-Message "Assigning remediation script to Entra ID Group" -Type Info
# payload structure
$assignmentPayload = @{
deviceHealthScriptAssignments = @(
@{
target = @{
"@odata.type" = "#microsoft.graph.groupAssignmentTarget"
groupId = $group.id
}
}
)
}
try {
Invoke-RestMethod -Method Post `
-Uri "https://graph.microsoft.com/beta/deviceManagement/deviceHealthScripts/$($script.id)/assign" `
-Headers @{
Authorization = "Bearer $token"
"Content-Type" = "application/json"
} `
-Body ($assignmentPayload | ConvertTo-Json -Depth 5 -Compress)
Show-Message "✅ Script assigned successfully to group: $($group.displayName)" -Type Info
}
catch {
Write-Error "❌ Failed to assign remediation script"
if ($_.Exception.Response) {
$reader = New-Object System.IO.StreamReader($_.Exception.Response.GetResponseStream())
$responseBody = $reader.ReadToEnd()
Write-Host "Status Code:" $_.Exception.Response.StatusCode.value__
Write-Host "Response Body:" $responseBody
}
throw $_
}
# Stop transcript at the end
Stop-Transcript
Write-Host "Transcript stopped."
Steps to Use the Automation Script
- Update the content of the detection script.
- Update the content of the remediation script.
- Update the JSON file with parameters.
- Run the automation script.
Result
The automation script will create the remediation script and assign the script to the Entra ID group provided in the JSON file. You can see in below screenshot that script created and assigned based on the details provided in JSON config file.

You can find the log files for the script execution under “Logs” subfolder within script directory.
Conclusion
With this approach, you can automate the creation and deployment of Intune remediation scripts using the Microsoft Graph API. The example here addresses a simple but common issue—clearing temp files—but the same workflow can be applied to more complex scenarios like fixing registry settings, resetting services, or enforcing configuration baselines.
Script Download
FAQs About Intune Remediation Script Automation
Why should I use automation instead of creating scripts directly in the Intune admin center?
Automation saves time, reduces human error, and supports bulk creation. It also integrates with CI/CD pipelines, which the admin center cannot.
Can this script be reused across multiple tenants?
Yes. By updating the JSON file and credentials, you can quickly deploy remediation scripts in different environments.
What happens if token acquisition fails?
The script checks for token status. If the acquisition fails, it terminates gracefully and logs the error.
Do I need admin consent for Graph API permissions?
Yes. Admin consent is required for permissions like DeviceManagementScripts.ReadWrite.All and Directory.ReadWrite.All.
Can I assign scripts to dynamic groups automatically?
Yes. The automation script can check if groups exist, create them if missing, and assign scripts without manual steps.
Where are logs stored?
Logs are generated in the Logs folder inside the script directory. Transcripts capture all actions for auditing and troubleshooting.
Related Posts
- Bulk Export Entra ID Group Members with PowerShell & Microsoft Graph API
- How to Bulk Sync Intune Devices with Microsoft Graph
- Bulk Add Devices to Entra ID Group from CSV File
- How to Bulk Rename Windows Devices from Intune
Subscribe to Techuisitive Newsletter
Be the first to know about our new blog posts. Get our newsletters directly in your inbox and stay up to date about Modern Desktop Management technologies & news.