rules: hybrid user-affinity + never-settled-app detection, dsregcmd on_event snapshot, evidence interpolation fixes

ANALYZE-ID-004 (hybrid sign-in never establishes Entra user affinity),
ANALYZE-APP-015 (required app pending forever, ESP completion deferred),
ANALYZE-ENRL-002 v1.1 (desktop-reached + apps-done evidence), GATHER-DEVICE-006
(dsregcmd /status triggered by hybrid_login_pending). Engine: list evidence
values now comma-joined for UI/{{token}} interpolation; timeoutHours added to
the evidence whitelist so ANALYZE-ENRL-002's explanation interpolates.

Motivated by esa-logistics sessions 3ac8cb0e/95f71149 (user-phase stuck,
GlobalProtect never settling, placeholder identity persisting across reboots).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Oliver Kieselbach
2026-08-14 13:39:16 +02:00
parent c60c0bbede
commit 6c6014940e
7 changed files with 466 additions and 7 deletions
+80
View File
@@ -0,0 +1,80 @@
{
"$schema": "../schema/analyze-rule.schema.json",
"ruleId": "ANALYZE-APP-015",
"title": "Required App Never Settled — ESP Completion Deferred",
"description": "The IME reported its user-session completion line, but at least one required app stayed pending — without ever failing or even starting to install — so the agent kept deferring the enrollment completion signal. Typically an assignment/requirement problem (requirement rules never met, dependency never satisfied, or the app needs a context that is not available during ESP, e.g. a VPN client waiting for user sign-in to a portal).",
"severity": "high",
"category": "apps",
"version": "1.0.0",
"author": "Autopilot Monitor",
"enabled": true,
"trigger": "correlation",
"baseConfidence": 60,
"confidenceThreshold": 55,
"preconditions": [
{
"source": "event_data",
"eventType": "enrollment_complete",
"operator": "not_exists",
"description": "Suppress when the pending app eventually settled and the enrollment completed — a transient deferral is normal."
},
{
"source": "event_data",
"eventType": "enrollment_failed",
"operator": "not_exists",
"description": "Suppress when the session failed explicitly — the app/ESP failure rules already cover that path; this rule targets the never-finishing case."
}
],
"conditions": [
{
"signal": "completion_deferred",
"source": "event_type",
"eventType": "agent_trace",
"dataField": "message",
"operator": "contains",
"value": "completion signal deferred",
"required": true
},
{
"signal": "apps_pending",
"source": "event_data",
"eventType": "app_tracking_summary",
"dataField": "pending",
"operator": "gte",
"value": "1",
"required": true
},
{
"signal": "pending_app_names",
"source": "event_data",
"eventType": "app_tracking_summary",
"dataField": "pendingNames",
"operator": "exists",
"value": "",
"required": false
}
],
"confidenceFactors": [
{ "signal": "pending_app_names", "condition": "exists", "weight": 5 }
],
"explanation": "The Intune Management Extension wrote its user-session completion line, but the agent observed `{{pending}}` required app(s) still pending (`{{pendingNames}}`) and therefore **deferred the enrollment completion signal** — repeatedly, if this happened across several logons or reboots.\n\nA pending app that never transitions to downloading/installing and never fails is almost always an **assignment or requirement problem**, not an install error:\n\n- requirement rules that are never met on this device (OS/architecture/registry/script checks),\n- an unsatisfied dependency or supersedence chain,\n- an app targeted as *required* for the user ESP that needs something unavailable during provisioning (e.g. a VPN client whose portal sign-in only happens after first logon),\n- user-targeted apps on a device where the user identity never fully registered (see the hybrid user-affinity rule if it also fired).",
"remediation": [
{
"title": "Identify and unblock the pending app",
"steps": [
"Check the app names listed in this finding's evidence (pendingNames) — these are the apps the ESP is waiting for.",
"In Intune, review the app's requirement rules and dependencies; test them on the device (IntuneManagementExtension.log logs each requirement evaluation).",
"Decide whether the app really must block the ESP: removing it from the ESP's 'blocking apps' list (or making it not-required during enrollment) unblocks completion immediately.",
"If the app is user-targeted on a hybrid-joined device, verify the user's Entra affinity first — without a signed-in Entra user, user-targeted policy never applies."
]
}
],
"relatedDocs": [
{
"title": "Microsoft Learn: Enrollment Status Page — blocking apps",
"url": "https://learn.microsoft.com/en-us/intune/intune-service/enrollment/windows-enrollment-status"
}
],
"markSessionAsFailedDefault": false,
"tags": ["apps", "esp", "completion", "assignment", "pending"]
}
+26 -2
View File
@@ -5,7 +5,7 @@
"description": "Detects when the enrollment session was force-failed by the server-side inactivity timeout (no agent telemetry for the configured SessionTimeoutHours window) without ever completing or explicitly failing.",
"severity": "high",
"category": "enrollment",
"version": "1.0.0",
"version": "1.1.0",
"enabled": true,
"baseConfidence": 80,
"preconditions": [
@@ -30,9 +30,26 @@
"operator": "exists",
"value": "",
"required": true
},
{
"signal": "desktop_was_reached",
"source": "event_type",
"eventType": "desktop_arrived",
"operator": "exists",
"value": "",
"required": false
},
{
"signal": "all_tracked_apps_completed",
"source": "event_data",
"eventType": "app_tracking_summary",
"dataField": "isAllCompleted",
"operator": "equals",
"value": "true",
"required": false
}
],
"explanation": "The enrollment session was force-failed by the server-side maintenance sweep after `{{timeoutHours}}` hour(s) of agent inactivity — the device stopped sending telemetry and never reported completion or an explicit failure.\n\nThis usually means the agent process died or the device went offline mid-enrollment (power off, network loss, bluescreen, reimage) rather than a clean enrollment failure. Because there is no terminal `enrollment_failed` event, the more specific app/ESP rules cannot pinpoint a cause — the evidence simply stops at the last event before the gap.",
"explanation": "The enrollment session was force-failed by the server-side maintenance sweep after `{{timeoutHours}}` hour(s) of agent inactivity — the device stopped sending telemetry and never reported completion or an explicit failure.\n\nThis usually means the agent process died or the device went offline mid-enrollment (power off, network loss, bluescreen, reimage) rather than a clean enrollment failure. Because there is no terminal `enrollment_failed` event, the more specific app/ESP rules cannot pinpoint a cause — the evidence simply stops at the last event before the gap.\n\n**If the evidence shows the user desktop was reached and all tracked apps completed**, the device most likely got all its content but the ESP never signaled completion — on hybrid-joined devices the usual culprit is the user session never establishing Entra affinity (Account Setup re-running on every logon). Check whether the hybrid user-affinity finding also fired for this session.",
"remediation": [
{
"title": "Investigate the silent session",
@@ -43,6 +60,13 @@
"If the device is reachable, collect the agent + IME logs and re-run enrollment, correlating with the timeout timestamp",
"If many sessions time out in the same window, check for a tenant-wide network/connectivity issue or an Intune service incident"
]
},
{
"title": "Desktop reached and apps done, but no completion",
"steps": [
"Sign in as the affected user and run dsregcmd /status — 'SSO State: AzureAdPrt' must be YES; NO means the user never registered with Entra and the Account Setup ESP will loop",
"Verify Entra Connect syncs both the computer object (userCertificate) and the signing-in user, and that the user's UPN suffix is a verified Entra domain"
]
}
],
"tags": ["enrollment", "timeout", "stalled"]
+86
View File
@@ -0,0 +1,86 @@
{
"$schema": "../schema/analyze-rule.schema.json",
"ruleId": "ANALYZE-ID-004",
"title": "Hybrid Sign-In Never Establishes Entra User Affinity",
"description": "On a hybrid-joined device the real user reached the desktop, but the Autopilot provisioning placeholder stayed active in JoinInfo and the agent repeatedly reported the hybrid sign-in as overdue. The user session never establishes Entra user affinity (no PRT), so the Account Setup ESP re-runs on every logon and the enrollment never completes.",
"severity": "high",
"category": "identity",
"version": "1.0.0",
"author": "Autopilot Monitor",
"enabled": true,
"trigger": "correlation",
"baseConfidence": 60,
"confidenceThreshold": 65,
"preconditions": [
{
"source": "event_data",
"eventType": "enrollment_complete",
"operator": "not_exists",
"description": "Suppress when the session eventually completed — a single overdue-login warning followed by a successful sign-in is normal hybrid latency, not a broken affinity."
}
],
"conditions": [
{
"signal": "hybrid_login_overdue",
"source": "event_type",
"eventType": "hybrid_login_pending",
"operator": "exists",
"value": "",
"required": true
},
{
"signal": "user_desktop_reached",
"source": "event_type",
"eventType": "desktop_arrived",
"operator": "exists",
"value": "",
"required": true
},
{
"signal": "placeholder_still_active",
"source": "event_type",
"eventType": "aad_placeholder_user_detected",
"operator": "exists",
"value": "",
"required": false
}
],
"confidenceFactors": [
{ "signal": "hybrid_login_pending", "condition": "count >= 2", "weight": 20 },
{ "signal": "hybrid_login_pending", "condition": "count >= 3", "weight": 10 },
{ "signal": "aad_placeholder_user_detected", "condition": "count >= 3", "weight": 10 }
],
"explanation": "A real user signed in and reached the desktop, but the device kept reporting the **Autopilot provisioning placeholder** as the active identity in JoinInfo and the hybrid sign-in as **overdue** — across multiple reboots. This means the signed-in user never established **Microsoft Entra user affinity** (no Primary Refresh Token), so:\n\n- the Account Setup ESP page re-appears on every logon,\n- user-targeted required apps and policies cannot settle,\n- the enrollment never reaches completion.\n\nAfter this many hours this is not normal Entra Connect sync latency — something is structurally preventing the user (or the computer object) from registering:\n\n- the computer object's `userCertificate` attribute is not syncing to Entra ID (sync scope / OU filtering),\n- the signing-in user is not synced, or their UPN does not match a verified Entra domain,\n- the device has no line of sight to a domain controller **at logon time**, so the hybrid PRT flow cannot finish,\n- time skew or a proxy blocking `login.microsoftonline.com` / `enterpriseregistration.windows.net` from the user context.",
"remediation": [
{
"title": "Verify user affinity on the device",
"steps": [
"Sign in as the affected user and run: dsregcmd /status — under 'SSO State' the value AzureAdPrt must be YES. NO means the user has no Entra token and this diagnosis is confirmed.",
"Also check 'Device State': AzureAdJoined = YES and DomainJoined = YES are expected for hybrid join.",
"Check Event Viewer: Applications and Services Logs > Microsoft > Windows > User Device Registration > Admin for PRT / registration errors (e.g. event 304/305/362).",
"Enable the gather rules 'Collect dsregcmd join status' so future sessions capture this state automatically."
]
},
{
"title": "Fix the identity pipeline",
"steps": [
"Entra Connect: confirm BOTH the computer OU and the user OU are in the sync scope, and the computer object's userCertificate attribute is being exported.",
"Verify the user's UPN suffix is a verified domain in Entra ID (no .local / mismatched suffix).",
"Ensure domain-controller line of sight at logon from the provisioning network/VLAN (hybrid PRT requires a reachable DC).",
"Check proxy/firewall rules for login.microsoftonline.com, device.login.microsoftonline.com and enterpriseregistration.windows.net from the user context."
]
}
],
"relatedDocs": [
{
"title": "Autopilot Monitor: Hybrid join — late device registration",
"url": "https://docs.autopilotmonitor.com/troubleshooting/hybrid-join-late-device-registration"
},
{
"title": "Microsoft Learn: Troubleshoot hybrid-joined devices",
"url": "https://learn.microsoft.com/en-us/entra/identity/devices/troubleshoot-hybrid-join-windows-current"
}
],
"markSessionAsFailedDefault": false,
"tags": ["identity", "hybrid-join", "entra-id", "user-affinity", "esp"]
}
+218 -2
View File
@@ -637,6 +637,95 @@
"0x80073cf9"
]
},
{
"ruleId": "ANALYZE-APP-015",
"title": "Required App Never Settled — ESP Completion Deferred",
"description": "The IME reported its user-session completion line, but at least one required app stayed pending — without ever failing or even starting to install — so the agent kept deferring the enrollment completion signal. Typically an assignment/requirement problem (requirement rules never met, dependency never satisfied, or the app needs a context that is not available during ESP, e.g. a VPN client waiting for user sign-in to a portal).",
"severity": "high",
"category": "apps",
"version": "1.0.0",
"author": "Autopilot Monitor",
"enabled": true,
"trigger": "correlation",
"baseConfidence": 60,
"confidenceThreshold": 55,
"preconditions": [
{
"source": "event_data",
"eventType": "enrollment_complete",
"operator": "not_exists",
"description": "Suppress when the pending app eventually settled and the enrollment completed — a transient deferral is normal."
},
{
"source": "event_data",
"eventType": "enrollment_failed",
"operator": "not_exists",
"description": "Suppress when the session failed explicitly — the app/ESP failure rules already cover that path; this rule targets the never-finishing case."
}
],
"conditions": [
{
"signal": "completion_deferred",
"source": "event_type",
"eventType": "agent_trace",
"dataField": "message",
"operator": "contains",
"value": "completion signal deferred",
"required": true
},
{
"signal": "apps_pending",
"source": "event_data",
"eventType": "app_tracking_summary",
"dataField": "pending",
"operator": "gte",
"value": "1",
"required": true
},
{
"signal": "pending_app_names",
"source": "event_data",
"eventType": "app_tracking_summary",
"dataField": "pendingNames",
"operator": "exists",
"value": "",
"required": false
}
],
"confidenceFactors": [
{
"signal": "pending_app_names",
"condition": "exists",
"weight": 5
}
],
"explanation": "The Intune Management Extension wrote its user-session completion line, but the agent observed `{{pending}}` required app(s) still pending (`{{pendingNames}}`) and therefore **deferred the enrollment completion signal** — repeatedly, if this happened across several logons or reboots.\n\nA pending app that never transitions to downloading/installing and never fails is almost always an **assignment or requirement problem**, not an install error:\n\n- requirement rules that are never met on this device (OS/architecture/registry/script checks),\n- an unsatisfied dependency or supersedence chain,\n- an app targeted as *required* for the user ESP that needs something unavailable during provisioning (e.g. a VPN client whose portal sign-in only happens after first logon),\n- user-targeted apps on a device where the user identity never fully registered (see the hybrid user-affinity rule if it also fired).",
"remediation": [
{
"title": "Identify and unblock the pending app",
"steps": [
"Check the app names listed in this finding's evidence (pendingNames) — these are the apps the ESP is waiting for.",
"In Intune, review the app's requirement rules and dependencies; test them on the device (IntuneManagementExtension.log logs each requirement evaluation).",
"Decide whether the app really must block the ESP: removing it from the ESP's 'blocking apps' list (or making it not-required during enrollment) unblocks completion immediately.",
"If the app is user-targeted on a hybrid-joined device, verify the user's Entra affinity first — without a signed-in Entra user, user-targeted policy never applies."
]
}
],
"relatedDocs": [
{
"title": "Microsoft Learn: Enrollment Status Page — blocking apps",
"url": "https://learn.microsoft.com/en-us/intune/intune-service/enrollment/windows-enrollment-status"
}
],
"markSessionAsFailedDefault": false,
"tags": [
"apps",
"esp",
"completion",
"assignment",
"pending"
]
},
{
"ruleId": "ANALYZE-CORR-003",
"title": "Proxy Configuration Causing Download Failure",
@@ -1268,7 +1357,7 @@
"description": "Detects when the enrollment session was force-failed by the server-side inactivity timeout (no agent telemetry for the configured SessionTimeoutHours window) without ever completing or explicitly failing.",
"severity": "high",
"category": "enrollment",
"version": "1.0.0",
"version": "1.1.0",
"enabled": true,
"baseConfidence": 80,
"preconditions": [
@@ -1293,9 +1382,26 @@
"operator": "exists",
"value": "",
"required": true
},
{
"signal": "desktop_was_reached",
"source": "event_type",
"eventType": "desktop_arrived",
"operator": "exists",
"value": "",
"required": false
},
{
"signal": "all_tracked_apps_completed",
"source": "event_data",
"eventType": "app_tracking_summary",
"dataField": "isAllCompleted",
"operator": "equals",
"value": "true",
"required": false
}
],
"explanation": "The enrollment session was force-failed by the server-side maintenance sweep after `{{timeoutHours}}` hour(s) of agent inactivity — the device stopped sending telemetry and never reported completion or an explicit failure.\n\nThis usually means the agent process died or the device went offline mid-enrollment (power off, network loss, bluescreen, reimage) rather than a clean enrollment failure. Because there is no terminal `enrollment_failed` event, the more specific app/ESP rules cannot pinpoint a cause — the evidence simply stops at the last event before the gap.",
"explanation": "The enrollment session was force-failed by the server-side maintenance sweep after `{{timeoutHours}}` hour(s) of agent inactivity — the device stopped sending telemetry and never reported completion or an explicit failure.\n\nThis usually means the agent process died or the device went offline mid-enrollment (power off, network loss, bluescreen, reimage) rather than a clean enrollment failure. Because there is no terminal `enrollment_failed` event, the more specific app/ESP rules cannot pinpoint a cause — the evidence simply stops at the last event before the gap.\n\n**If the evidence shows the user desktop was reached and all tracked apps completed**, the device most likely got all its content but the ESP never signaled completion — on hybrid-joined devices the usual culprit is the user session never establishing Entra affinity (Account Setup re-running on every logon). Check whether the hybrid user-affinity finding also fired for this session.",
"remediation": [
{
"title": "Investigate the silent session",
@@ -1306,6 +1412,13 @@
"If the device is reachable, collect the agent + IME logs and re-run enrollment, correlating with the timeout timestamp",
"If many sessions time out in the same window, check for a tenant-wide network/connectivity issue or an Intune service incident"
]
},
{
"title": "Desktop reached and apps done, but no completion",
"steps": [
"Sign in as the affected user and run dsregcmd /status — 'SSO State: AzureAdPrt' must be YES; NO means the user never registered with Entra and the Account Setup ESP will loop",
"Verify Entra Connect syncs both the computer object (userCertificate) and the signing-in user, and that the user's UPN suffix is a verified Entra domain"
]
}
],
"tags": [
@@ -2222,6 +2335,109 @@
"security"
]
},
{
"ruleId": "ANALYZE-ID-004",
"title": "Hybrid Sign-In Never Establishes Entra User Affinity",
"description": "On a hybrid-joined device the real user reached the desktop, but the Autopilot provisioning placeholder stayed active in JoinInfo and the agent repeatedly reported the hybrid sign-in as overdue. The user session never establishes Entra user affinity (no PRT), so the Account Setup ESP re-runs on every logon and the enrollment never completes.",
"severity": "high",
"category": "identity",
"version": "1.0.0",
"author": "Autopilot Monitor",
"enabled": true,
"trigger": "correlation",
"baseConfidence": 60,
"confidenceThreshold": 65,
"preconditions": [
{
"source": "event_data",
"eventType": "enrollment_complete",
"operator": "not_exists",
"description": "Suppress when the session eventually completed — a single overdue-login warning followed by a successful sign-in is normal hybrid latency, not a broken affinity."
}
],
"conditions": [
{
"signal": "hybrid_login_overdue",
"source": "event_type",
"eventType": "hybrid_login_pending",
"operator": "exists",
"value": "",
"required": true
},
{
"signal": "user_desktop_reached",
"source": "event_type",
"eventType": "desktop_arrived",
"operator": "exists",
"value": "",
"required": true
},
{
"signal": "placeholder_still_active",
"source": "event_type",
"eventType": "aad_placeholder_user_detected",
"operator": "exists",
"value": "",
"required": false
}
],
"confidenceFactors": [
{
"signal": "hybrid_login_pending",
"condition": "count >= 2",
"weight": 20
},
{
"signal": "hybrid_login_pending",
"condition": "count >= 3",
"weight": 10
},
{
"signal": "aad_placeholder_user_detected",
"condition": "count >= 3",
"weight": 10
}
],
"explanation": "A real user signed in and reached the desktop, but the device kept reporting the **Autopilot provisioning placeholder** as the active identity in JoinInfo and the hybrid sign-in as **overdue** — across multiple reboots. This means the signed-in user never established **Microsoft Entra user affinity** (no Primary Refresh Token), so:\n\n- the Account Setup ESP page re-appears on every logon,\n- user-targeted required apps and policies cannot settle,\n- the enrollment never reaches completion.\n\nAfter this many hours this is not normal Entra Connect sync latency — something is structurally preventing the user (or the computer object) from registering:\n\n- the computer object's `userCertificate` attribute is not syncing to Entra ID (sync scope / OU filtering),\n- the signing-in user is not synced, or their UPN does not match a verified Entra domain,\n- the device has no line of sight to a domain controller **at logon time**, so the hybrid PRT flow cannot finish,\n- time skew or a proxy blocking `login.microsoftonline.com` / `enterpriseregistration.windows.net` from the user context.",
"remediation": [
{
"title": "Verify user affinity on the device",
"steps": [
"Sign in as the affected user and run: dsregcmd /status — under 'SSO State' the value AzureAdPrt must be YES. NO means the user has no Entra token and this diagnosis is confirmed.",
"Also check 'Device State': AzureAdJoined = YES and DomainJoined = YES are expected for hybrid join.",
"Check Event Viewer: Applications and Services Logs > Microsoft > Windows > User Device Registration > Admin for PRT / registration errors (e.g. event 304/305/362).",
"Enable the gather rules 'Collect dsregcmd join status' so future sessions capture this state automatically."
]
},
{
"title": "Fix the identity pipeline",
"steps": [
"Entra Connect: confirm BOTH the computer OU and the user OU are in the sync scope, and the computer object's userCertificate attribute is being exported.",
"Verify the user's UPN suffix is a verified domain in Entra ID (no .local / mismatched suffix).",
"Ensure domain-controller line of sight at logon from the provisioning network/VLAN (hybrid PRT requires a reachable DC).",
"Check proxy/firewall rules for login.microsoftonline.com, device.login.microsoftonline.com and enterpriseregistration.windows.net from the user context."
]
}
],
"relatedDocs": [
{
"title": "Autopilot Monitor: Hybrid join — late device registration",
"url": "https://docs.autopilotmonitor.com/troubleshooting/hybrid-join-late-device-registration"
},
{
"title": "Microsoft Learn: Troubleshoot hybrid-joined devices",
"url": "https://learn.microsoft.com/en-us/entra/identity/devices/troubleshoot-hybrid-join-windows-current"
}
],
"markSessionAsFailedDefault": false,
"tags": [
"identity",
"hybrid-join",
"entra-id",
"user-affinity",
"esp"
]
},
{
"ruleId": "ANALYZE-OFFICE-001",
"title": "Microsoft 365 Apps Install Failed",
+21
View File
@@ -128,6 +128,27 @@
"oobe"
]
},
{
"ruleId": "GATHER-DEVICE-006",
"title": "Collect dsregcmd join status on overdue hybrid sign-in",
"description": "Runs dsregcmd /status the moment the agent reports a hybrid sign-in as overdue (hybrid_login_pending), capturing the Entra join and registration state at exactly the point where the problem is detected. Complements GATHER-DEVICE-001 (snapshot on entering Account Setup). Note: the agent runs as SYSTEM, so the output shows device join state — the per-user SSO/PRT state still requires running dsregcmd as the signed-in user.",
"category": "device",
"version": "1.0.0",
"author": "Autopilot Monitor",
"enabled": false,
"collectorType": "command_allowlisted",
"target": "dsregcmd /status",
"trigger": "on_event",
"triggerEventType": "hybrid_login_pending",
"outputEventType": "gather_dsregcmd_status",
"outputSeverity": "Info",
"tags": [
"device",
"entra",
"join",
"hybrid"
]
},
{
"ruleId": "GATHER-ENROLL-001",
"title": "MDM enrollment diagnostic events",
+17
View File
@@ -0,0 +1,17 @@
{
"$schema": "../schema/gather-rule.schema.json",
"ruleId": "GATHER-DEVICE-006",
"title": "Collect dsregcmd join status on overdue hybrid sign-in",
"description": "Runs dsregcmd /status the moment the agent reports a hybrid sign-in as overdue (hybrid_login_pending), capturing the Entra join and registration state at exactly the point where the problem is detected. Complements GATHER-DEVICE-001 (snapshot on entering Account Setup). Note: the agent runs as SYSTEM, so the output shows device join state — the per-user SSO/PRT state still requires running dsregcmd as the signed-in user.",
"category": "device",
"version": "1.0.0",
"author": "Autopilot Monitor",
"enabled": false,
"collectorType": "command_allowlisted",
"target": "dsregcmd /status",
"trigger": "on_event",
"triggerEventType": "hybrid_login_pending",
"outputEventType": "gather_dsregcmd_status",
"outputSeverity": "Info",
"tags": ["device", "entra", "join", "hybrid"]
}
@@ -129,7 +129,7 @@ namespace AutopilotMonitor.Functions.Services
["timestamp"] = evt.Timestamp,
["eventType"] = evt.EventType,
["field"] = condition.DataField,
["value"] = fieldValue
["value"] = FormatEvidenceValue(fieldValue)
};
AddDataFieldsToEvidence(evidence, evt, "", "");
return (true, evidence);
@@ -175,7 +175,7 @@ namespace AutopilotMonitor.Functions.Services
["sequence"] = evt.Sequence,
["timestamp"] = evt.Timestamp,
["field"] = condition.DataField,
["value"] = fieldValue
["value"] = FormatEvidenceValue(fieldValue)
};
AddDataFieldsToEvidence(evidence, evt, "", "");
return (true, evidence);
@@ -185,6 +185,21 @@ namespace AutopilotMonitor.Functions.Services
return (false, "no matching data");
}
/// <summary>
/// Evidence values feed the finding UI and {{token}} interpolation, both of which
/// render via ToString() — a raw List would surface as its .NET type name
/// ("System.Collections.Generic.List`1[System.Object]"). Collections are therefore
/// flattened to a comma-joined string; scalars and dictionaries pass through.
/// </summary>
private static object FormatEvidenceValue(object fieldValue)
{
if (fieldValue is string || fieldValue is System.Collections.IDictionary)
return fieldValue;
if (fieldValue is System.Collections.IEnumerable sequence)
return string.Join(", ", sequence.Cast<object>().Select(o => o?.ToString()));
return fieldValue;
}
/// <summary>
/// Evaluates a condition against an ARRAY field on the event (e.g. provisioning_package_scan's
/// <c>artifacts</c>). For each element, the element's <see cref="RuleCondition.ItemField"/>
@@ -931,7 +946,7 @@ namespace AutopilotMonitor.Functions.Services
if (evt.Data == null) return;
// Whitelist: short identifiers only. errorDetail/message removed (can be multi-KB).
var knownFields = new[] { "appId", "appName", "errorPatternId", "errorCode", "exitCode", "status" };
var knownFields = new[] { "appId", "appName", "errorPatternId", "errorCode", "exitCode", "status", "timeoutHours" };
foreach (var field in knownFields)
{