June 6th, 2014

Understanding XML and XPath

Doctor Scripto
Scripter

Summary: Microsoft Scripting Guy, Ed Wilson, explores XML and XPath.

Microsoft Scripting Guy, Ed Wilson, is here. One of the things that confused me for a long time about using the Get-WinEvent cmdlet is the difference between the –FilterXPath parameter and the –FilterXml parameters. Part of the problem is that there are nearly no examples to be found that illustrate using –FilterXPath. A close look at the syntax of the Get-WinEvent cmdlet, however, does provide a bit of a clue. I include two examples here:

Get-WinEvent [[-LogName] <String[]>] [-ComputerName <String>] [-Credential

<PSCredential>] [-FilterXPath <String>] [-Force] [-MaxEvents <Int64>] [-Oldest]

[<CommonParameters>]

 

Get-WinEvent [-FilterXml] <XmlDocument> [-ComputerName <String>] [-Credential

<PSCredential>] [-MaxEvents <Int64>] [-Oldest] [<CommonParameters>]

So the FilterXPath parameter wants a simple string, and FilterXml wants an actual XML document. When I see XMLDocument, I think, “Structured XML.” Maybe I should back up just a little bit…

What is XPath anyway? Well, XPath is a query language that is used for selecting nodes from an XML document. In addition, I can use XPath to compute values, but this really does not have much to do with querying data from event logs. MSDN has an XPath Reference guide that is pretty good, but it is simply for reference. This is because the Windows event log does not contain full support for the XPath query language. Instead, it uses a subset of XPath 1.0. The Consuming Events topic in the Windows Dev Center has a section called XPath 1.0 limitations, which is an excellent reference about the specific limitations of the XPath 1.0 subset for querying events and log files.

An XPath query must resolve to select events, not a single event—it must resolve to events. All valid paths begin with either a * or the keyword Event. The paths operate on event nodes, and they are composed of a series of steps. Each step is a structure of three parts: Axis, Node Test, and Predicate. XPath is an industry standard that has been around since 1999. The W3C has a nice language specification (XML Path Language (XPath)), which is a good reference.

The following are limitations of XPath 1.0 in regards to working with event logs:

Axis   Only the Child (default) and Attribute (and its shorthand @) axis are supported.

Node Test   Only node names and NCName tests are supported. The "*" character, which selects any character, is supported.

Predicates   Any valid XPath expression is acceptable if the location paths conform to the following restrictions:

  • The standard operators OR, AND, =, !=, <=, <, >=, >, and parentheses are supported.
  • Generating a string value for a node name is not supported.
  • Evaluation in reverse order is not supported.
  • Node sets are not supported.
  • Namespace scoping is not supported.
  • Namespace, processing, and comment nodes are not supported.
  • Context size is not supported.
  • Variable bindings are not supported.
  • The position function and its shorthand array reference are supported (on leaf nodes only).
  • The band function is supported. The function performs a bitwise AND for two integer number arguments. If the result of the bitwise AND is nonzero, the function evaluates to True; otherwise, the function evaluates to False.
  • The timediff function is supported. The function computes the difference between the second argument and the first argument. One of the arguments must be a literal number. The arguments must use the FILETIME representation. The result is the number of milliseconds between the two times. The result is positive if the second argument represents a later time; otherwise, it is negative. When the second argument is not provided, the current system time is used.

When to use XPath

I use XPath queries when I am querying from the event log in the following situations:

  • It is a simple query from a single source.
  • It is a simple expression.
  • It is a compound expression that uses less than 20 expressions.
  • It does not use a suppressor.

I use an XML structured query when I need to do the following:

  • Use a compound query from more than one source
  • Use a suppressor to prevent events from being selected
  • Use a compound expression with more than 20 expressions

Here is an example of a structured XML query that illustrates querying the system and the application logs. In addition, events from the application log are only Level 3 and Level 1. Level 2 events are suppressed. The events occurred within the last 86400000 seconds. 

$query = @"

<QueryList>

  <Query Id="0">

    <Select Path="Application">

        *[System[(Level &lt;= 3) and

        TimeCreated[timediff(@SystemTime) &lt;= 86400000]]]

    </Select>

    <Suppress Path="Application">

        *[System[(Level = 2)]]

    </Suppress>

    <Select Path="System">

        *[System[(Level=1  or Level=2 or Level=3) and

        TimeCreated[timediff(@SystemTime) &lt;= 86400000]]]

    </Select>

  </Query>

</QueryList>

"@

 

Get-WinEvent -FilterXml $query

When I run the previous query, the following output returns:

Image of command output

Although this structured XML is really powerful and it results in a nice output, for queries that are easier to understand and easier to compose, I want to use FilterXPath.

Note  Whereas the –FilterHashTable and the –FilterXml parameters do not accept the LogName parameter (because both require the log inside the query itself),–FilterXPath requires the LogName parameter. This is how I specify which event log I want to search.

Xpath examples

The easiest Xpath query is *, which means “return everything.” I can type this directly into the Windows PowerShell console as follows (remember that the FilterXPath parameter expects a string, and therefore, quotation marks are not required):

Get-WinEvent -LogName application -FilterXPath *

On the other hand, if I put it in a script, I need to add the quotation marks, as shown here:

$xpath = "*"

Get-WinEvent -LogName application -FilterXPath $xpath

To query events from a specific provider, I need to specify Provider and use @Name to get to the provider name. Notice that there are several square brackets in the query.

$xpath = "*[System/Provider[@Name='Microsoft-Windows-DNS-Client']]"

Get-WinEvent -LogName system -FilterXPath $xpath 

If I want to add in an additional filter (for example, to only retrieve warning messages), I append it this way:

$xpath = "*[System/Provider[@Name='Microsoft-Windows-DNS-Client'] and System/Level=3] "

Get-WinEvent -LogName system -FilterXPath $xpath

If I would also like to add a date to the equation, I can specify the System/TimeCreated node and reference SystemTime as shown here:

$xpath = "*[System/Provider[@Name='Microsoft-Windows-DNS-Client']

and System/Level=3

and System/TimeCreated[@SystemTime < '2014-03-01T18:06:09.000Z']]"

Get-WinEvent -LogName system -FilterXPath $xpath

That is all there is to using XPath to query the event log. This also brings Event Log Week to a close. Join me tomorrow when I will share three way cool Windows PowerShell profile functions that Bruce Payette shared with me.

I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.

Ed Wilson, Microsoft Scripting Guy 

Author

The "Scripting Guys" is a historical title passed from scripter to scripter. The current revision has morphed into our good friend Doctor Scripto who has been with us since the very beginning.

0 comments

Discussion are closed.