Automating Intune & Microsoft 365 Monitoring
Introduction
Managing Intune and Microsoft 365 environments at scale
requires automation to ensure proactive monitoring and faster remediation.
Microsoft Graph API and PowerShell provide powerful ways to automate daily
checks, consolidate reports, and reduce manual effort. This document outlines
key areas where automation can be applied, with explanations of what can be
monitored and how.
1. Service Health Check
·
Monitor Intune-related issues or advisories to
detect outages or degradation.
·
Automation: Use Microsoft Graph Service
Communications API to pull current advisories/incidents and schedule reports.
2. Device Compliance & Health
·
Non-Compliant Devices: Identify non-compliant
devices and reasons.
·
Device Check-ins: Detect devices not checked in
recently (e.g., 7 days).
·
Autopilot Deployment Status: Track deployment
profiles and enrollment progress.
3. App Monitoring
·
App Deployment Failures: Identify failed/pending
installations.
·
Pending App Approvals: Review user requests
awaiting approval.
4. Configuration Profiles
·
Profile Deployment Status: Monitor
failed/pending deployments.
·
Script Execution Failures: Detect failed Intune
PowerShell scripts.
5. Endpoint Security
·
Policy Status: Monitor antivirus, firewall,
encryption policies.
·
Threat Detection: Use Defender ATP/Graph
Security API for incidents.
6. User Issues & Support
·
Helpdesk Tickets: Cross-reference device/app
issues with compliance data.
·
Device Enrollment Failures: Track enrollment
failures and causes.
7. Audit & Alerts
·
Audit Logs: Retrieve admin actions for
compliance/governance.
·
Alerts & Notifications: Consolidate alerts
from Intune, Azure AD, and Defender.
8. Licensing & Users
·
License Availability: Ensure sufficient license
pool for Intune/EMS/M365.
·
User Assignment Issues: Detect unlicensed users
and generate reports.
Conclusion
By leveraging Microsoft Graph API and PowerShell automation,
administrators can reduce manual monitoring tasks across Intune and Microsoft
365. Automated jobs provide real-time insights, proactive alerts, and
consolidated reporting, ensuring better visibility, faster response, and
improved device/user experience.
HTML view:
SCRIPT: Copy to notepad and Save as .ps1 file
<#
.SYNOPSIS
Modular M365 / Intune Health Monitoring Report
.DESCRIPTION
Connects to Microsoft Graph and collects:
- Service Health
- Device Compliance
- Autopilot Devices
- Defender Alerts
- Licensing
Outputs:
- CSV exports
- HTML summary report
.NOTES
Author: Prasad Chenikala
#>
# -------------------------
# 0. Graph SDK Environment Validator
# -------------------------
function Validate-GraphEnvironment {
Write-Host "`nChecking Microsoft Graph SDK installation..." -ForegroundColor Cyan
$module = Get-InstalledModule Microsoft.Graph -ErrorAction SilentlyContinue | Sort-Object Version -Descending | Select-Object -First 1
if ($null -eq $module) {
Write-Host "Microsoft.Graph module not found. Please install it:" -ForegroundColor Red
Write-Host "Install-Module Microsoft.Graph -Scope CurrentUser -Force"
exit
}
Write-Host "Microsoft.Graph module version: $($module.Version)" -ForegroundColor Green
Write-Host "Microsoft Graph SDK v2 detected and ready." -ForegroundColor Green
}
# -------------------------
# 1. Initialization
# -------------------------
function Initialize-Environment {
$Global:Today = Get-Date -Format "yyyyMMdd"
$Global:ReportPath = "$env:USERPROFILE\Documents\Reports\M365_Intune_Report_$Today"
New-Item -ItemType Directory -Force -Path $ReportPath | Out-Null
$Scopes = @(
"DeviceManagementManagedDevices.Read.All",
"DeviceManagementConfiguration.Read.All",
"DeviceManagementApps.Read.All",
"DeviceManagementServiceConfig.Read.All",
"Directory.Read.All",
"Reports.Read.All",
"SecurityEvents.Read.All",
"AuditLog.Read.All",
"ServiceHealth.Read.All"
)
Connect-MgGraph -Scopes $Scopes -NoWelcome
}
# -------------------------
# 2. Service Health
# -------------------------
function Get-ServiceHealth {
$data = Get-MgServiceAnnouncementHealthOverview
$data | Export-Csv "$ReportPath\ServiceHealth.csv" -NoTypeInformation
return $data
}
# -------------------------
# 3. Device Compliance
# -------------------------
function Get-DeviceCompliance {
$nonCompliant = Get-MgDeviceManagementManagedDevice -Filter "complianceState ne 'compliant'"
$nonCompliant | Export-Csv "$ReportPath\NonCompliantDevices.csv" -NoTypeInformation
$stale = Get-MgDeviceManagementManagedDevice | Where-Object {
$_.lastSyncDateTime -lt (Get-Date).AddDays(-7)
}
$stale | Export-Csv "$ReportPath\StaleDevices.csv" -NoTypeInformation
return @{
NonCompliant = $nonCompliant
Stale = $stale
}
}
# -------------------------
# 4. Autopilot Devices
# -------------------------
function Get-AutopilotDevices {
$data = Get-MgDeviceManagementWindowsAutopilotDeviceIdentity
$data | Export-Csv "$ReportPath\AutopilotDevices.csv" -NoTypeInformation
return $data
}
# -------------------------
# 5. Defender Alerts
# -------------------------
function Get-DefenderAlerts {
$data = Get-MgSecurityAlert -All
$data | Export-Csv "$ReportPath\DefenderAlerts.csv" -NoTypeInformation
return $data
}
# -------------------------
# 6. Licensing
# -------------------------
function Get-Licensing {
$licenses = Get-MgSubscribedSku
$licenses | Export-Csv "$ReportPath\Licenses.csv" -NoTypeInformation
$users = Get-MgUser -All
$userLicenses = @()
foreach ($u in $users) {
$userLicenses += Get-MgUserLicenseDetail -UserId $u.Id
}
$userLicenses | Export-Csv "$ReportPath\UserLicenses.csv" -NoTypeInformation
return @{
Licenses = $licenses
Users = $userLicenses
}
}
# -------------------------
# 7. Build HTML Report
# -------------------------
function Build-HtmlReport {
param (
$ServiceHealth,
$DeviceCompliance,
$Autopilot,
$DefenderAlerts,
$Licensing
)
$html = @'
<html>
<head>
<title>M365 and Intune Daily Report</title>
<style>
body { font-family: Arial; }
h2 { background-color: #0078D4; color: white; padding: 5px; }
table { border-collapse: collapse; width: 100%; margin-bottom: 20px; }
th, td { border: 1px solid #ddd; padding: 8px; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>M365 and Intune Daily Health Report - REPLACEME</h1>
'@
$html = $html -replace 'REPLACEME', $Global:Today
$html += '<h2>Service Health</h2>'
$html += ($ServiceHealth | Select-Object workload, status | ConvertTo-Html -Fragment)
$html += '<h2>Non-Compliant Devices</h2>'
$html += ($DeviceCompliance.NonCompliant | Select-Object deviceName, userPrincipalName, complianceState, lastSyncDateTime | ConvertTo-Html -Fragment)
$html += '<h2>Stale Devices (greater than 7 days no check-in)</h2>'
$html += ($DeviceCompliance.Stale | Select-Object deviceName, userPrincipalName, lastSyncDateTime | ConvertTo-Html -Fragment)
$html += '<h2>Autopilot Devices</h2>'
$html += ($Autopilot | Select-Object serialNumber, deploymentProfileAssignmentStatus | ConvertTo-Html -Fragment)
$html += '<h2>Defender Alerts</h2>'
$html += ($DefenderAlerts | Select-Object title, severity, status, createdDateTime | ConvertTo-Html -Fragment)
$html += '<h2>Licenses</h2>'
$html += ($Licensing.Licenses | Select-Object skuPartNumber, consumedUnits, prepaidUnits | ConvertTo-Html -Fragment)
$html += '</body></html>'
$html | Out-File "$ReportPath\M365_Intune_Report.html" -Encoding utf8
}
# -------------------------
# Main Execution
# -------------------------
Validate-GraphEnvironment
Initialize-Environment
$ServiceHealth = Get-ServiceHealth
$DeviceCompliance = Get-DeviceCompliance
$Autopilot = Get-AutopilotDevices
$DefenderAlerts = Get-DefenderAlerts
$Licensing = Get-Licensing
Build-HtmlReport -ServiceHealth $ServiceHealth `
-DeviceCompliance $DeviceCompliance `
-Autopilot $Autopilot `
-DefenderAlerts $DefenderAlerts `
-Licensing $Licensing
Write-Host "`nReport generated at $ReportPath" -ForegroundColor Green