Skip to content

Instantly share code, notes, and snippets.

@kmahyyg
Last active March 16, 2026 05:49
Show Gist options
  • Select an option

  • Save kmahyyg/13ceb3feeb9f16290af6bff5dd3fe75b to your computer and use it in GitHub Desktop.

Select an option

Save kmahyyg/13ceb3feeb9f16290af6bff5dd3fe75b to your computer and use it in GitHub Desktop.

Revisions

  1. kmahyyg revised this gist Mar 16, 2026. 1 changed file with 0 additions and 10 deletions.
    10 changes: 0 additions & 10 deletions DefenderDLPTrace.ps1
    Original file line number Diff line number Diff line change
    @@ -11,7 +11,6 @@ $script:DDLP_EtlPath = Join-Path $script:DDLP_Root 'DefenderDLPTrace.etl'
    $script:DDLP_ProfileId = 'DefenderDLPTrace.Verbose'

    $script:DDLP_ExpectedIds = @{
    'Microsoft-Antimalware-RTP' = @(22,23,24)
    'Microsoft-Antimalware-Service' = @(21,52,53,54)
    }

    @@ -34,14 +33,6 @@ function New-DefenderDLPTraceProfile {
    <MaximumFileSize Value="128" FileMode="Circular" />
    </EventCollector>
    <EventProvider Id="EP_AntimalwareRTP" Name="Microsoft-Antimalware-RTP">
    <EventFilters FilterIn="true">
    <!-- EventId Value="22"/ -->
    <EventId Value="23"/>
    <EventId Value="24"/>
    </EventFilters>
    </EventProvider>
    <EventProvider Id="EP_AntimalwareService" Name="Microsoft-Antimalware-Service">
    <EventFilters FilterIn="true">
    <!-- EventId Value="21"/ -->
    @@ -59,7 +50,6 @@ function New-DefenderDLPTraceProfile {
    <Collectors>
    <EventCollectorId Value="EC_DefenderDLP">
    <EventProviders>
    <EventProviderId Value="EP_AntimalwareRTP"/>
    <EventProviderId Value="EP_AntimalwareService"/>
    </EventProviders>
    </EventCollectorId>
  2. kmahyyg revised this gist Mar 7, 2026. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion DefenderDLPTrace.ps1
    Original file line number Diff line number Diff line change
    @@ -25,7 +25,7 @@ function New-DefenderDLPTraceProfile {

    $wprp = @'
    <?xml version="1.0" encoding="utf-8"?>
    <WindowsPerformanceRecorder Version="1.0" Author="Patrick Yang">
    <WindowsPerformanceRecorder Version="1.0" Author="GPT-Codex-kmahyyg">
    <Profiles>
    <EventCollector Id="EC_DefenderDLP" Name="Defender DLP Event Collector">
  3. kmahyyg revised this gist Mar 7, 2026. 1 changed file with 6 additions and 5 deletions.
    11 changes: 6 additions & 5 deletions DefenderDLPTrace.ps1
    Original file line number Diff line number Diff line change
    @@ -25,25 +25,26 @@ function New-DefenderDLPTraceProfile {

    $wprp = @'
    <?xml version="1.0" encoding="utf-8"?>
    <WindowsPerformanceRecorder Version="1.0" Author="GPT-Codex-kmahyyg">
    <WindowsPerformanceRecorder Version="1.0" Author="Patrick Yang">
    <Profiles>
    <EventCollector Id="EC_DefenderDLP" Name="Defender DLP Event Collector">
    <BufferSize Value="128"/>
    <Buffers Value="256"/>
    <BufferSize Value="64"/>
    <Buffers Value="128"/>
    <MaximumFileSize Value="128" FileMode="Circular" />
    </EventCollector>
    <EventProvider Id="EP_AntimalwareRTP" Name="Microsoft-Antimalware-RTP">
    <EventFilters FilterIn="true">
    <EventId Value="22"/>
    <!-- EventId Value="22"/ -->
    <EventId Value="23"/>
    <EventId Value="24"/>
    </EventFilters>
    </EventProvider>
    <EventProvider Id="EP_AntimalwareService" Name="Microsoft-Antimalware-Service">
    <EventFilters FilterIn="true">
    <EventId Value="21"/>
    <!-- EventId Value="21"/ -->
    <EventId Value="52"/>
    <EventId Value="53"/>
    <EventId Value="54"/>
  4. kmahyyg revised this gist Mar 7, 2026. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion DefenderDLPTrace.ps1
    Original file line number Diff line number Diff line change
    @@ -25,7 +25,7 @@ function New-DefenderDLPTraceProfile {

    $wprp = @'
    <?xml version="1.0" encoding="utf-8"?>
    <WindowsPerformanceRecorder Version="1.0" Author="Patrick Yang">
    <WindowsPerformanceRecorder Version="1.0" Author="GPT-Codex-kmahyyg">
    <Profiles>
    <EventCollector Id="EC_DefenderDLP" Name="Defender DLP Event Collector">
  5. kmahyyg created this gist Mar 7, 2026.
    172 changes: 172 additions & 0 deletions DefenderDLPTrace.ps1
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,172 @@
    #requires -RunAsAdministrator
    Set-StrictMode -Version Latest
    $ErrorActionPreference = 'Stop'

    # -------------------------------
    # Static config (non-interactive friendly)
    # -------------------------------
    $script:DDLP_Root = 'C:\Windows\TEMP'
    $script:DDLP_WprpPath = Join-Path $script:DDLP_Root 'DefenderDLPTrace.wprp'
    $script:DDLP_EtlPath = Join-Path $script:DDLP_Root 'DefenderDLPTrace.etl'
    $script:DDLP_ProfileId = 'DefenderDLPTrace.Verbose'

    $script:DDLP_ExpectedIds = @{
    'Microsoft-Antimalware-RTP' = @(22,23,24)
    'Microsoft-Antimalware-Service' = @(21,52,53,54)
    }

    function New-DefenderDLPTraceProfile {
    [CmdletBinding()]
    param()

    if (-not (Test-Path $script:DDLP_Root)) {
    New-Item -Path $script:DDLP_Root -ItemType Directory -Force | Out-Null
    }

    $wprp = @'
    <?xml version="1.0" encoding="utf-8"?>
    <WindowsPerformanceRecorder Version="1.0" Author="Patrick Yang">
    <Profiles>
    <EventCollector Id="EC_DefenderDLP" Name="Defender DLP Event Collector">
    <BufferSize Value="128"/>
    <Buffers Value="256"/>
    </EventCollector>
    <EventProvider Id="EP_AntimalwareRTP" Name="Microsoft-Antimalware-RTP">
    <EventFilters FilterIn="true">
    <EventId Value="22"/>
    <EventId Value="23"/>
    <EventId Value="24"/>
    </EventFilters>
    </EventProvider>
    <EventProvider Id="EP_AntimalwareService" Name="Microsoft-Antimalware-Service">
    <EventFilters FilterIn="true">
    <EventId Value="21"/>
    <EventId Value="52"/>
    <EventId Value="53"/>
    <EventId Value="54"/>
    </EventFilters>
    </EventProvider>
    <Profile Id="DefenderDLPTrace.Verbose.File"
    Name="DefenderDLPTrace"
    Description="Capture only selected Defender DLP Event IDs"
    DetailLevel="Verbose"
    LoggingMode="File">
    <Collectors>
    <EventCollectorId Value="EC_DefenderDLP">
    <EventProviders>
    <EventProviderId Value="EP_AntimalwareRTP"/>
    <EventProviderId Value="EP_AntimalwareService"/>
    </EventProviders>
    </EventCollectorId>
    </Collectors>
    </Profile>
    </Profiles>
    </WindowsPerformanceRecorder>
    '@

    Set-Content -Path $script:DDLP_WprpPath -Value $wprp -Encoding UTF8
    return $script:DDLP_WprpPath
    }

    function Start-DefenderDLPTrace {
    [CmdletBinding()]
    param(
    [switch]$OverwriteEtl
    )

    if (-not (Get-Command wpr.exe -ErrorAction SilentlyContinue)) {
    throw "wpr.exe not found."
    }

    $wprpPath = New-DefenderDLPTraceProfile

    if ($OverwriteEtl -and (Test-Path $script:DDLP_EtlPath)) {
    Remove-Item -Path $script:DDLP_EtlPath -Force
    }

    # Best-effort cleanup; ignore failure if no active session
    try { & wpr.exe -cancel | Out-Null } catch { }

    $profileArg = "$wprpPath!$($script:DDLP_ProfileId)"
    & wpr.exe -start $profileArg -filemode | Out-Null

    [pscustomobject]@{
    Action = 'Start'
    Success = $true
    Profile = $profileArg
    EtlPath = $script:DDLP_EtlPath
    Timestamp = (Get-Date).ToString('o')
    }
    }

    function Stop-DefenderDLPTrace {
    [CmdletBinding()]
    param(
    [switch]$SkipValidation
    )

    if (-not (Get-Command wpr.exe -ErrorAction SilentlyContinue)) {
    throw "wpr.exe not found."
    }

    & wpr.exe -stop $script:DDLP_EtlPath | Out-Null

    if (-not (Test-Path $script:DDLP_EtlPath)) {
    throw "ETL not found after stop: $($script:DDLP_EtlPath)"
    }

    if ($SkipValidation) {
    return [pscustomobject]@{
    Action = 'Stop'
    Success = $true
    Validated = $false
    EtlPath = $script:DDLP_EtlPath
    Timestamp = (Get-Date).ToString('o')
    }
    }

    $countsMap = @{} # key = "Provider|EventId" ; value = count
    $totalEvents = 0

    Get-WinEvent -Path $script:DDLP_EtlPath -Oldest | ForEach-Object {
    $totalEvents++
    $provider = $_.ProviderName
    $id = [int]$_.Id
    $key = "$provider|$id"
    if ($countsMap.ContainsKey($key)) { $countsMap[$key]++ } else { $countsMap[$key] = 1 }
    }

    $counts = @(foreach ($k in $countsMap.Keys) {
    $p = $k.Split('|',2)[0]
    $i = [int]$k.Split('|',2)[1]
    [pscustomobject]@{
    Provider = $p
    EventId = $i
    Count = $countsMap[$k]
    }
    }) | Sort-Object Count -Descending

    $unexpected = @(foreach ($row in $counts) {
    if ($script:DDLP_ExpectedIds.ContainsKey($row.Provider) -and
    ($row.EventId -notin $script:DDLP_ExpectedIds[$row.Provider])) {
    $row
    }
    })

    [pscustomobject]@{
    Action = 'Stop'
    Success = $true
    Validated = $true
    ValidationPassed = ($unexpected.Count -eq 0)
    EtlPath = $script:DDLP_EtlPath
    TotalEvents = $totalEvents
    Summary = $counts
    Unexpected = @($unexpected)
    Timestamp = (Get-Date).ToString('o')
    }
    }