Search code examples
powershellxpathevent-viewer

Windows Event Viewer xPath query doesn't work on certain strings. Escape characters?


I am trying to return an event log entry from the Windows security log using xPath (in PowerShell, in Event Viewer UI) and not succeeding.

This query doesn't work, as it returns zero results event though there is are appropriate entries in the log:

Get-WinEvent -FilterXPath "*[EventData[Data[@Name='CommandLine']='-ExecutionPolicy ByPass -File Do-Something.ps1']]" -LogName Security

The syntax of the query seems fine as changing the query value will return the expected results:

Get-WinEvent -FilterXPath "*[EventData[Data[@Name='CommandLine']='\??\C:\Windows\system32\conhost.exe 0xffffffff -ForceV1']]" -LogName Security

Same results if formatted as -FilterXML.

Alternative query strategy works, though is not efficient at all with big logs:

Get-WinEvent -LogName Security | Where-Object -Property Message -match '-ExecutionPolicy ByPass -File Do-Something.ps1'

So it seems that there is something in the xPath query value that is not quite kosher. I don't know what it is. What am I missing?

Here is EventData for the desired hit:

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-a5ba-3e3b0328c30d}" /> 
  <EventID>4688</EventID> 
  <Version>2</Version> 
  <Level>0</Level> 
  <Task>13312</Task> 
  <Opcode>0</Opcode> 
  <Keywords>0x8020000000000000</Keywords> 
  <TimeCreated SystemTime="2020-02-19T15:17:13.982780900Z" /> 
  <EventRecordID>SCRUBBED</EventRecordID> 
  <Correlation /> 
  <Execution ProcessID="4" ThreadID="256" /> 
  <Channel>Security</Channel> 
  <Computer>SCRUBBED</Computer> 
  <Security /> 
  </System>
- <EventData>
  <Data Name="SubjectUserSid">SCRUBBED</Data> 
  <Data Name="SubjectUserName">SCRUBBED</Data> 
  <Data Name="SubjectDomainName">SCRUBBED</Data> 
  <Data Name="SubjectLogonId">SCRUBBED</Data> 
  <Data Name="NewProcessId">SCRUBBED</Data> 
  <Data Name="NewProcessName">C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe</Data> 
  <Data Name="TokenElevationType">%%1937</Data> 
  <Data Name="ProcessId">0x41c</Data> 
  <Data Name="CommandLine">-ExecutionPolicy ByPass -File Do-Something.ps1</Data> 
  <Data Name="TargetUserSid">S-1-0-0</Data> 
  <Data Name="TargetUserName">-</Data> 
  <Data Name="TargetDomainName">-</Data> 
  <Data Name="TargetLogonId">0x0</Data> 
  <Data Name="ParentProcessName">C:\Windows\System32\gpscript.exe</Data> 
  <Data Name="MandatoryLabel">SCRUBBED</Data> 
  </EventData>
  </Event>

Here is EventData for the other hit that works but isn't interesting to me:

- <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
- <System>
  <Provider Name="Microsoft-Windows-Security-Auditing" Guid="{54849625-5478-4994-a5ba-3e3b0328c30d}" /> 
  <EventID>4688</EventID> 
  <Version>2</Version> 
  <Level>0</Level> 
  <Task>13312</Task> 
  <Opcode>0</Opcode> 
  <Keywords>0x8020000000000000</Keywords> 
  <TimeCreated SystemTime="2020-02-19T15:21:21.753690000Z" /> 
  <EventRecordID>SCRUBBED</EventRecordID> 
  <Correlation /> 
  <Execution ProcessID="4" ThreadID="96" /> 
  <Channel>Security</Channel> 
  <Computer>SCRUBBED</Computer> 
  <Security /> 
  </System>
- <EventData>
  <Data Name="SubjectUserSid">SCRUBBED</Data> 
  <Data Name="SubjectUserName">SCRUBBED</Data> 
  <Data Name="SubjectDomainName">SCRUBBED</Data> 
  <Data Name="SubjectLogonId">SCRUBBED</Data> 
  <Data Name="NewProcessId">SCRUBBED</Data> 
  <Data Name="NewProcessName">C:\Windows\System32\conhost.exe</Data> 
  <Data Name="TokenElevationType">%%1936</Data> 
  <Data Name="ProcessId">0x690</Data> 
  <Data Name="CommandLine">\??\C:\Windows\system32\conhost.exe 0xffffffff -ForceV1</Data> 
  <Data Name="TargetUserSid">S-1-0-0</Data> 
  <Data Name="TargetUserName">-</Data> 
  <Data Name="TargetDomainName">-</Data> 
  <Data Name="TargetLogonId">0x0</Data> 
  <Data Name="ParentProcessName">C:\Program Files\Windows Defender\MpCmdRun.exe</Data> 
  <Data Name="MandatoryLabel">SCRUBBED</Data> 
  </EventData>
  </Event>

Solution

  • Enabling command line process auditing here to reproduce this: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/component-updates/command-line-process-auditing

    Searching for the NewProcessName first:

    $a = Get-WinEvent -FilterXPath "*[EventData[Data[@Name='NewProcessName']='C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe']]" Security
    

    And looking at the xml:

    $a[1] | foreach { $xml = [xml]$_.toxml(); $xml.event.eventdata.data }
    
    Name               #text
    ----               -----
    SubjectUserSid     S-1-5-21-1528843147-373324174-1919417755-1001
    SubjectUserName    admin
    SubjectDomainName  DESKTOP-JQ7B7RP
    SubjectLogonId     0x31db1a
    NewProcessId       0x7c4
    NewProcessName     C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
    TokenElevationType %%1937
    ProcessId          0x19d4
    CommandLine         -ExecutionPolicy ByPass -File do-something.ps1
    TargetUserSid      S-1-0-0
    TargetUserName     -
    TargetDomainName   -
    TargetLogonId      0x0
    ParentProcessName  C:\Windows\System32\gpscript.exe
    MandatoryLabel     S-1-16-12288
    

    It looks like there's strangely a space at the beginning and the end of the CommandLine property. The xml text is trimmed in event viewer. The spaces are still there with $xml.save('file.xml').

    $a[1] | foreach { $xml = [xml]$_.toxml(); $xml.event.eventdata.data } | 
      where '#text' -match bypass | % { 'x' + $_.'#text' + 'x' }
    
    x -ExecutionPolicy ByPass -File do-something.ps1 x
    

    I ran this script as a group policy powershell login script.

    Thus after adding the extra spaces, the nested predicate xpath becomes:

    Get-WinEvent -FilterXPath "*[EventData[Data[@Name='CommandLine']=' -executionpolicy bypass -file do-something.ps1 ']]" Security
    
    
       ProviderName: Microsoft-Windows-Security-Auditing
    
    TimeCreated                     Id LevelDisplayName Message
    -----------                     -- ---------------- -------
    2/21/2020 3:16:13 PM          4688 Information      A new process has been created....
    2/21/2020 3:16:06 PM          4688 Information      A new process has been created....
    2/21/2020 3:03:24 PM          4688 Information      A new process has been created....
    2/21/2020 2:54:16 PM          4688 Information      A new process has been created....
    

    Alternative less "nested" xpath expressions. Functions like text() or substring() can't be used with windows logs, or "//" or "/Event", for some reason.

    get-winevent security -FilterXPath "*/EventData/Data[@Name='CommandLine']=' -ExecutionPolicy ByPass -File Do-Something.ps1 '"
    get-winevent security -FilterXPath "*/*/*[@Name='CommandLine']=' -ExecutionPolicy ByPass -File Do-Something.ps1 '"
    get-winevent security -FilterXPath "Event/EventData/Data[@Name='CommandLine']=' -ExecutionPolicy ByPass -File Do-Something.ps1 '"
    

    In powershell 6 and above this can be reduced to:

    get-winevent @{logname = 'security'; commandline = ' -executionpolicy bypass -file do-something.ps1 ' }