Search code examples
xpathwindows-task-scheduler

Windows Task Scheduler XPath for filtering event on hour of day


I'm creating a custom event filter in order to trigger a task from Windows Task Scheduler. I'm needing to select my event only if it occurs before x o'clock.

Here's the portion of the event XML that I care about:

<Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
  <System>
    <Provider Name="acvpnagent" /> 
    <EventID Qualifiers="25600">2039</EventID> 
    <TimeCreated SystemTime="2021-11-01T04:24:49.6333217Z" /> 
    <Channel>Cisco AnyConnect Secure Mobility Client</Channel> 
  </System>
</Event>

So far I have the following XPath, but it is missing the time constraint:

<QueryList>
  <Query Id="0" Path="Cisco AnyConnect Secure Mobility Client">
    <Select Path="Cisco AnyConnect Secure Mobility Client">*[System[Provider[@Name='acvpnagent'] and (EventID=2039)</Select>
  </Query>
</QueryList>

Is it possible to add a condition for TimeCreated to satisfy my constraint? And am I still limited to XPath 1.0 on Windows 10?


Solution

  • This XPath 1.0 expression will select Event nodes as follows

    //x:Event[./x:System/x:Provider/@Name="acvpnagent" and ./x:System/x:EventID=2039 and number(translate(substring-before(substring-after(./x:System/x:TimeCreated/@SystemTime,"T"),"."),":","")) < 110000]
    

    This XPath will select nodes according to the criteria in the OP's sample

    //x:Event[./x:System/x:Provider/@Name="acvpnagent" and ./x:System/x:EventID=2039]
    

    While this XPath part will add a filter by time of day

    number(translate(substring-before(substring-after(./x:System/x:TimeCreated/@SystemTime,"T"),"."),":","")) < 110000
    

    Date handling
    Given an ISO-8601 date as 2021-11-01T04:24:49.6333217Z, this would return the HH:mm:ss part

    substring-before(substring-after(./x:System/x:TimeCreated/@SystemTime,"T"),".")
    

    Result: 04:24:49

    Let's remove semicolons:

    translate(substring-before(substring-after(./x:System/x:TimeCreated/@SystemTime,"T"),"."),":","")
    

    Result: 042449

    Finally, make it a number and compare with desired limit

    number(translate(substring-before(substring-after(./x:System/x:TimeCreated/@SystemTime,"T"),"."),":","")) < 110000
    

    Given this XML sample

    <root>
    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
      <System>
        <Provider Name="acvpnagent" /> 
        <EventID Qualifiers="25600">2039</EventID> 
        <TimeCreated SystemTime="2021-11-01T04:24:49.6333217Z" /> 
        <Channel>Cisco AnyConnect Secure Mobility Client</Channel> 
      </System>
    </Event>
    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
      <System>
        <Provider Name="acvpnagent" /> 
        <EventID Qualifiers="25600">2039</EventID> 
        <TimeCreated SystemTime="2021-11-01T08:24:49.6333217Z" /> 
        <Channel>Cisco AnyConnect Secure Mobility Client</Channel> 
      </System>
    </Event>
    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
      <System>
        <Provider Name="acvpnagent" /> 
        <EventID Qualifiers="25600">2039</EventID> 
        <TimeCreated SystemTime="2021-11-01T11:24:49.6333217Z" /> 
        <Channel>Cisco AnyConnect Secure Mobility Client</Channel> 
      </System>
    </Event>
    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
      <System>
        <Provider Name="acvpnagent" /> 
        <EventID Qualifiers="25600">2039</EventID> 
        <TimeCreated SystemTime="2021-11-01T22:24:49.6333217Z" /> 
        <Channel>Cisco AnyConnect Secure Mobility Client</Channel> 
      </System>
    </Event>
    </root>
    

    Find events that match the criteria and occured before 11:00:00 using this XPath

    //x:Event[./x:System/x:Provider/@Name="acvpnagent" and ./x:System/x:EventID=2039 and number(translate(substring-before(substring-after(./x:System/x:TimeCreated/@SystemTime,"T"),"."),":","")) < 110000]
    

    Result:

    echo -e 'setns x=http://schemas.microsoft.com/win/2004/08/events/event\ncat //x:Event[./x:System/x:Provider/@Name="acvpnagent" and ./x:System/x:EventID=2039 and number(translate(substring-before(substring-after(./x:System/x:TimeCreated/@SystemTime,"T"),"."),":","")) < 110000]' | xmllint --shell tmp.xml 
    / > setns x=http://schemas.microsoft.com/win/2004/08/events/event
    / > cat //x:Event[./x:System/x:Provider/@Name="acvpnagent" and ./x:System/x:EventID=2039 and number(translate(substring-before(substring-after(./x:System/x:TimeCreated/@SystemTime,"T"),"."),":","")) < 110000]
     -------
    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
      <System>
        <Provider Name="acvpnagent"/> 
        <EventID Qualifiers="25600">2039</EventID> 
        <TimeCreated SystemTime="2021-11-01T04:24:49.6333217Z"/> 
        <Channel>Cisco AnyConnect Secure Mobility Client</Channel> 
      </System>
    </Event>
     -------
    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
      <System>
        <Provider Name="acvpnagent"/> 
        <EventID Qualifiers="25600">2039</EventID> 
        <TimeCreated SystemTime="2021-11-01T08:24:49.6333217Z"/> 
        <Channel>Cisco AnyConnect Secure Mobility Client</Channel> 
      </System>
    </Event>
    / >
    

    If a full date is used for comparison, this would be the XPath expression

    //x:Event[./x:System/x:Provider/@Name="acvpnagent" and ./x:System/x:EventID=2039 and number(translate(substring-before(./x:System/x:TimeCreated/@SystemTime,"."),"T:-","")) < 20211101110000]
    

    Note 1: expressions start with ./ to make evaluation in the current node context.
    Note 2: I don't have Windows to test but XPath 1.0 is mostly independent of the language/OS so it should work. The OP would need to add namespace handling to his implementation or remove the x: namespace prefix from expressions in this answer.