#!/bin/bash # Intune custom compliance discovery script for Linux: is Microsoft Defender # for Endpoint (mdatp) installed, onboarded, licensed and protecting? # # Upload in Intune > Devices > Compliance > Scripts (Linux), and pair it with # defender-compliance.json in a Linux compliance policy (Custom compliance). # Himmelblau runs it as root inside himmelblaud-tasks.service and sends the # JSON on stdout to Intune, which evaluates it against the rules. Every setting # is always emitted, so a missing or stopped Defender reads as non-compliant # instead of as a script error. MDATP=/usr/bin/mdatp # Print one `mdatp health` field without quotes or a trailing " [managed]". # Unlicensed or unonboarded, mdatp prints "ATTENTION: ..." lines first. field() { "${MDATP}" health --field "$1" 2>/dev/null | grep -v '^ATTENTION' | tail -n1 \ | sed -e 's/ \[managed\]$//' -e 's/^"//' -e 's/"$//' } bool() { [[ "$1" == true ]] && echo true || echo false } installed=false running=false healthy=false licensed=false onboarded=false rtp=false behavior_monitoring=false cloud_protection=false definitions_ok=false definitions_age=-1 version="" if [[ -x "${MDATP}" ]]; then installed=true if [[ "$(field healthy)" =~ ^(true|false)$ ]]; then # The daemon answered. running=true healthy="$(bool "$(field healthy)")" licensed="$(bool "$(field licensed)")" rtp="$(bool "$(field real_time_protection_enabled)")" [[ "$(field behavior_monitoring)" == enabled ]] && behavior_monitoring=true cloud_protection="$(bool "$(field cloud_enabled)")" [[ -n "$(field org_id)" ]] && onboarded=true [[ "$(field definitions_status)" == up_to_date ]] && definitions_ok=true age="$(field definitions_updated_minutes_ago)" [[ "${age}" =~ ^[0-9]+$ ]] && definitions_age=$(( age / 1440 )) version="$(field app_version)" version="${version//[^0-9A-Za-z._-]/}" fi fi cat <