Wrap around the New-MpPerformanceRecording

Why Defender Boys decided to build Invoke-DBDefenderPerformance powershell tool

When you run into performance issues on a Windows endpoint, Microsoft Defender is sometimes part of the conversation.

So why does this happen?

It usually falls back to the fact that modern environments are messy:

  • legacy applications
  • developer tooling
  • self-updating binaries
  • temporary execution paths
  • unsigned components

The Reality of Modern Endpoint Protection

Microsoft Defender today is far more than traditional antivirus.

It includes:

  • real-time protection
  • behavioral monitoring
  • Endpoint Detection & Response (EDR, and if you are looking at all workloads such as identity, data etc we have XDR)
  • script and memory inspection
  • integration with cloud intelligence

All of this is designed to handle both:

  • modern threats
  • and older, less predictable software

That combination is important. Because in many environments, the biggest performance impact doesn’t come from malware – it comes from:

  • complex applications
  • heavy file churn
  • development workloads
  • installers and updaters
  • or software that doesn’t follow modern best practices

Where Things Get Difficult

From a troubleshooting perspective, this creates a challenge.

You might see:

  • CPU spikes in MsMpEng.exe
  • activity from MsSense.exe
  • delays during file operations

But that doesn’t tell you:

  • which files are being scanned
  • why they are being scanned
  • which process triggered the activity
  • or how expensive the scans actually are

Without that visibility, it’s easy to fall into guesswork.

What Microsoft Provides

Microsoft provides built-in tooling for this:

  • New-MpPerformanceRecording
  • Get-MpPerformanceReport

Which allow you to capture:

  • detailed scan activity
  • durations
  • top files and processes
  • scan reasons (like EDRSensor)

The data is there but the format is not very easy to interpret for everyone

  • timestamps are not human-readable
  • durations are in ticks
  • output is deeply nested
  • there’s no prioritization

So while everything you need is technically there, it still takes effort to interpret.

Bridging the Gap

That’s where these functions come in:

  • Invoke-DBDefenderPerformance
  • Convert-DBDefenderPerformanceReport

The idea is simple, take Defender’s detailed trace data and make it usable for real-world analysis. Instead of manually parsing JSON, you get:

  • normalized timings (milliseconds instead of ticks)
  • clear overview of scan activity
  • grouped insights by:
  • scan reason
  • file type
  • path
  • visibility into what’s actually consuming time

This makes it easier to answer questions like:

  • Is this driven by AV scanning or EDR activity?
  • Are specific file types more expensive?
  • Are certain paths generating excessive activity?
  • Is this expected behavior for the workload?
  • Why This Matters

In many cases, Defender is working exactly as intended but it has to operate in environments where:

  • software may be outdated
  • files change frequently
  • large numbers of small files are accessed
  • or applications behave in ways that trigger deeper inspection

Without proper analysis, it’s easy to jump straight to exclusions. That approach can work – but could introduce risks.

A better approach is:

  • Understand what’s happening
  • Identify the actual cost drivers
  • Decide whether tuning is necessary

A typical trace might show:

  • OnDemandScan activity
  • Reason: EDRSensor
  • Files under:
  • AppData\Local\Programs\Microsoft VS Code
  • node_modules
  • Process-based scans (pid:xxxxx)

Defender is simply doing its job – inspecting what could be risky.

The Goal

The purpose of these functions isn’t to reduce protection. It’s to provide clarity. Because once you can see:

  • what is being scanned
  • why it’s being scanned
  • and how much it costs
The tool is published in the following Github repo:
https://github.com/mattiasborg82/PublicTools/blob/main/Defender%20Boys/Defender/Performance/Invoke-DBDefenderPerformance.ps1

Example usage to Create a recording:
Invoke-DBDefenderPerformance -Seconds 900 -Top 50 -Raw -ExportJson
Example usage to Read the report:
$report = Get-MpPerformanceReport -Path "C:\Temp\DefenderPerformance-20260428-095235.etl" -Raw

$summary = Convert-DBDefenderPerformanceReport -Report $report -Top 10 -SlowScanMs 200 -IncludeRaw
$summary | Format-Table -AutoSize

$summary.SlowScans | Format-Table DurationMs, ScanType, Reason, SkipReason, Extension, Path -AutoSize
    $summary.ByReason | Format-Table -AutoSize
    $summary.ByExtension | Format-Table -AutoSize
    $summary.ByParentPath | Format-Table -AutoSize
    $summary.SlowScans |
        Where-Object Reason -eq "EDRSensor" |
        Select-Object DurationMs, ScanType, Extension, Path |
        Format-Table -AutoSize

# Additional analysis example: Check authenticode signatures of slow scans involving executables
    $summary.SlowScans |
        Where-Object { $_.Extension -in ".exe", ".dll" } |
        Select-Object -ExpandProperty Path -Unique |
        ForEach-Object {
            if (Test-Path -LiteralPath $_) {
                Get-AuthenticodeSignature -FilePath $_ |
                    Select-Object Path, Status, StatusMessage, SignerCertificate
            }
        }

Basically, you can now make well-informed decisions in a easy way

#Happy Hunting

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.