Bonus! Unhealthy MEMCM Clients email report
Bonus!
As another example of how you can export data from MS Graph, below is an Azure automation Runbook you can use to generate an email report of unhealthy co-managed MEMCM clients. Specifically, it will export a list of MEMCM co-managed devices that have synced with Intune in the last 7 days but have not synced with a MEMCM management point in the last 7 days. It will then send you the list as a CSV attachment in an email.
Unhealthy MEMCM Clients runbook
Requirements
Your automation account must be using a managed identity
The managed identity must be granted the appropriate permissions to Microsoft Graph as described in this guide
Outlook 365 with direct send or smtp relay configured
################################################################################
## Azure automation runbook PowerShell script to export a list of unhealthy ##
## MEMCM clients from Microsoft Intune / Endpoint Manager and send it the CSV ##
## report as an email attachment. ##
################################################################################
# Set some variables
$ProgressPreference = 'SilentlyContinue'
$EmailParams = @{
To = 'recipient@contoso.com'
From = 'azureautomation@contoso.onmicrosoft.com'
Smtpserver = 'contoso-com.mail.protection.outlook.com'
Port = 25
}
# Obtain an access token for MS Graph as a Managed Identity
$url = $env:IDENTITY_ENDPOINT
$headers = New-Object "System.Collections.Generic.Dictionary[[String],[String]]"
$headers.Add("X-IDENTITY-HEADER", $env:IDENTITY_HEADER)
$headers.Add("Metadata", "True")
$body = @{resource='https://graph.microsoft.com/' }
$accessToken = (Invoke-RestMethod $url -Method 'POST' -Headers $headers -ContentType 'application/x-www-form-urlencoded' -Body $body ).access_token
$authHeader = @{
'Authorization' = "Bearer $accessToken"
}
# Download data from MS Graph
$URI = "https://graph.microsoft.com/beta/deviceManagement/manageddevices?`$filter=StartsWith(operatingSystem,'Windows')&`$select=deviceName,enrolledDateTime,lastSyncDateTime,managementAgent,deviceEnrollmentType,userPrincipalName,model,serialNumber,userDisplayName,configurationManagerClientEnabledFeatures,configurationManagerClientHealthState"
$Response = Invoke-WebRequest -Uri $URI -Method Get -Headers $authHeader -UseBasicParsing
$JsonResponse = $Response.Content | ConvertFrom-Json
$DeviceData = $JsonResponse.value
If ($JsonResponse.'@odata.nextLink')
{
do {
$URI = $JsonResponse.'@odata.nextLink'
$Response = Invoke-WebRequest -Uri $URI -Method Get -Headers $authHeader -UseBasicParsing
$JsonResponse = $Response.Content | ConvertFrom-Json
$DeviceData += $JsonResponse.value
} until ($null -eq $JsonResponse.'@odata.nextLink')
}
# Organise the data as we want it displayed
$Devices = New-Object System.Collections.ArrayList
foreach ($item in $DeviceData)
{
try {
[void]$Devices.Add(
[PSCustomObject]@{
deviceName = $item.deviceName
enrolledDateTime = $item.enrolledDateTime
daysEnrolled = [math]::Round(((Get-Date) - ($item.enrolledDateTime | Get-Date -ErrorAction SilentlyContinue)).TotalDays,0)
lastSyncDateTime = $item.lastSyncDateTime
daysSinceLastSync = [math]::Round(((Get-Date) - ($item.lastSyncDateTime | Get-Date -ErrorAction SilentlyContinue)).TotalDays,0)
managementAgent = $item.managementAgent
deviceEnrollmentType = $item.deviceEnrollmentType
userPrincipalName = $item.userPrincipalName
model = $item.model
serialNumber = $item.serialNumber
userDisplayName = $item.userDisplayName
memcmEnabledFeature_inventory = $item.configurationManagerClientEnabledFeatures.inventory
memcmEnabledFeature_modernApps = $item.configurationManagerClientEnabledFeatures.modernApps
memcmEnabledFeature_resourceAccess = $item.configurationManagerClientEnabledFeatures.resourceAccess
memcmEnabledFeature_deviceConfiguration = $item.configurationManagerClientEnabledFeatures.deviceConfiguration
memcmEnabledFeature_compliancePolicy = $item.configurationManagerClientEnabledFeatures.compliancePolicy
memcmEnabledFeature_windowsUpdateForBusiness = $item.configurationManagerClientEnabledFeatures.windowsUpdateForBusiness
memcmEnabledFeature_endpointProtection = $item.configurationManagerClientEnabledFeatures.endpointProtection
memcmEnabledFeature_officeApps = $item.configurationManagerClientEnabledFeatures.officeApps
memcmClientHealth_state = $item.configurationManagerClientHealthState.state
memcmClientHealth_errorCode = $item.configurationManagerClientHealthState.errorCode
memcmClientHealth_lastSyncDateTime = $item.configurationManagerClientHealthState.lastSyncDateTime
memcmClientHealth_daysSinceLastSync = [math]::Round(((Get-Date) - ($item.configurationManagerClientHealthState.lastSyncDateTime | Get-Date -ErrorAction SilentlyContinue)).TotalDays,0)
}
)
}
catch {}
}
# Filter and export just the unhealthy clients - those that have talked to Intune but haven't talked to MEMCM in the last 7 days
$UnhealthyMEMCMClients = $Devices | where {$_.memcmClientHealth_state -ne 'healthy' -and $_.daysSinceLastSync -le 7 -and $_.memcmClientHealth_daysSinceLastSync -gt 7}
$UnhealthyMEMCMClients | export-csv -Path $env:temp\UnhealthyMEMCMClients.csv -Force -NoTypeInformation
# Send the email
Send-MailMessage @EmailParams -Subject "[Azure Automation] Unhealthy MEMCM Clients in Intune ($($UnhealthyMEMCMClients.Count))" -Attachments "$env:temp\UnhealthyMEMCMClients.csv"
Last updated