Skip to content

robgrame/Intune.DiskGuardian

Repository files navigation

Intune Disk Guardian

License: MIT .NET Azure

Automated solution for Microsoft Intune that detects Windows devices with low free disk space using Proactive Remediations and performs bidirectional sync with an Entra ID security group: devices with low disk space are added, and devices that recover are automatically removed.


✨ What's Included

Component Path Description
Proactive Remediation Scripts RemediationScripts/ Detection script (checks free space, exit 0/1) + optional remediation script (cleans temp files)
Azure Logic App (Bicep) main.bicep Serverless Logic App that reads Intune inventory and adds low-disk devices to an Entra group
.NET 10 Worker Service Automation/IntuneDiskGuardian/ Long-running background service — reads remediation results via Graph API, bidirectional group sync
PowerShell Automation Automation/ Standalone scripts for the same bidirectional sync + Windows Scheduled Task setup
App Registration Automation/Register-App.ps1 Creates the Entra app with least-privilege Graph permissions
Graph Permissions grant-graph-permissions.ps1 Grants Graph API permissions to the Logic App's Managed Identity

🏗️ Architecture

┌────────────────────┐      ┌──────────────────────┐      ┌────────────────────────┐
│  Intune Proactive  │      │  .NET Worker Service  │      │  Entra ID Group        │
│  Remediation       │      │  (or PowerShell /     │      │  "Devices-LowDisk"     │
│                    │      │   Logic App)          │      │                        │
│  Detect-LowDisk    │      │                       │      │  Targeted policies:    │
│  runs on device    │─────►│  Reads health script  │─────►│  - Cleanup scripts     │
│  < 25 GB = exit 1  │      │  run states via Graph │      │  - Conditional Access  │
│                    │      │  Adds/removes devices │      │  - Notifications       │
│  Remediate-LowDisk │      │  bidirectionally      │      │                        │
│  cleans temp files │      │                       │      │                        │
└────────────────────┘      └──────────────────────┘      └────────────────────────┘

Three deployment options — pick the one that fits your environment:

Option Best for Runs on
A — .NET Worker Service Enterprises needing a robust, long-running service Windows Server / Container / Azure Container Apps
B — PowerShell Scheduled Task Simple on-prem deployments Windows Server (Task Scheduler)
C — Azure Logic App Fully serverless, zero infrastructure Azure (Consumption plan)

📋 Prerequisites

  • Azure subscription (Contributor on target Resource Group — for Logic App option)
  • Microsoft Intune with enrolled Windows devices
  • Entra ID permissions to create security groups and app registrations
  • .NET 10 SDK — for the Worker Service (download)
  • Azure CLI + Bicep CLI — for the Logic App option
  • Microsoft Graph PowerShell SDK:
    Install-Module Microsoft.Graph -Scope CurrentUser

🚀 Quick Start

Step 1 — Deploy the Proactive Remediation in Intune

  1. Intune admin center → Devices → Remediations → Create script package
  2. Name: IntuneDiskGuardian - Low Disk Space
  3. Upload RemediationScripts/Detect-LowDiskSpace.ps1 as the Detection script
  4. Upload RemediationScripts/Remediate-LowDiskSpace.ps1 as the Remediation script (optional — cleans temp files)
  5. Set Run this script using the logged-on credentials: No (run as SYSTEM)
  6. Assign to your device groups and configure the Schedule (e.g., every 1 hour, daily)
  7. After deploying, note the Health Script ID from the Intune portal URL or via Graph:
    GET https://graph.microsoft.com/beta/deviceManagement/deviceHealthScripts
    

Devices with less than 25 GB free on the system drive will report exit 1 (issue detected). When a device frees up space, the next run reports exit 0 and it will be automatically removed from the group at the next sync cycle.

Step 2 — Create the App Registration

.\Automation\Register-App.ps1

Save the output (TenantId, ClientId, ClientSecret) securely — ideally in Azure Key Vault.

Step 3 — Run the Automation

Option A — .NET 10 Worker Service

cd Automation/IntuneDiskGuardian

# Store secrets with .NET User Secrets (never in appsettings.json)
dotnet user-secrets set "IntuneDiskGuardian:TenantId"       "<YOUR-TENANT-ID>"
dotnet user-secrets set "IntuneDiskGuardian:ClientId"        "<YOUR-CLIENT-ID>"
dotnet user-secrets set "IntuneDiskGuardian:ClientSecret"     "<YOUR-CLIENT-SECRET>"
dotnet user-secrets set "IntuneDiskGuardian:EntraGroupId"     "<YOUR-GROUP-OBJECT-ID>"
dotnet user-secrets set "IntuneDiskGuardian:HealthScriptId"   "<YOUR-HEALTH-SCRIPT-ID>"

dotnet run

Configuration in appsettings.json:

{
  "IntuneDiskGuardian": {
    "TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "ClientSecret": "use-user-secrets-or-keyvault",
    "EntraGroupId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "HealthScriptId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "ThresholdGB": 25,
    "SyncInterval": "01:00:00"
  }
}

Option B — PowerShell Scheduled Task

.\Automation\Setup-ScheduledTask.ps1 `
    -TenantId       "<TENANT-ID>" `
    -ClientId       "<CLIENT-ID>" `
    -ClientSecret   "<CLIENT-SECRET>" `
    -EntraGroupId   "<GROUP-ID>" `
    -HealthScriptId "<HEALTH-SCRIPT-ID>" `
    -ScriptPath     "C:\Scripts\Sync-NonCompliantDevices.ps1"

Option C — Azure Logic App (Serverless)

az group create --name rg-intune-disk-guardian --location westeurope

az deployment group create \
  --resource-group rg-intune-disk-guardian \
  --template-file main.bicep \
  --parameters main.bicepparam

# Grant Graph permissions to Managed Identity (from deployment output)
.\grant-graph-permissions.ps1 -ManagedIdentityObjectId "<MI-OBJECT-ID>"

🔐 Required Graph API Permissions

Permission Type Purpose
DeviceManagementConfiguration.Read.All Application Read Proactive Remediation (health script) run states
GroupMember.ReadWrite.All Application Add/remove devices in the Entra group
Device.Read.All Application Resolve device objects in Entra ID

All permissions follow the least-privilege principle. The Register-App.ps1 script assigns them automatically with admin consent.


🔧 Customization

Change the Disk Space Threshold

Edit RemediationScripts/Detect-LowDiskSpace.ps1 — change the $thresholdGB variable:

$thresholdGB = 25   # Change this value

Also update ThresholdGB in the Worker Service config / PowerShell parameter to match.

Change 25 to your desired threshold in GB.

Change the Sync Interval (.NET Worker)

In appsettings.json or via environment variable:

"SyncInterval": "00:30:00"

Format: HH:mm:ss (e.g., 00:30:00 = every 30 minutes).


🧪 Troubleshooting

Symptom Cause Fix
401 Unauthorized Graph permissions not yet propagated Wait 15–30 min after granting permissions
403 Forbidden Missing application permissions Re-run Register-App.ps1 or grant-graph-permissions.ps1
Device not flagged freeStorageSpaceInBytes is 0 or null Verify device is enrolled and syncing with Intune
400 Bad Request on group add Device already in group Expected behavior — silently skipped
No devices processed All devices are compliant Check compliance state in Intune admin center

🗂️ Project Structure

IntuneDiskGuardian/
├── RemediationScripts/
│   ├── Detect-LowDiskSpace.ps1              # Proactive Remediation detection (runs on device)
│   └── Remediate-LowDiskSpace.ps1           # Optional: cleans temp files to free space
├── Automation/
│   ├── Register-App.ps1                     # App Registration setup
│   ├── Sync-NonCompliantDevices.ps1         # PowerShell sync script
│   ├── Setup-ScheduledTask.ps1              # Scheduled Task installer
│   └── IntuneDiskGuardian/                  # .NET 10 Worker Service
│       ├── Program.cs
│       ├── Worker.cs
│       ├── Configuration/
│       │   └── IntuneDiskGuardianOptions.cs
│       ├── Services/
│       │   └── DeviceSyncService.cs
│       └── appsettings.json
├── main.bicep                               # Logic App infrastructure (Bicep)
├── main.bicepparam                          # Deployment parameters
├── main.json                                # Compiled ARM template
└── grant-graph-permissions.ps1              # Graph permissions for Managed Identity

🔒 Security Best Practices

  • Never commit secrets to source control — use .NET User Secrets or Azure Key Vault
  • For production, prefer certificate-based authentication over client secrets
  • The App Registration uses least-privilege application permissions
  • Rotate client secrets before expiry (default: 1 year)
  • The Logic App uses a System-assigned Managed Identity (no secrets to manage)

📄 License

This project is licensed under the MIT License.


🤝 Contributing

Contributions are welcome! Please open an issue or submit a pull request.

About

Automated Intune solution that detects Windows devices with low disk space, flags them as non-compliant via Custom Compliance Policy, and adds them to an Entra ID group for targeted remediation. Includes .NET 10 Worker Service, PowerShell automation, and Azure Logic App (Bicep).

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors