@@ -18,7 +18,7 @@ ms.collection:
18
18
description : Admins can learn about the information on the Microsoft Defender for Office 365 Overview dashboard in the Microsoft Defender portal.
19
19
ms.custom :
20
20
ms.service : defender-office-365
21
- ms.date : 07/14 /2025
21
+ ms.date : 07/16 /2025
22
22
appliesto :
23
23
- ✅ <a href="https://learn.microsoft.com/defender-office-365/mdo-about#defender-for-office-365-plan-1-vs-plan-2-cheat-sheet" target="_blank">Microsoft Defender for Office 365 Plan 1 and Plan 2</a>
24
24
- ✅ <a href="https://learn.microsoft.com/defender-xdr/microsoft-365-defender" target="_blank">Microsoft Defender XDR</a>
@@ -56,8 +56,9 @@ The graph on the **Phish / Malware Efficacy** card visually represents the prote
56
56
57
57
- ** Pre-delivery** : Items detected before they reach the recipient's mailbox.
58
58
- ** Post-delivery** : Items removed after the item was delivered to the recipient's mailbox via [ zero-hour auto purge (ZAP)] ( zero-hour-auto-purge.md ) .
59
- - ** Uncaught** : Delivered items that ZAP identified but didn't remove due to them already being remediated . For example:
59
+ - ** Uncaught** : Delivered items that ZAP identified but failed to remove . For example:
60
60
- Admin deletions or remediations.
61
+ - ZAP being disabled for the specific mailboxes.
61
62
- [ Admin submissions] ( submissions-admin.md ) to Microsoft identifying the message as malware or phishing.
62
63
- User deletions.
63
64
- Non-Microsoft security provider deletions.
@@ -256,87 +257,47 @@ Organizations with Defender for Office 365 Plan 2 can use the following query in
256
257
> The numbers might differ slightly due to the different refresh rates for advanced hunting vs. reporting data.
257
258
258
259
``` kusto
259
- // This query by default will take the last 30 days of data.
260
- // The query and calculation can be tweaked to meet individual needs, and will update over time to get incrementally more accurate.
261
- // Ben Harris - Microsoft Defender for Office 365 PM.
262
260
let _startTime = ago(30d);
263
261
let _endTime = now();
264
- // Get all mailflow detected as clean at time of delivery
265
- let EmailEventsClean = materialize(
262
+ let PreDelivery = toscalar(
266
263
EmailEvents
267
- | where Timestamp between (_startTime .. _endTime) and EmailDirection == "Inbound"
268
- | where ThreatTypes !contains "Phish" and ThreatTypes !contains "Malware"
269
- | project NetworkMessageId,ThreatTypes
270
- );
271
- // Get all mailflow detected as phish or malware at time of delivery
272
- let EmailEventsThreats = materialize(
273
- EmailEvents
274
- | where Timestamp between (_startTime .. _endTime) and EmailDirection == "Inbound"
275
- | where ThreatTypes contains "Phish" or ThreatTypes contains "Malware"
264
+ | where Timestamp between (_startTime .. _endTime)
265
+ and EmailDirection == "Inbound"
266
+ and DeliveryLocation in ("Junk folder", "Quarantine")
267
+ and (ThreatTypes contains "Phish" or ThreatTypes contains "Malware")
276
268
| extend MDO_detection = parse_json(DetectionMethods)
277
269
| extend FirstDetection = iif(isempty(MDO_detection), "Clean", tostring(bag_keys(MDO_detection)[0]))
278
270
| extend FirstSubcategory = iif(FirstDetection != "Clean" and array_length(MDO_detection[FirstDetection]) > 0, strcat(FirstDetection, ": ", tostring(MDO_detection[FirstDetection][0])), "No Detection (clean)")
279
- | project NetworkMessageId,FirstDetection,FirstSubcategory,MDO_detection,ThreatTypes
271
+ | summarize PreDelivery = count()
280
272
);
281
- // Get all post delivery ZAP / Redelivery events, and arg_max them to ensure we have the latest verdict to work with for each
282
- let EmailPostDeliveryFiltered = materialize(
273
+ let PostDelivery = toscalar(
283
274
EmailPostDeliveryEvents
284
- | where Timestamp between (_startTime .. datetime_add('day', 7, _endTime))
285
- | where ActionType in ("Malware ZAP","Phish ZAP","Redelivery")
286
- | extend Key = strcat(NetworkMessageId , "-", RecipientEmailAddress)
287
- | summarize arg_max(Timestamp, *) by Key
288
- | project Action,ActionType,ActionResult,ThreatTypes,NetworkMessageId
289
- );
290
- // Optional - get all admin submissions for malware or phish, so we can also count these in the miss bucket.
291
- let CloudAppEventsFiltered = materialize(
292
- CloudAppEvents
293
- | where Timestamp between (_startTime .. datetime_add('day', 7, _endTime))
294
- | where ActionType == "AdminSubmissionSubmitted"
295
- | extend SubmissionType = tostring(parse_json(RawEventData).SubmissionType)
296
- | extend NetworkMessageId = tostring(parse_json(RawEventData).ObjectId)
297
- | where SubmissionType in ("1", "2")
298
- | project SubmissionType,NetworkMessageId
299
- );
300
- // get the number of threats caught in mailflow
301
- let Mal_Phish_Mailflow = toscalar(
302
- EmailEventsThreats
303
- | summarize count()
275
+ | where Timestamp between (_startTime .. _endTime)
276
+ and ActionType in ("Malware ZAP","Phish ZAP")
277
+ and ActionResult in ("Success","UserTriaged")
278
+ | summarize PostDelivery = count()
304
279
);
305
- // get the number of threats caught in mailflow which turned out to be false positives (FPs) so we can correct the calculation
306
- let FP_ZAP = toscalar(
307
- EmailPostDeliveryFiltered
308
- | where ThreatTypes !contains "Phish" and ThreatTypes !contains "Malware" and ActionType == "Redelivery"
309
- | join kind=leftsemi (EmailEventsThreats) on NetworkMessageId
310
- | summarize count()
311
- );
312
- // get the number of threats successfully cleaned up post delivery, ignoring where administrative policy stopped action
313
- let FN_ZAP_Successful = toscalar(
314
- EmailPostDeliveryFiltered
315
- | where ActionType in ("Malware ZAP","Phish ZAP") and ActionResult in ("Success","AdminPolicy")
316
- | join kind=leftsemi (EmailEventsClean) on NetworkMessageId
317
- | summarize count()
318
- );
319
- // get the number of threats unsuccessfully cleaned up post delivery.
320
- let FN_ZAP_Unsuccessful = toscalar(
321
- EmailPostDeliveryFiltered
322
- | where ActionType in ("Malware ZAP","Phish ZAP") and ActionResult !in ("Success","AdminPolicy")
323
- | join kind=leftsemi (EmailEventsClean) on NetworkMessageId
324
- | summarize count()
280
+ let Uncaught = toscalar(
281
+ EmailPostDeliveryEvents
282
+ | where Timestamp between (_startTime .. _endTime)
283
+ and ActionType in ("Malware ZAP","Phish ZAP")
284
+ and ActionResult !in ("Success", "UserTriaged")
285
+ | summarize Uncaught = count()
325
286
);
326
- // join the administrative submissions to clean mailflow to find the additional miss
327
- let FN_Admin_Submissions = toscalar(
328
- CloudAppEventsFiltered
329
- | join kind=rightsemi (EmailEventsClean) on NetworkMessageId
330
- | summarize count()
331
- );
332
- // print each result, and run the calculation to work out effectiveness at time of delivery and post delivery.
333
- union withsource=Table
334
- (print StatisticName="Mal/Phish Mailflow totals - Minus FPs", Value=toreal(Mal_Phish_Mailflow) - toreal(FP_ZAP)),
335
- (print StatisticName="Admin Mal/Phish FNs Submitted", Value=toreal(FN_Admin_Submissions)),
336
- (print StatisticName="Mal/Phish FPs Reverse Zapped", Value=toreal(FP_ZAP)),
337
- (print StatisticName="Mal / Phish Successfully Zapped ", Value=toreal(FN_ZAP_Successful)),
338
- (print StatisticName="Mal / Phish UN-Successfully Zapped ", Value=toreal(FN_ZAP_Unsuccessful)),
339
- (print StatisticName="Effectiveness Post Delivery ", Value=abs(round(((toreal(FN_Admin_Submissions)+toreal(FN_ZAP_Unsuccessful))/(toreal(Mal_Phish_Mailflow)+toreal(FN_ZAP_Successful)+toreal(FN_ZAP_Unsuccessful)+toreal(FN_Admin_Submissions)-toreal(FP_ZAP))*100-100),2))),
340
- (print StatisticName="Effectiveness Pre-Delivery ", Value=abs(round(((toreal(FN_Admin_Submissions)+toreal(FN_ZAP_Unsuccessful)+toreal(FN_ZAP_Successful))/(toreal(Mal_Phish_Mailflow)+toreal(FN_ZAP_Successful)+toreal(FN_ZAP_Unsuccessful)+toreal(FN_Admin_Submissions)-toreal(FP_ZAP))*100-100),2)))
287
+ let PreDeliveryReal = toreal(PreDelivery);
288
+ let PostDeliveryReal = toreal(PostDelivery);
289
+ let UncaughtReal = toreal(Uncaught);
290
+ let Effectiveness = round(
291
+ iif(
292
+ (PreDeliveryReal + PostDeliveryReal + UncaughtReal) == 0,
293
+ 0.0,
294
+ ((PreDeliveryReal + PostDeliveryReal) / (PreDeliveryReal + PostDeliveryReal + UncaughtReal)) * 100.0
295
+ ), 2
296
+ );
297
+ union
298
+ (print StatisticName = "Pre-Delivery Catch ", Value = PreDeliveryReal),
299
+ (print StatisticName = "Post-Delivery Catch ", Value = PostDeliveryReal),
300
+ (print StatisticName = "Failed ZAP / Miss or Uncaught ", Value = UncaughtReal),
301
+ (print StatisticName = "Phish / Malware Efficacy ", Value = Effectiveness)
341
302
| project StatisticName, Value
342
303
```
0 commit comments