none
Xpath filter syntax RRS feed

  • Question

  • Hi all

    I've got an xpath query that filters the Directory Services event log for 1644 events.  I'm trying to narrow down the query so that it searches for specific source IP addresses.  These are contained in the Event data in the XML, e.g.


    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
      <System>
        <Provider Name="Microsoft-Windows-ActiveDirectory_DomainService" Guid="{0e8478c5-3605-4e8c-8497-1e730c959516}" EventSourceName="NTDS General" />
        <EventID Qualifiers="16384">1644</EventID>
        <Version>0</Version>
        <Level>4</Level>
        <Task>15</Task>
        <Opcode>0</Opcode>
        <Keywords>0x8080000000000000</Keywords>
        <TimeCreated SystemTime="2009-04-17T03:30:07.520Z" />
        <EventRecordID>14569</EventRecordID>
        <Correlation />
        <Execution ProcessID="648" ThreadID="1568" />
        <Channel>Directory Service</Channel>
        <Computer>mydc.ad.local</Computer>
        <Security UserID="S-1-5-21-854245398-152049171-725345543-31623" />
      </System>
      <EventData>
        <Data>DC=ad,DC=local</Data>
        <Data> ( &amp;  (objectCategory=CN=Group,CN=Schema,CN=Configuration,DC=ad,DC=local)  (objectSid=S-1-5-21-854245398-152049171-725345543-22738) ) </Data>
        <Data>1</Data>
        <Data>1</Data>
        <Data>10.200.137.145:2935 </Data>
        <Data>subtree</Data>
        <Data>groupType</Data>
        <Data>
        </Data>
      </EventData>
    </Event>

    Here's the xpath query I am using.

    <QueryList>
      <Query Id="0" Path="Directory Service">
        <Select Path="Directory Service">*[System[(Level=4 or Level=0) and (EventID=1644)]] and *[EventData[Data[5]='10.200.137.145:2935 ']]</Select>
      </Query>
    </QueryList>

    This works great, but I want to be able to filter using just the IP address, i.e. without the port number.  I have done some reading up on xpath and it looks like I should be able to use the "starts-with" function to specify just the IP address.  I've tried various forms of the syntax, but haven't cracked it yet.  Here's an example of one of my failed attempts.

    <QueryList>
      <Query Id="0" Path="Directory Service">
        <Select Path="Directory Service">*[System[(Level=4 or Level=0) and (EventID=1644)]] and *[EventData[starts-with(Data[5],'10.200.137.145')]]</Select>
      </Query>
    </QueryList>

    Can anyone assist with the query syntax?

    Thanks
    Tony
    Tuesday, April 21, 2009 2:18 AM

Answers

  • Hi Tony,

    The problem is related to the setting of default namespace.
    Here are two links for your reference:
    http://support.microsoft.com/kb/288147
    http://support.microsoft.com/kb/313372

    In your case, your xml has defined "xmlns="http://schemas.microsoft.com/win/2004/08/events/event".
    There are three approaches to solve.
    First approach :
     - Give a prefix in the Xml file
        e.g. xmlns:myevent="http://schemas.microsoft.com/win/2004/08/events/event
     - Then, in the javascript code, use
        xml.setProperty("SelectionNamespaces", "xmlns:myevent='http://schemas.microsoft.com/win/2004/08/events/event'");

    Second approach:
     - In the javascript code, use
        xml.setProperty("SelectionNamespaces", "xmlns:myevent='http://schemas.microsoft.com/win/2004/08/events/event'");
     - The query statement changes to
        var nodeList = xml.selectNodes("*[ myevent:System[(myevent:Level=4 or myevent:Level=0) and (myevent:EventID=1644)]  and myevent:EventData[starts-with(myevent:Data[5],'10.200.137.145')]  ]");

    Third approach:
     - Remove the namespace in xml file
       i.e. xmlns="http://schemas.microsoft.com/win/2004/08/events/event
     - In the javascript code, the statement below is not necessary.
        xml.setProperty("SelectionNamespaces", "xmlns='http://schemas.microsoft.com/win/2004/08/events/event'");
    • Proposed as answer by Ivan Ting Friday, April 24, 2009 5:27 PM
    • Marked as answer by Tony MurrayMVP Monday, April 27, 2009 8:49 PM
    Friday, April 24, 2009 5:27 PM

All replies

  • Your XPath expression looks good, and I'm not sure where is wrong. You can try and error, by providing an empty string to starts-with() function first, which is equivalent with your previous XPath query:

    <QueryList>
      <Query Id="0" Path="Directory Service">
        <Select Path="Directory Service">*[System[(Level=4 or Level=0) and (EventID=1644)]] and *[EventData[starts-with(Data[5], '')]]</Select>
      </Query>
    </QueryList>

    If that does not work, I will suspect that your application that handles such XPath query does not support starts-with() function.


    Your potential, our passion.
    • Proposed as answer by Chen Zhuo Wednesday, April 22, 2009 12:52 AM
    Tuesday, April 21, 2009 3:13 AM
  • You may try this query string "*[ System[(Level=4 or Level=0) and (EventID=1644)]  and EventData[starts-with(Data[5],'10.200.137.145')]  ]"

    Below is the javacript to retrieve the node:

    xmlFile = "event.xml"
    
    
    
    var xml = new ActiveXObject("MSXML2.DOMDocument.6.0");
    
    xml.setProperty("SelectionNamespaces", "xmlns='http://schemas.microsoft.com/win/2004/08/events/event'");
    
    
    
    xml.async = false;
    
    xml.load(xmlFile);
    
    
    
    // Query 1
    
    var nodeList = xml.selectNodes("*[ System[(Level=4 or Level=0) and (EventID=1644)]  and EventData[starts-with(Data[5],'10.200.137.145')]  ]");    
    
    // Query 2
    
    // var nodeList = xml.selectNodes("*[ System[(Level=4 or Level=0) and (EventID=1644)]  and EventData[Data[5]='10.200.137.145:2935 ']  ]");
    
    WScript.Echo(nodeList.length + " nodes returned");
    
    WScript.Echo("---------------------");
    
    for(j=0; j<nodeList.length; j++) WScript.Echo(nodeList[j].text);
    
    

    Hope it help!!

    Tuesday, April 21, 2009 5:49 AM
  • Hi Chen

    Thanks for you reply.

    I've tried your method with the empty string and I get the response "The specified query is invalid".  As you indicate, it seems that the application (Windows Event Viewer) doesn't support the starts_with() function.  A pity really, as it would be useful.

    Tony
    Tuesday, April 21, 2009 10:22 PM
  • Thanks Ivan

    I couldn't get either of your queries (Query 1 and Query 2) to work with my XML file.  I just get "0 nodes returned" in output.  In fact the only way I could get any nodes returned at all was to change the query to:

    var nodeList = xml.selectNodes("\*");

    This just returned 1 node ("Event") and the associated values.  In fact all of the values from all nodes.

    I'm not a developer, so I'm sure it's something that I am doing wrong.

    Tony


    Tuesday, April 21, 2009 10:32 PM
  • Hi Tony,

    I have used the xml from your first post. So this is the one your application working on?
    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
        ...........
    </Event>
    Adn, I tried my code on Msxml3, 4 and 6 which can retrive the node. So, which msxml version you use?
    In Msxml3, if you want to use the starts-with funciton, you have to add the following statement before loading the xml file.

    "xmlDoc.setProperty("SelectionLanguage","XPath");"


    Wednesday, April 22, 2009 1:18 AM
  • Hi Ivan

    Strange.  It should work. :-(

    Here's my environment.

    Windows Server 2008 Standard Edition x64
    .Net Framework 3.5 (which gives me msxml6, right?)

    I copied your code to Notepad and saved as c:\util\event.js
    I copied my XML to Notepad and saved as c:\util\event.xml
    I opened a command prompt, changed to c:\util and typed "cscript event.js" 
    Output is:

    0 nodes returned
    ---------------------

    One thought I had was that copy/paste from web sometimes changes the character sets.  I've replaced all the obvious characters that can cause problems (" and '), but it didn't make any difference.

    I've pasted my event.js code below, just in case I've missed something.

    xmlFile = "event.xml"
    
    
    
    var xml = new ActiveXObject("MSXML2.DOMDocument.6.0");
    
    xml.setProperty("SelectionNamespaces", "xmlns='http://schemas.microsoft.com/win/2004/08/events/event'");
    
    
    
    xml.async = false;
    
    xml.load(xmlFile);
    
    
    
    // Query 1
    
    var nodeList = xml.selectNodes("*[ System[(Level=4 or Level=0) and (EventID=1644)]  and EventData[starts-with(Data[5],'10.200.137.145')]  ]");    
    
    // Query 2
    
    // var nodeList = xml.selectNodes("*[ System[(Level=4 or Level=0) and (EventID=1644)]  and EventData[Data[5]='10.200.137.145:2935 ']  ]");
    
    WScript.Echo(nodeList.length + " nodes returned");
    
    WScript.Echo("---------------------");
    
    for(j=0; j<nodeList.length; j++) WScript.Echo(nodeList[j].text);
    
    Thanks for your help.

    Tony
    Wednesday, April 22, 2009 1:46 AM
  • Hi Tony,

    The problem is related to the setting of default namespace.
    Here are two links for your reference:
    http://support.microsoft.com/kb/288147
    http://support.microsoft.com/kb/313372

    In your case, your xml has defined "xmlns="http://schemas.microsoft.com/win/2004/08/events/event".
    There are three approaches to solve.
    First approach :
     - Give a prefix in the Xml file
        e.g. xmlns:myevent="http://schemas.microsoft.com/win/2004/08/events/event
     - Then, in the javascript code, use
        xml.setProperty("SelectionNamespaces", "xmlns:myevent='http://schemas.microsoft.com/win/2004/08/events/event'");

    Second approach:
     - In the javascript code, use
        xml.setProperty("SelectionNamespaces", "xmlns:myevent='http://schemas.microsoft.com/win/2004/08/events/event'");
     - The query statement changes to
        var nodeList = xml.selectNodes("*[ myevent:System[(myevent:Level=4 or myevent:Level=0) and (myevent:EventID=1644)]  and myevent:EventData[starts-with(myevent:Data[5],'10.200.137.145')]  ]");

    Third approach:
     - Remove the namespace in xml file
       i.e. xmlns="http://schemas.microsoft.com/win/2004/08/events/event
     - In the javascript code, the statement below is not necessary.
        xml.setProperty("SelectionNamespaces", "xmlns='http://schemas.microsoft.com/win/2004/08/events/event'");
    • Proposed as answer by Ivan Ting Friday, April 24, 2009 5:27 PM
    • Marked as answer by Tony MurrayMVP Monday, April 27, 2009 8:49 PM
    Friday, April 24, 2009 5:27 PM
  • Hi Ivan

    Thanks very much.  All is working well now.

    Tony
    Monday, April 27, 2009 8:50 PM
  • For more information about this, see my blog entry (includes Powershell script).

    http://www.open-a-socket.com/index.php/2009/04/29/powershell-script-to-filter-events-using-an-xpath-query/

    Tony
    Wednesday, April 29, 2009 9:33 PM
  • I went to your blog but I wasn't able to reproduce your results successfully.  Mine is a little different and I'm interested in sending an e-mail when a particular 'DOMAIN\user' is in a data element of event 1016 of the application log.  Here's the log:

    <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
     <System>
      <Provider Name="MSExchangeIS Mailbox Store" /> 
      <EventID Qualifiers="16">1016</EventID> 
      <Level>0</Level> 
      <Task>16</Task> 
      <Keywords>0xa0000000000000</Keywords> 
      <TimeCreated SystemTime="2009-10-03T02:56:59.000Z" /> 
      <EventRecordID>210601</EventRecordID> 
      <Channel>Application</Channel> 
      <Computer>EXCHANGE.domain.com</Computer> 
      <Security /> 
     </System>
     <EventData>
      <Data>DOMAIN\user1</Data> 
      <Data>EMAIL REMOVED</Data> 
     </EventData>
    </Event>

    So, here's the filter I tried:

    <QueryList>
     <Query Id=”0" Path=”Application”>
      <Select Path=”Application”>*[System[Provider[@Name=’MSExchangeIS Mailbox Store’] and (EventID=1016)] and EventData[Data=’DOMAIN\user1']]</Select>
     </Query>
    </QueryList>

    This didn't work at all.  It said the format is invalid.  One thing I notice about the logged event is there are no labels for the Data sections like in your security event.  Since I couldn't get these to work I tried your example on your blog:

    <QueryList>
     <QueryId="0" Path="Security">
      <Select Path="Security">*</Select>
     </Query>
    </QueryList>

    So, nothing works for me.  Can you help me out?
    Saturday, October 3, 2009 3:56 AM
  • I was able to get the following to work:

    <QueryList>
      <Query Id="0" Path="Application">
        <Select Path="Application">*[System[(EventID=1016)] and EventData[Data="EMAIL REMOVED"]]</Select>
        <Suppress Path="Application">*[EventData[Data="NT AUTHORITY\NETWORK SERVICE"]]</Suppress>
        <Suppress Path="Application">*[EventData[Data="NT AUTHORITY\SYSTEM"]]</Suppress>
      </Query>
    </QueryList>
    Monday, October 5, 2009 8:24 PM
  • Hi Everyone,

    I am trying to query event logs for the events which have provider name consisting string 'MSExchange' similar to:

    - <Event xmlns="http://schemas.microsoft.com/win/2004/08/events/event">
    - <System>
      <Provider Name="MSExchange ADAccess" />
      <EventID Qualifiers="16388">2080</EventID>

    I have tried using:
    string queryString = "*[System[Provider[starts-with(@Name,'MSExchange')] and (Level=1  or Level=2 or Level=3 or Level=4 or Level=0) and TimeCreated[timediff(@SystemTime) <= 600000]]]";
    but it does not seems to be working .. i am getting 'The specified query is invalid'.
    using query string as:
    string queryString = "*[System[Provider[@Name='MSExchange ADAccess'] and (Level=1  or Level=2 or Level=3 or Level=4 or Level=0) and TimeCreated[timediff(@SystemTime) <= 600000]]]";
    works fine but it is able to retrieve event only with this specific provider name.
    I am using the following code:
    EventLogQuery query = new EventLogQuery("Application", PathType.LogName, queryString);

    Any help would be much appreciated.

    Tuesday, October 5, 2010 1:27 PM