{"id":15381,"date":"2011-03-08T00:01:00","date_gmt":"2011-03-08T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2011\/03\/08\/how-to-improve-the-performance-of-a-powershell-event-log-query\/"},"modified":"2011-03-08T00:01:00","modified_gmt":"2011-03-08T00:01:00","slug":"how-to-improve-the-performance-of-a-powershell-event-log-query","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/how-to-improve-the-performance-of-a-powershell-event-log-query\/","title":{"rendered":"How to Improve the Performance of a PowerShell Event Log Query"},"content":{"rendered":"<p><b>Summary<\/b>: Learn how to improve the performance of a Windows PowerShell event log query.<\/p>\n<p><img decoding=\"async\" height=\"34\" width=\"34\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" align=\"left\" alt=\"Hey, Scripting Guy! Question\" border=\"0\" title=\"Hey, Scripting Guy! Question\" \/> Hey, Scripting Guy! I am a beginner when it comes to using Windows PowerShell, and I was inspired by your article yesterday about using <a target=\"_blank\" href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2011\/03\/07\/use-powershell-to-query-all-event-logs-for-recent-events.aspx\">Windows PowerShell to Query All Event Logs for Recent Events<\/a>, and today I attempted to write a command to get all of the events generated by LANDESK in the application event log. <\/p>\n<p>Here is the code I put together. <\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Get-WinEvent -Logname Application -EA silentlycontinue |<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">where-object { $_.providername.ToLower().contains(&#8220;landesk&#8221;) -AND $_.timecreated -gt [datetime]::today}<\/span><\/p>\n<\/blockquote>\n<p>The code appears to work well, but it is very slow and CPU intensive. Am I missing something?<\/p>\n<p>&mdash;MZ<\/p>\n<p><img decoding=\"async\" height=\"34\" width=\"34\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" align=\"left\" alt=\"Hey, Scripting Guy! Answer\" border=\"0\" title=\"Hey, Scripting Guy! Answer\" \/>Hello MZ, <\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, here. It has been a really long time since I have had anything to do with the LANDESK product; therefore, I do not have it installed on my computer. However, that does not really matter, because what you are talking about is attempting to speed up the results of a query. I have talked about <a target=\"_blank\" href=\"http:\/\/blogs.technet.com\/search\/searchresults.aspx?q=measure-command&amp;sections=7618\">measuring the speed of Windows PowerShell commands<\/a> in the past. In fact, it is one of my favorite topics. <\/p>\n<p>The first thing I need to do is to obtain a baseline of query performance. As I mentioned earlier, I do not have LANDESK installed on my computer; therefore, I decided to query for events related to WMI. An example of such an event is shown here.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6254.HSG-3-8-11-01_00CAF3CE.jpg\"><img decoding=\"async\" height=\"434\" width=\"604\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2134.HSG-3-8-11-01_thumb_51B89229.jpg\" alt=\"Image of Event Viewer\" border=\"0\" title=\"Image of Event Viewer\" style=\"border-bottom: 0px;border-left: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" \/><\/a><\/p>\n<p>The command that I derived is very much like yours&mdash;in fact, it is identical, except for the name of the provider. <\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Get-WinEvent -LogName application -ea SilentlyContinue | <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Where-Object { $_.providername.ToLower().Contains(&#8216;wmi&#8217;) -AND <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">$_.TimeCreated -gt [datetime]::today }<\/span><\/p>\n<\/blockquote>\n<p>To measure the performance of the command, I use the <b>Measure-Command<\/b> Windows PowerShell cmdlet. It accepts a parameter called <i>Expression <\/i>which is where the Windows PowerShell command is placed. The command that is shown here is the command to time the <b>Get-WinEvent<\/b> command listed previously.<\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Measure-Command -Expression {<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Get-WinEvent -LogName application -ea SilentlyContinue | <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Where-Object { $_.providername.ToLower().Contains(&#8216;wmi&#8217;) -AND <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">$_.TimeCreated -gt [datetime]::today }<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">}<\/span><\/p>\n<\/blockquote>\n<p>When I am working with commands that use more than one or two lines in the Windows PowerShell console, I tend to use the Windows PowerShell ISE because it makes it easier to keep track of the commands, and it makes it easier to modify those commands. The command and its associated output are shown in the following image.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4606.HSG-3-8-11-02_73E077E2.jpg\"><img decoding=\"async\" height=\"424\" width=\"604\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4048.HSG-3-8-11-02_thumb_38E91F4C.jpg\" alt=\"Image of command output\" border=\"0\" title=\"Image of command output\" style=\"border-bottom: 0px;border-left: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" \/><\/a><\/p>\n<p>On my computer, the previous command completes in just a little more than 21 seconds. In reality, that is not too horribly bad. After all, the application log on my computer consumes 20 megabytes of disk space, and it contains 21810 entries. I found the size by looking at the event log properties in the Event Viewer. I determined the number of entries in the log by using the <b>Measure-Object<\/b> cmdlet as shown here.<\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">PS C:\\&gt; Get-WinEvent -LogName application | Measure-Object<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Count : 21810<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Average :<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Sum :<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Maximum :<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Minimum :<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Property :<\/span><\/p>\n<\/blockquote>\n<p>MZ, I noticed that you posted a <a target=\"_blank\" href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2011\/03\/07\/use-powershell-to-query-all-event-logs-for-recent-events.aspx#comments\">comment on yesterday&rsquo;s Hey Scripting Guy! blog<\/a> in addition to sending an email message to the <a href=\"mailto:scripter@microsoft.com\">scripter@microsoft.com<\/a> alias. Bartek,&nbsp;one of our readers, suggested you were working too hard, and offered a revision to your command. I think it will be fun to test his revision, and see what happens. Here is the command with the modifications suggested by Bartek. <\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Measure-Command -Expression {<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Get-WinEvent -LogName application -ea 0 | <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Where-Object { $_.providername -match &#8216;wmi&#8217; -AND <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">$_.TimeCreated -gt [datetime]::today }<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">}<\/span><\/p>\n<\/blockquote>\n<p>The first change Bartek made was to change <i>&ndash;ea SilentlyContinue<\/i> to <i>&ndash;ea 0<\/i>. As it turns out, 0 is the enumeration value for <i>SilentlyContinue<\/i>. I found that out by using the Get-EnumAndValues.ps1 script from my <a target=\"_blank\" href=\"http:\/\/blogs.technet.comhttps:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-weekend-scripter-enumerations-and-values\/\">Enumerations and Values Weekend Scripter<\/a> article. The other enumerations and values from the &#8220;System.Management.Automation.ActionPreference&#8221; enumeration are shown here.<\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Name Value<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">&#8212;- &#8212;&#8211;<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Inquire 3<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Continue 2<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Stop 1<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">SilentlyContinue 0<\/span><\/p>\n<\/blockquote>\n<p>The next change he made was to remove <i>tolower <\/i>and <i>contains <\/i>from your query, and replace them with the &ndash;<i>match<\/i> operator. The resultant clause is shown here.<\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">$_.providername -match &#8216;wmi&#8217;<\/span><\/p>\n<\/blockquote>\n<p>On my computer, when I measured the performance of the revised command, the results were a little more than 21 seconds. This is shown in the following image.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3157.HSG-3-8-11-03_75516E29.jpg\"><img decoding=\"async\" height=\"424\" width=\"604\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/3580.HSG-3-8-11-03_thumb_665A1942.jpg\" alt=\"Image of command output\" border=\"0\" title=\"Image of command output\" style=\"border-bottom: 0px;border-left: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" \/><\/a><\/p>\n<p>Bartek is correct MZ, you are doing too much work. As you can see, there was no advantage to converting to all lowercase and using the <i>contains<\/i> method. <\/p>\n<p>The first thing I want to do is to quit searching for the provider and replace it with the proper provider name. I use the following command to find the WMI provider name. <\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">PS C:\\&gt; (get-winevent -listlog Application).providernames | where { $_ -match &#8216;wmi&#8217;}<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">WMI.NET Provider Extension<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Microsoft-Windows-WMI<\/span><\/p>\n<\/blockquote>\n<p>When I search for event log providers that match the string &#8216;wmi&#8217;, I found that there are two providers. I assumed that there was only one match, when there were actually two matches. This could skew the accuracy of my queries. I think I really want the Microsoft-Windows-WMI provider, but I check the event log in Event Viewer to be sure. This is illustrated in the following image.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/8206.HSG-3-8-11-04_22C26820.jpg\"><img decoding=\"async\" height=\"434\" width=\"604\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4578.HSG-3-8-11-04_thumb_24CF411C.jpg\" alt=\"Image of Event Viewer\" border=\"0\" title=\"Image of Event Viewer\" style=\"border-bottom: 0px;border-left: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" \/><\/a><\/p>\n<p>Now that I know the provider name, I can use it directly with the <b>Get-WinEvent<\/b> cmdlet. The first thing to remember is that I cannot use the <i>ProviderName<\/i> parameter and the <i>LogName<\/i> parameter in the same command. It seems like a major limitation; but in reality, it is not. This is because an event log provider can only be registered with one event log. The revised command and associated output are shown here.<\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">PS C:\\Users\\ed.NWTRADERS&gt; Get-WinEvent -ea SilentlyContinue `<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">-ProviderName &#8220;Microsoft-Windows-WMI&#8221;| <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Where-Object { $_.TimeCreated -gt [datetime]::today }<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">TimeCreated ProviderName Id Message<\/span><\/p>\n<\/blockquote>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">&#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8212; &#8212; &#8212;&#8212;-<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">3\/7\/2011 6:42:46 AM Microsoft-Windows-WMI 5617 Windows Management In&#8230;<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">3\/7\/2011 6:42:46 AM Microsoft-Windows-WMI 5615 Windows Management In&#8230;<\/span><\/p>\n<\/blockquote>\n<p>Just watching the command run, I could see that there was a significant improvement in speed. In fact, the results took less than a second. The modification and the output are shown here.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6746.HSG-3-8-11-05_738056BB.jpg\"><img decoding=\"async\" height=\"424\" width=\"604\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4428.HSG-3-8-11-05_thumb_53552431.jpg\" alt=\"Image of command output\" border=\"0\" title=\"Image of command output\" style=\"border-bottom: 0px;border-left: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" \/><\/a><\/p>\n<p>The big reason for the big performance improvement is reducing the number of event log entries that are identified by the <b>Get-WinEvent<\/b> cmdlet prior to shipping the events over the pipeline to be filtered by the <b>Where-Object<\/b> cmdlet. It is always faster to filter before sending to the <b>Where-Object<\/b> than to filter afterwards. <\/p>\n<p>It is possible to remove the <b>Where-Object<\/b> cmdlet completely. To do this requires using the <i>FilterHashTable <\/i>parameter. The hash table will let you filter on <i>LogName<\/i>, <i>ProviderName<\/i>, <i>Path<\/i>, <i>Keywords<\/i>, <i>Id<\/i>, <i>Level<\/i>, <i>StartTime<\/i>, <i>EndTime,<\/i> and <i>UserId<\/i>. For more information about using <i>FilterHashTable,<\/i> see the <a target=\"_blank\" href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2011\/01\/24\/use-powershell-cmdlet-to-filter-event-log-for-easy-parsing.aspx\">Use a PowerShell Cmdlet to Filter Event Log for Easy Parsing<\/a> Hey! Scripting Guy article. <\/p>\n<p>In using the <i>FilterHashTable<\/i> parameter, I am able to completely remove the <b>Where-Object<\/b> cmdlet. The revised command is shown here.<\/p>\n<blockquote>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Get-WinEvent -ea SilentlyContinue `<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">-FilterHashtable @{ProviderName= &#8220;Microsoft-Windows-WMI&#8221;; <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">LogName = &#8220;application&#8221;; StartTime = [datetime]::today}<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">When I run the command, it returns quickly. To see how quickly, I added it to the <b>Measure-Command<\/b> command as shown here.<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Measure-Command -Expression {<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">Get-WinEvent -ea SilentlyContinue `<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">-FilterHashtable @{ProviderName= &#8220;Microsoft-Windows-WMI&#8221;; <\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">LogName = &#8220;application&#8221;; StartTime = [datetime]::today}<\/span><\/p>\n<p><span style=\"font-family: Lucida Sans Typewriter;font-size: x-small\">}<\/span><\/p>\n<\/blockquote>\n<p>On my system, this command results in only a slight improvement over the previous command. This is shown in the following image.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6518.HSG-3-8-11-06_700E9946.jpg\"><img decoding=\"async\" height=\"424\" width=\"604\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5543.HSG-3-8-11-06_thumb_0B174288.jpg\" alt=\"Image of command output\" border=\"0\" title=\"Image of command output\" style=\"border-bottom: 0px;border-left: 0px;padding-left: 0px;padding-right: 0px;border-top: 0px;border-right: 0px;padding-top: 0px\" \/><\/a><\/p>\n<p>MZ, that is all there is to using <b>Get-WinEvent<\/b> parameters and the <b>Measure-Command<\/b> cmdlet to improve query performance. I invite you to join me tomorrow for more Windows PowerShell goodness. <\/p>\n<p>I invite you to follow me on <a target=\"_blank\" href=\"http:\/\/bit.ly\/scriptingguystwitter\">Twitter<\/a> and <a target=\"_blank\" href=\"http:\/\/bit.ly\/scriptingguysfacebook\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\">scripter@microsoft.com<\/a>, or post your questions on the <a target=\"_blank\" href=\"http:\/\/bit.ly\/scriptingforum\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Learn how to improve the performance of a Windows PowerShell event log query. Hey, Scripting Guy! I am a beginner when it comes to using Windows PowerShell, and I was inspired by your article yesterday about using Windows PowerShell to Query All Event Logs for Recent Events, and today I attempted to write a [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[97,51,98,60,3,4,45],"class_list":["post-15381","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-event-logs","tag-getting-started","tag-logs-and-monitoring","tag-performance","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Learn how to improve the performance of a Windows PowerShell event log query. Hey, Scripting Guy! I am a beginner when it comes to using Windows PowerShell, and I was inspired by your article yesterday about using Windows PowerShell to Query All Event Logs for Recent Events, and today I attempted to write a [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/15381","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\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=15381"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/15381\/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=15381"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=15381"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=15381"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}