Learn about Windows PowerShell
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]
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:
I use XPath queries when I am querying from the event log in the following situations:
I use an XML structured query when I need to do the following:
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 = @"
*[System[(Level <= 3) and
TimeCreated[timediff(@SystemTime) <= 86400000]]]
*[System[(Level = 2)]]
*[System[(Level=1 or Level=2 or Level=3) and
Get-WinEvent -FilterXml $query
When I run the previous query, the following output returns:
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.
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/TimeCreated[@SystemTime < '2014-03-01T18:06:09.000Z']]"
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 email@example.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy
@Ed - excellent. This is a good starter tutorial. As you posted there is a paucity of examples. This will lead to many more examples. The topic is extensive. Don't be distract4ed by the support limitations fo rXPAth. It is still extremely powerful.
FilterXML allows for multiple queries and some alternate elements of definition as well as elimination of alternate parameters in most cases.
I beleieve that "FilterXPath: can be considered a simple subset of "FilterXML".
Be careful ... OR, AND are lowercase only or, and ....
@Ed Great post, thanks! You say seconds but I believe you mean milliseconds, though, right? 1 day = 86400000 milliseconds.
Is there anyway I can generate the query XML inserting $millis values, for example? I've been trying to concatenate them into the above query , but I think the "@@" is what I'm not quite getting.