Zoho Banner September 2011

Posts tagged ‘xpath’

I have recently spent some time working with Xpath queries as part of Event Log filtering in Windows Server 2008.  It’s a great feature, but one limitation I found was that it doesn’t appear possible to use the starts-with() function when querying Event Logs with either the UI or Wevtutil.exe.  Here’s an example.

Let’s say I enabled LDAP logging on a DC and want to filter the Directory Service event log to find all LDAP queries coming from a particular IP address.  The IP address is buried in one of the Data nodes of the Event XML, as shown in red below.

<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>0×8080000000000000</Keywords>

    <TimeCreated SystemTime=”2009-04-29T20:39:00.886Z” />

    <EventRecordID>339453</EventRecordID>

    <Correlation />

    <Execution ProcessID=”648″ ThreadID=”792″ />

    <Channel>Directory Service</Channel>

    <Computer>DC1.Myco.Com</Computer>

    <Security UserID=”S-1-5-21-854245398-152049171-725345543-4606″ />

  </System>

  <EventData>

    <Data>CN=MyCo Enterprise Issuing CA 1, CN=Public Key Services,CN=Services,CN=Configuration,DC=MyCo,DC=Com</Data>

    <Data> (objectClass=cRLDistributionPoint) </Data>

    <Data>1</Data>

    <Data>1</Data>

    <Data>192.168.40.10:4048</Data>

    <Data>base</Data>

    <Data>deltaRevocationList</Data>

    <Data>

    </Data>

  </EventData>

</Event>

So if I wanted to use Xpath to filter all events in the Directory Service Event Log from that IP address my query would look something like this:

<QueryList>

  <Query Id=”0″ Path=”Directory Service”>

    <Select Path=”Directory Service”>*[System[(Level=4 or Level=0) and (EventID=1644)]] and *[EventData[Data[5]=’192.168.40.10:4048′]]</Select>

  </Query>

</QueryList>

The query works well, but the problem is that the Data node within the XML contains the port number (4048) in addition to the IP address.  I want to find all queries issued from that client, regardless of the port used.  Here’s my attempt to use the starts-with() function to filter the event.

<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],’192.168.40.10′)]]</Select>

  </Query>

</QueryList>

This fails with the error “The specified query is invalid“.  Back to the drawing board.  I posted a question to Technet Forums and got some good help from Ivan Ting at Microsoft.  He provided some Javascript that used starts-with() and this worked (after some fun messing around with default namespace issues).  Being something of a Javascript muppet (the antithesis of a Javascript guru), I decided to try my hand at a Powershell version.  Here’s what I came up with.

#####
# Author: Tony Murray
# File name: LDAPEvents.ps1
# Date: 28th April 2009
# Purpose: Extracts LDAP Search information from Directory Service Event
# Log. Requires LDAP logging to be switched on.
#####

# Function to create an object for XML document navigation
# Source: Technet Scriptcenter
function get-xpn ($text)
{
$rdr = [System.IO.StreamReader] $text
$trdr = [system.io.textreader]$rdr
$xpdoc = [System.XML.XPath.XPathDocument] $trdr
$xpdoc.CreateNavigator()
}

# Run Wevtutil.exe to export the Event log to file
# Could use Powershell to do this but it creates odd-looking xml!

$file = “c:\util\dumplog.xml”
& $env:windir\System32\wevtutil qe `”Directory Service` /e:Events | Out-File $file

# Remove the namespace from the xml file. It won’t work if it stays

$findStr = ” xmlns=`’http://schemas.microsoft.com/win/2004/08/events/event`’”
$ReplStr = “”
$newcontent = (Get-Content $file) -replace ($findStr,$ReplStr)
Set-Content $file $newcontent

# Invoke the navigator
$xb = get-xpn $file

# Define the Xpath query we want to use
$query = “//*[ System[(Level=4 or Level=0) and (EventID=1644)] `
and EventData[starts-with(Data[5],’192.168.40.10′)]]”

# Create a CSV file with the output. Each line represents the details
# we want from a single Event.

Write-Output $xb.Select($query) | %{[xml] $_.OuterXml} | Select-Object `
@{name = “Date&Time”;Expression = {$_.Event.System.TimeCreated.SystemTime}}, `
@{name = “SearchBase”;Expression = {$_.Event.EventData.Data[0]}}, `
@{name = “Filter”;Expression = {$_.Event.EventData.Data[1]}}, `
@{name = “Visited”;Expression = {$_.Event.EventData.Data[2]}}, `
@{name = “Returned”;Expression = {$_.Event.EventData.Data[3]}}, `
#@{name = “SourceIP”;Expression = {$_.Event.EventData.Data[4]}}, `
@{name = “SearchScope”;Expression = {$_.Event.EventData.Data[5]}} `
| export-csv ds.csv -notype
# Replace the previous line with the following line to change the output format
#ConvertTo-HTML | Out-File “LDAPEvent.html”

Having to write a script is more effort than simply issuing the query from within Eventvwr, but it does have the advantage of allowing you to return only the information you are interested in – and in the format that you want.  Hopefully, my experience will save you a bit of time and effort if you are trying to achieve something similar.

If you’ve spent some time with Vista or Windows Server 2008 you’ll have noticed that there are some fundamental changes to the event viewer.  One of the changes is in the way in which event logs can be filtered.  In addition to the point-and-click filter selection you can now also enter an xpath query by accessing the XML tab (see screenshots below).  This gives you the ability to filter using a much wider range of criteria.  Basically, you can search using anything that is presented in the list of XML values.

event_filtering1.JPG

-

event_filtering2.JPG

The xpath queries take a bit of getting used to and as yet there don’t appear to be many publicly available examples.  Here are a few to get you started. This query searches the Security Event log for 4624 events that include a TargetUsername of “User1″ and corresponding to a logon type of “2″ (interactive). 

<QueryList>
  <Query Id=”0″ Path=”Security”>
    <Select Path=”Security”>*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventID=4624)] and EventData[Data[@Name='TargetUserName']=’User1′] and EventData[Data[@Name='LogonType']=’2′]]</Select>
  </Query>
</QueryList>

The query below also looks for 4624 events, but this time for those that include a WorkstationName of “Workstation1″ and a logon type of “3″ (network). 

<QueryList>
  <Query Id=”0″ Path=”Security”>
    <Select Path=”Security”>*[System[Provider[@Name='Microsoft-Windows-Security-Auditing'] and (EventID=4624)] and EventData[Data[@Name='WorkstationName']=’Workstation1′] and EventData[Data[@Name='LogonType']=’3′]]</Select>
  </Query>
</QueryList>

Even though Xpath can appear a little daunting at first it is worth spending a bit of time with as it’s potentially quite powerful.  As with Powershell it is something that is likely to be here to stay.