Microsoft Defender for Endpoint Device Health
Microsoft just announced the public preview of the new Device Health Reporting for Microsoft Defender for Endpoint and I already love it. It not only gives you deeper insights into your environment but also adds much needed information like engine version, last scan time, and scan results.
Sensor health & OS
This overview gives you insights into deployed OS versions, the current state of the sensor health and for Windows 10 there is an extra section that shows the different releases deployed in your environment.
Sadly it lacks the same for Windows 11, which I hope the product group will add for general availability.
If you select one of the different health states or OS versions the MDE portal will redirect to you to the device overview with the correct filters already applied.
Microsoft Defender Antivirus health
This is even more helpful, since it shows you relevant information about the agent versions in the field. Since there are three different update types to Microsoft Defender it is easy to misconfigure one of them. Now you can see where the gaps in your environment are.
And if you click on either one of those nice colorful bars, it will open a flyout blade on the right side where you can see the list of machines and export this list for future refence.
Advanced hunting
But the best part of this release for me, is not the fancy graphics and bar-charts but it’s the information gathered in the backend and provided as part of the DeviceTvmInfoGathering
Advanced hunting table. So let’s pop the hood open and see what we information is hidden there.
DeviceTvmInfoGathering
The table itself has only a few columns
- Timestamp
- LastSeenTime
- DeviceId
- DeviceName
- OSPlatform
- AdditionalFields
The first five are self explanatory, but AdditionalFields
is very interesting with this table.
DeviceTvmInfoGathering
| project-away Timestamp, LastSeenTime, DeviceId, DeviceName
| limit 10
As you can see there is some familiar information showing up. Looking closer there are 43 different rows hidden in this field. By far not all of them contain values and it also seems to depend on the OS version and OS type which keys have values.
In my demo environment I found that all of the devices contain additional information about the Antivirus engine. Using the bag_unpack
function in KQL you can easily convert those values in “propper” rows. I filtered out the ones that contain no AV data in this example.
DeviceTvmInfoGathering
| project-away Timestamp, LastSeenTime, DeviceId, DeviceName
| evaluate bag_unpack(AdditionalFields)
| where isnotempty( AvEnginePublishTime )
| limit 10
As you can see there are many different properties available, some of them not exposed in the report. Here are a few ideas to start with.
Device control minimum version check
What to use device control in your environment? Better have at least version 4.18.2107
installed on all Windows 10 and Windows 11 devices.
DeviceTvmInfoGathering
| extend AdditionalFields = parse_json(AdditionalFields)
| extend AvPlatformVersion = tostring(AdditionalFields.["AvPlatformVersion"])
| project-away AdditionalFields
| where OSPlatform startswith "Windows"
| where parse_version(AvPlatformVersion) < parse_version("4.18.2107")
Gradual rollout channels
Are you using the gradual rollout channels to manage engine, platform and signature rollout waves? Check which device is assigned to which ring.
let AvModeDescription = dynamic({"0":"Normal", "1":"Passive", "4":"EDR Block"});
let RingDescription = dynamic({ "2":"Beta", "3":"Preview", "4":"Staged", "5":"Default-Manual", "6":"Critical: Time Delay"});
DeviceTvmInfoGathering
| extend AdditionalFields = parse_json(AdditionalFields)
| extend AvEngineVersion = tostring(AdditionalFields.["AvEngineVersion"])
| extend AvPlatformVersion = tostring(AdditionalFields.["AvPlatformVersion"])
| extend AvMode = tostring(AvModeDescription[tostring(AdditionalFields.["AvMode"])])
| where isnotempty( AvMode )
| extend AvEngineRing = tostring(RingDescription[tostring(AdditionalFields.["AvEngineRing"])])
| extend AvEngineRing = iff(isempty(AvEngineRing),"Default",AvEngineRing)
| extend AvSignatureRing = tostring(RingDescription[tostring(AdditionalFields.["AvSignatureRing"])])
| extend AvSignatureRing = iff(isempty(AvSignatureRing),"Default",AvSignatureRing)
| extend AvPlatformRing = tostring(RingDescription[tostring(AdditionalFields.["AvPlatformRing"])])
| extend AvPlatformRing = iff(isempty(AvPlatformRing),"Default",AvPlatformRing)
| project-away AdditionalFields, Timestamp, LastSeenTime, DeviceId
Antivirus not in normal mode
Are there any devices in your environment not running in “Normal” AV mode? Devices running in passive mode, even if EDR block mode is configured, could mean that the connection to cloud protection service is impaired.
let AvModeDescription = dynamic({"0":"Normal", "1":"Passive", "4":"EDR Block"});
DeviceTvmInfoGathering
| extend AdditionalFields = parse_json(AdditionalFields)
| extend AvEngineVersion = tostring(AdditionalFields.["AvEngineVersion"])
| extend AvPlatformVersion = tostring(AdditionalFields.["AvPlatformVersion"])
| extend AvMode = tostring(AvModeDescription[tostring(AdditionalFields.["AvMode"])])
| where isnotempty( AvMode ) and AvMode != "Normal"
| project-away AdditionalFields, Timestamp, LastSeenTime, DeviceId, DeviceName
| summarize Count=count() by AvMode
Conclusion
As you can see this table has a lot to offer and when you look closely you will find other information that might interest you. It’s great to see that Microsoft makes this data available in advanced hunting because this gives you the power to create your own datasets suited for your needs.