Tuesday, 23 September 2025

Automating Intune & Microsoft 365 Monitoring


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