{"id":1241,"date":"2014-06-06T00:01:00","date_gmt":"2014-06-06T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2014\/06\/06\/understanding-xml-and-xpath\/"},"modified":"2014-06-06T00:01:00","modified_gmt":"2014-06-06T00:01:00","slug":"understanding-xml-and-xpath","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/understanding-xml-and-xpath\/","title":{"rendered":"Understanding XML and XPath"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft Scripting Guy, Ed Wilson, explores XML and <strong>XPath<\/strong>.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. One of the things that confused me for a long time about using the <b>Get-WinEvent<\/b> cmdlet is the difference between the <b>&ndash;FilterXPath<\/b> parameter and the <b>&ndash;FilterXml<\/b> parameters. Part of the problem is that there are nearly no examples to be found that illustrate using <b>&ndash;FilterXPath<\/b>. A close look at the syntax of the <b>Get-WinEvent<\/b> cmdlet, however, does provide a bit of a clue. I include two examples here:<\/p>\n<p style=\"margin-left:30px\">Get-WinEvent [[-LogName] &lt;String[]&gt;] [-ComputerName &lt;String&gt;] [-Credential<\/p>\n<p style=\"margin-left:30px\">&lt;PSCredential&gt;] [-FilterXPath &lt;String&gt;] [-Force] [-MaxEvents &lt;Int64&gt;] [-Oldest]<\/p>\n<p style=\"margin-left:30px\">[&lt;CommonParameters&gt;]<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\">Get-WinEvent [-FilterXml] &lt;XmlDocument&gt; [-ComputerName &lt;String&gt;] [-Credential<\/p>\n<p style=\"margin-left:30px\">&lt;PSCredential&gt;] [-MaxEvents &lt;Int64&gt;] [-Oldest] [&lt;CommonParameters&gt;]<\/p>\n<p>So the <b>FilterXPath<\/b> parameter wants a simple string, and <b>FilterXml<\/b> wants an actual XML document. When I see <b>XMLDocument<\/b>, I think, &ldquo;Structured XML.&rdquo; Maybe I should back up just a little bit&hellip;<\/p>\n<p>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 <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/ms256115(v=vs.110).aspx\" target=\"_blank\">XPath Reference<\/a> 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&nbsp;1.0. The Consuming Events topic in the Windows Dev Center has a section called <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/windows\/desktop\/dd996910(v=vs.85).aspx#limitations\" target=\"_blank\">XPath 1.0 limitations<\/a>, which is an excellent reference about the specific limitations of the XPath&nbsp;1.0 subset for querying events and log files.<\/p>\n<p>An XPath query must resolve to select events, not a single event&mdash;it must resolve to events. All valid paths begin with either a * or the keyword <b>Event<\/b>. 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 (<a href=\"http:\/\/www.w3.org\/TR\/xpath\/\" target=\"_blank\">XML Path Language (XPath)<\/a>), which is a good reference.<\/p>\n<p>The following are limitations of XPath&nbsp;1.0 in regards to working with event logs:<\/p>\n<p><b>Axis<\/b>&nbsp;&nbsp; Only the <b>Child<\/b> (default) and <b>Attribute<\/b> (and its shorthand <b>@<\/b>) axis are supported.<\/p>\n<p><b>Node Test&nbsp;&nbsp;<\/b> Only node names and NCName tests are supported. The &quot;<b>*<\/b>&quot; character, which selects any character, is supported.<\/p>\n<p><b>Predicates&nbsp;&nbsp;<\/b> Any valid XPath expression is acceptable if the location paths conform to the following restrictions:<\/p>\n<ul>\n<li>The standard operators OR, AND, =, !=, &lt;=, &lt;, &gt;=, &gt;, and parentheses are supported.<\/li>\n<li>Generating a string value for a node name is not supported.<\/li>\n<li>Evaluation in reverse order is not supported.<\/li>\n<li>Node sets are not supported.<\/li>\n<li>Namespace scoping is not supported.<\/li>\n<li>Namespace, processing, and comment nodes are not supported.<\/li>\n<li>Context size is not supported.<\/li>\n<li>Variable bindings are not supported.<\/li>\n<li>The <b>position<\/b> function and its shorthand array reference are supported (on leaf nodes only).<\/li>\n<li>The <b>band<\/b> 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.<\/li>\n<li>The <b>timediff<\/b> 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.<\/li>\n<\/ul>\n<h2>When to use XPath<\/h2>\n<p>I use XPath queries when I am querying from the event log in the following situations:<\/p>\n<ul>\n<li>It is a simple query from a single source.<\/li>\n<li>It is a simple expression.<\/li>\n<li>It is a compound expression that uses less than 20 expressions.<\/li>\n<li>It does not use a suppressor.<\/li>\n<\/ul>\n<p>I use an XML structured query when I need to do the following:<\/p>\n<ul>\n<li>Use a compound query from more than one source<\/li>\n<li>Use a suppressor to prevent events from being selected<\/li>\n<li>Use a compound expression with more than 20 expressions<\/li>\n<\/ul>\n<p>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.&nbsp;<\/p>\n<p style=\"margin-left:30px\">$query = @&quot;<\/p>\n<p style=\"margin-left:30px\">&lt;QueryList&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp; &lt;Query Id=&quot;0&quot;&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &lt;Select Path=&quot;Application&quot;&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[System[(Level &amp;lt;= 3) and<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TimeCreated[timediff(@SystemTime) &amp;lt;= 86400000]]]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &lt;\/Select&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &lt;Suppress Path=&quot;Application&quot;&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[System[(Level = 2)]]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &lt;\/Suppress&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &lt;Select Path=&quot;System&quot;&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; *[System[(Level=1&nbsp; or Level=2 or Level=3) and<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; TimeCreated[timediff(@SystemTime) &amp;lt;= 86400000]]]<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp; &lt;\/Select&gt;<\/p>\n<p style=\"margin-left:30px\">&nbsp; &lt;\/Query&gt;<\/p>\n<p style=\"margin-left:30px\">&lt;\/QueryList&gt;<\/p>\n<p style=\"margin-left:30px\">&quot;@<\/p>\n<p>&nbsp;<\/p>\n<p style=\"margin-left:30px\">Get-WinEvent -FilterXml $query<\/p>\n<p>When I run the previous query, the following output returns:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-6-6-14-01.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/hsg-6-6-14-01.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>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 <b>FilterXPath<\/b>.<\/p>\n<p style=\"margin-left:30px\"><b>Note&nbsp;<\/b> Whereas the <b>&ndash;FilterHashTable<\/b> and the <b>&ndash;FilterXml<\/b> parameters do not accept the <b>LogName<\/b> parameter (because both require the log inside the query itself),<b>&ndash;FilterXPath<\/b> requires the <b>LogName<\/b> parameter. This is how I specify which event log I want to search.<\/p>\n<h2>Xpath examples<\/h2>\n<p>The easiest Xpath query is <b>*<\/b>, which means &ldquo;return everything.&rdquo; I can type this directly into the Windows PowerShell console as follows (remember that the <b>FilterXPath<\/b> parameter expects a string, and therefore, quotation marks are not required):<\/p>\n<p style=\"margin-left:30px\">Get-WinEvent -LogName application -FilterXPath *<\/p>\n<p>On the other hand, if I put it in a script, I need to add the quotation marks, as shown here:<\/p>\n<p style=\"margin-left:30px\">$xpath = &quot;*&quot;<\/p>\n<p style=\"margin-left:30px\">Get-WinEvent -LogName application -FilterXPath $xpath<\/p>\n<p>To query events from a specific provider, I need to specify <b>Provider<\/b> and use <b>@Name<\/b> to get to the provider name. Notice that there are several square brackets in the query.<\/p>\n<p style=\"margin-left:30px\">$xpath = &quot;*[System\/Provider[@Name=&#039;Microsoft-Windows-DNS-Client&#039;]]&quot;<\/p>\n<p style=\"margin-left:30px\">Get-WinEvent -LogName system -FilterXPath $xpath&nbsp;<\/p>\n<p>If I want to add in an additional filter (for example, to only retrieve warning messages), I append it this way:<\/p>\n<p style=\"margin-left:30px\">$xpath = &quot;*[System\/Provider[@Name=&#039;Microsoft-Windows-DNS-Client&#039;] and System\/Level=3] &quot;<\/p>\n<p style=\"margin-left:30px\">Get-WinEvent -LogName system -FilterXPath $xpath<\/p>\n<p>If I would also like to add a date to the equation, I can specify the <b>System\/TimeCreated<\/b> node and reference <b>SystemTime <\/b>as shown here:<\/p>\n<p style=\"margin-left:30px\">$xpath = &quot;*[System\/Provider[@Name=&#039;Microsoft-Windows-DNS-Client&#039;]<\/p>\n<p style=\"margin-left:30px\">and System\/Level=3<\/p>\n<p style=\"margin-left:30px\">and System\/TimeCreated[@SystemTime &lt; &#039;2014-03-01T18:06:09.000Z&#039;]]&quot;<\/p>\n<p style=\"margin-left:30px\">Get-WinEvent -LogName system -FilterXPath $xpath<\/p>\n<p>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.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &ndash;FilterXPath parameter and the &ndash;FilterXml parameters. Part of the problem is that there are nearly no examples [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[97,98,3,4,45,165,515],"class_list":["post-1241","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-event-logs","tag-logs-and-monitoring","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell","tag-xml","tag-xpath"],"acf":[],"blog_post_summary":"<p>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 &ndash;FilterXPath parameter and the &ndash;FilterXml parameters. Part of the problem is that there are nearly no examples [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/1241","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=1241"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/1241\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=1241"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=1241"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=1241"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}