Files
bootc-images/images/fedora-intune/intune/defender-compliance.sh
T
Wesley van TilburgandClaude Opus 5.5 ebe1d80f80
Build containers / fedora-cosmic (44) (pull_request) Canceled after 0s
Build containers / fedora-cosmic (rawhide) (pull_request) Canceled after 0s
Build containers / fedora-remote (44) (pull_request) Canceled after 0s
Build containers / fedora-intune (44) (pull_request) Canceled after 0s
Build containers / Compute changes (pull_request) Canceled after 17s
Build containers / Prune old releases and tags (pull_request) Skipped
fedora-intune: enforce Defender protection settings
Defender's defaults left behavior monitoring off and every setting
unmanaged. Ship /etc/opt/microsoft/mdatp/managed/mdatp_managed.json:
real-time protection, behavior monitoring, PUA blocking, cloud-delivered
protection at the high block level, automatic definition updates and
sample submission, and scheduled scans (daily quick at 12:00, weekly full
on Wednesday 12:30, low priority). Users can't change managed settings.
The build fails if the file isn't valid JSON.

Network protection (Insiders channels only) and tamper protection
(audit-only preview on Linux) are left out.

The compliance script and rules now also check behavior monitoring and
cloud-delivered protection.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-20 12:19:17 +00:00

71 lines
2.3 KiB
Bash
Executable File

#!/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 <<EOF
{
"DefenderInstalled": ${installed},
"DefenderRunning": ${running},
"DefenderHealthy": ${healthy},
"DefenderLicensed": ${licensed},
"DefenderOnboarded": ${onboarded},
"DefenderRealTimeProtection": ${rtp},
"DefenderBehaviorMonitoring": ${behavior_monitoring},
"DefenderCloudProtection": ${cloud_protection},
"DefenderDefinitionsUpToDate": ${definitions_ok},
"DefenderDefinitionsAgeDays": ${definitions_age},
"DefenderVersion": "${version}"
}
EOF