{"id":13171,"date":"2011-07-29T00:01:00","date_gmt":"2011-07-29T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2011\/07\/29\/create-and-parse-performance-monitor-logs-with-powershell\/"},"modified":"2011-07-29T00:01:00","modified_gmt":"2011-07-29T00:01:00","slug":"create-and-parse-performance-monitor-logs-with-powershell","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/create-and-parse-performance-monitor-logs-with-powershell\/","title":{"rendered":"Create and Parse Performance Monitor Logs with PowerShell"},"content":{"rendered":"<p><strong>Summary:<\/strong> Learn how to create and parse performance monitor logs by using Windows PowerShell.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\" \/>Hey, Scripting Guy! I am wondering if I can use Windows PowerShell to create a performance counter log that I can use in Perfmon?<\/p>\n<p>&nbsp;<\/p>\n<p>&mdash;CS<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\" \/>Hello CS,<\/p>\n<p>Microsoft Scripting Guy Ed Wilson here. After I finished giving my two talks on Windows PowerShell at SQLSaturday in Wheeling, West Virginia, I had the chance to talk to Ken M. and Matt L. who are both from Pittsburgh, Pennsylvania. Actually, The Scripting Wife and I had a chance to meet Ken M. at the PowerShell Deep Dive in Las Vegas. One of the things we were talking about was starting a new Windows PowerShell users group in Pittsburgh. I hope it will happen. By the way, next weekend (August 6&ndash;7, 2011) I have a couple of articles that talk about what is involved in starting a Windows PowerShell users group. If you would like to start a Windows PowerShell users group, shoot me an email at <a href=\"mailto:scripter@microsoft.com\">scripter@microsoft.com<\/a>. &nbsp;<\/p>\n<p style=\"padding-left: 30px\"><b>Note<\/b>&nbsp; &nbsp;Performance counter cmdlets in Windows PowerShell work on Windows 7 and later. If you need to work with performance counter logs in an operating system before Windows 7, use the Relog.exe utility. <a href=\"http:\/\/technet.microsoft.com\/en-us\/library\/cc737657(WS.10).aspx\">This library article<\/a> talks about other command-line tools that you might find useful in working with performance counters.<\/p>\n<p>&nbsp;<\/p>\n<p>CS, when running scripts that might generate a lot of data, it is important to look at potential memory consumption. For example, let&rsquo;s use the commands from <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2011\/07\/28\/use-performance-counter-sets-and-powershell-to-ease-baselining.aspx\">yesterday&rsquo;s Hey, Scripting Guy! Blog post<\/a> that select the performance counter paths to collect processor, memory, and disk information. After I have gathered all the counters, I submit them to the <b>Get-Counter<\/b> cmdlet to begin the collection of the data. The commands is shown here:<\/p>\n<p style=\"padding-left: 30px\">$a = (Get-Counter -ListSet &#8220;Processor Information&#8221;).paths<\/p>\n<p style=\"padding-left: 30px\">$a += (Get-Counter -listSet &#8220;memory&#8221;).paths<\/p>\n<p style=\"padding-left: 30px\">$a += (Get-Counter -listSet &#8220;LogicalDisk&#8221;).paths<\/p>\n<p style=\"padding-left: 30px\">$a += (Get-Counter -listSet &#8220;PhysicalDisk&#8221;).paths<\/p>\n<p style=\"padding-left: 30px\">Get-Counter -Counter $a<\/p>\n<p>&nbsp;<\/p>\n<p>If I want to use Windows PowerShell to create a performance log, the best way to do this is to use the pipeline and stream the data directly to the file. Streaming the data directly to a file will reduce the memory consumption of the command. I can use the <i>continuous<\/i> switched parameter to cause the <b>Get-Counter<\/b> cmdlet to stream data continuously. Because of the manual intervention required, this switch is limited to ad hoc performance testing. One would never kick off a scheduled task with the <i>continuous <\/i>switch. The modified command is shown here:<\/p>\n<p style=\"padding-left: 30px\">$a = (Get-Counter -ListSet &#8220;Processor Information&#8221;).paths<\/p>\n<p style=\"padding-left: 30px\">$a += (Get-Counter -listSet &#8220;memory&#8221;).paths<\/p>\n<p style=\"padding-left: 30px\">$a += (Get-Counter -listSet &#8220;LogicalDisk&#8221;).paths<\/p>\n<p style=\"padding-left: 30px\">$a += (Get-Counter -listSet &#8220;PhysicalDisk&#8221;).paths<\/p>\n<p style=\"padding-left: 30px\">Get-Counter -Counter $a -Continuous | Export-Counter -Path c:\\fso\\myperflog.blg<\/p>\n<p>If I run this command from the Windows PowerShell ISE, I can click the red button to halt execution of the command. If I run this from the Windows PowerShell console, I need to press Ctrl+C to halt execution. This is because I used the <i>continuous<\/i> switch. The <b>Export-Counter<\/b> cmdlet has a <i>maxsize<\/i> parameter (to limit the size of a performance log), but it does not work when the <b>Get-Counter<\/b> cmdlet is run in continuous mode.<\/p>\n<p>After I have finished collecting my data, I can open the .blg file directly in PerfMon, as shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7080.hsg-7-29-11-1.jpg\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of the .blg file opened in PerfMon\" alt=\"Image of the .blg file opened in PerfMon\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7080.hsg-7-29-11-1.jpg\" \/><\/a><\/p>\n<p>To explore the data from the performance log, I import the performance log into a variable, index into the variable, and pull out a single snapshot. Remember from <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2011\/07\/28\/use-performance-counter-sets-and-powershell-to-ease-baselining.aspx\">yesterday<\/a>, the counter set on my laptop contains more than 220 counter paths, so for each snapshot, I have more than 220 performance points to examine.<\/p>\n<p>The data I want to work with is stored in a property called <b>countersamples<\/b>. This is where I will find the information I am interested in examining.<\/p>\n<p>If I want to find all counters in the first sample (that contains 220 performance points) that have a cooked value that is greater than 3000, I use the command following this paragraph. On my laptop, quite a few counters return from the command because of the various memory counters at work (my laptop has total memory that is greater than 3000 bytes). Anyway, here is a command that will return all cooked values that are greater than 3000. In this command, the <b>[0]<\/b> is used to index into the array of performance counter information, and return the first record set of data. The <b>?<\/b> is an alias for the <b>Where-Object<\/b> cmdlet. The <b>$_<\/b> is used to refer to each performance counter as it streams across the pipeline. The curly brackets indicate a script block that is supplied to the <b>Where-Object<\/b> cmdlet:<\/p>\n<p style=\"padding-left: 30px\">$a[0].countersamples | ? {$_.cookedvalue -gt 3000 }<\/p>\n<p>To use Windows PowerShell to troll through the data and return useful information, it is necessary to use a compound query. In other words, I want to find counters that contain a certain word and have a certain value. For example, suppose I notice I have an issue with disk utilization. I might use a command such as the one shown here to identify all counters that contain the word <i>logicaldisk <\/i>in the path and that have a cooked value that is greater than 2. The reason for this query is that a <b>diskqueue<\/b> length greater than 2 could be signs of a problem. Here is the command (when using the <b>&ndash;AND<\/b> operator in a <b>Where-Object<\/b> cmdlet, it is necessary to repeat the <b>$_<\/b> for each property with which you wish to work):<\/p>\n<p style=\"padding-left: 30px\">$a[0].countersamples | ? {$_.path -match &#8216;logicaldisk&#8217; -AND $_.cookedvalue -gt 2 }<\/p>\n<p>&nbsp;<\/p>\n<p>The output, as shown here, is not too enlightening because of the large number of counters that relate to disk space:<\/p>\n<p style=\"padding-left: 30px\"><span style=\"text-decoration: underline\">Path<\/span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"text-decoration: underline\">InstanceName<\/span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <span style=\"text-decoration: underline\">CookedValue<\/span><\/p>\n<p style=\"padding-left: 30px\">\\\\edwils1\\logicaldisk(harddiskvolume1)\\% free space&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; harddiskvolume1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 94.3312101910828<\/p>\n<p style=\"padding-left: 30px\">\\\\edwils1\\logicaldisk(_total)\\% free space &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _total&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 38.6717598265006<\/p>\n<p style=\"padding-left: 30px\">\\\\edwils1\\logicaldisk(c:)\\% free space&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 38.0932520373644<\/p>\n<p style=\"padding-left: 30px\">\\\\edwils1\\logicaldisk(harddiskvolume1)\\free megabytes&nbsp;&nbsp;&nbsp;&nbsp; harddiskvolume1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 1481<\/p>\n<p style=\"padding-left: 30px\">\\\\edwils1\\logicaldisk(_total)\\free megabytes&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _total&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 59022<\/p>\n<p style=\"padding-left: 30px\">\\\\edwils1\\logicaldisk(c:)\\free megabytes&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; c:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 57541<\/p>\n<p>&nbsp;<\/p>\n<p>I can now begin to filter out the information, because I have a good idea of the type of data with which I am working. I also know that many of the returned counters are returning percentages of free space, and that is a value I am not too interested in right now. Because I am working with a collection of 195 different readings, one might be tempted to use the <b>ForEach-Object<\/b> cmdlet to work through the <b>countersamples<\/b>. After all, I did have to index into the array to begin working with the <b>countersamples<\/b>. The following command would work. It would also return only counters that match <b>logicaldisks<\/b>, but do not have the word free in the path:<\/p>\n<p style=\"padding-left: 30px\">$a | % {$_.countersamples | ? {$_.path -match &#8216;logicaldisk&#8217; -AND $_.path -notmatch &#8220;free&#8221; -And $_.cookedvalue -gt 2 } }<\/p>\n<p>A better approach, however, is to use the <b>expandproperty<\/b><i> <\/i>property from the <b>Select-Object<\/b> cmdlet. This avoids the performance hit of interrupting the stream across the pipeline. To make the output easier to read, I pipe the output to the <b>Format-Table<\/b> cmdlet (this is one logical command that has broken across multiple lines; I have not included any line-continuation characters):<\/p>\n<p style=\"padding-left: 30px\">$a | select -ExpandProperty countersamples | ? {$_.path -match &#8216;logicaldisk&#8217; -AND $_.path -n<\/p>\n<p style=\"padding-left: 30px\">otmatch &#8220;free&#8221; -And $_.cookedvalue -gt 2 } | ft cookedvalue, instancename, path &ndash;auto<\/p>\n<p>The command and associated output are shown in the following figure.<\/p>\n<p>&nbsp;<a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1185.HSG-7-29-11-02.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of command and associated output\" alt=\"Image of command and associated output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1185.HSG-7-29-11-02.png\" \/><\/a><\/p>\n<p>But, I had said, I thought I had a problem with the disk queue. I change my query around a bit. For one thing, I do not need to exclude any counters with the word <i>free<\/i> in the path because I am looking for items to do with the disk queue. I am specifically interested in any counter dealing with a disk queue that has a length greater than 2. I pipe the results to the <b>Format-Table<\/b> cmdlet to make the display a bit easier to read. Here is the command (keep in mind it is a single-line command, and I have not added any line-continuation characters; therefore, if you run this command, make sure it is a single line):<\/p>\n<p style=\"padding-left: 30px\">$a | select -ExpandProperty countersamples | ? {$_.path -like &#8216;*logicaldisk*queue*&#8217; -And $_.<\/p>\n<p style=\"padding-left: 30px\">cookedvalue -gt 2 } | ft instancename, cookedvalue, path -auto<\/p>\n<p>The command and associated output are shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4237.HSG-7-29-11-03.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of command and associated output\" alt=\"Image of command and associated output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4237.HSG-7-29-11-03.png\" \/><\/a><\/p>\n<p>Scrolling through the list, it is not obvious which problem I might actually have. I decide to sort the list. First, I sort by the queue length. I want the largest numbers on top, so I use the <i>descending<\/i> switched parameter. Once again, this is a single command:<\/p>\n<p style=\"padding-left: 30px\">$a | select -ExpandProperty countersamples | ? {$_.path -like &#8216;*logicaldisk*queue*&#8217; -AND $_.<\/p>\n<p style=\"padding-left: 30px\">path -notmatch &#8220;free&#8221; -And $_.cookedvalue -gt 2 } | sort cookedvalue -desc| ft instancename, cookedv<\/p>\n<p style=\"padding-left: 30px\">alue, path &ndash;auto<\/p>\n<p>The command and associated output are shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1452.HSG-7-29-11-04.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of command and associated output\" alt=\"Image of command and associated output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/1452.HSG-7-29-11-04.png\" \/><\/a><\/p>\n<p>I think I would like to see the counters sorted by path name. This will give me a feel for the ranges involved. The command is shown here (this is a single-line command; I have not included the backtick line continuation character):<\/p>\n<p style=\"padding-left: 30px\">$a | select -ExpandProperty countersamples | ? {$_.path -like &#8216;*logicaldisk*queue*&#8217; -AND $_.<\/p>\n<p style=\"padding-left: 30px\">path -notmatch &#8220;free&#8221; -And $_.cookedvalue -gt 2 } | sort path | ft instancename, cookedvalue, path &#8211;<\/p>\n<p style=\"padding-left: 30px\">auto<\/p>\n<p>The command and associated output are shown here.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6710.HSG-7-29-11-05.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of command and associated output\" alt=\"Image of command and associated output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6710.HSG-7-29-11-05.png\" \/><\/a><\/p>\n<p>Well, that is all there is to working with performance logs in Windows PowerShell.<\/p>\n<p>&nbsp;<\/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\">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><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Learn how to create and parse performance monitor logs by using Windows PowerShell. &nbsp; Hey, Scripting Guy! I am wondering if I can use Windows PowerShell to create a performance counter log that I can use in Perfmon? &nbsp; &mdash;CS &nbsp; Hello CS, Microsoft Scripting Guy Ed Wilson here. After I finished giving my [&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":[31,60,3,45],"class_list":["post-13171","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-operating-system","tag-performance","tag-scripting-guy","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Learn how to create and parse performance monitor logs by using Windows PowerShell. &nbsp; Hey, Scripting Guy! I am wondering if I can use Windows PowerShell to create a performance counter log that I can use in Perfmon? &nbsp; &mdash;CS &nbsp; Hello CS, Microsoft Scripting Guy Ed Wilson here. After I finished giving my [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/13171","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=13171"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/13171\/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=13171"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=13171"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=13171"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}