{"id":170,"date":"2019-01-29T02:41:27","date_gmt":"2019-01-29T07:41:27","guid":{"rendered":"http:\/\/itblog.ldlnet.net\/?p=170"},"modified":"2019-01-29T06:47:34","modified_gmt":"2019-01-29T11:47:34","slug":"measuring-cpu-processor-times-per-core-across-multiple-servers-through-powershell","status":"publish","type":"post","link":"https:\/\/itblog.ldlnet.net\/index.php\/2019\/01\/29\/measuring-cpu-processor-times-per-core-across-multiple-servers-through-powershell\/","title":{"rendered":"Measuring CPU Processor Times Per Core Across Multiple Servers through PowerShell."},"content":{"rendered":"\n<h4 class=\"wp-block-heading\" style=\"text-align:center\"><em>I want to thank Jason Field for the bulk of this script!<\/em><\/h4>\n\n\n\n<p>Our team was presented with an issue where we needed to measure the CPU Percentage Processor Times for Each Core within the Physical Processor and be able to output that data quickly through PowerShell. We all have knowledge that Performance Monitor can do this through a GUI, but it is very difficult to be able to output that data to a file in a manner that can be easily read. We had an original PowerShell cmdlet that would accomplish this for the total percent processor time for all cores over a one minute period:<\/p>\n\n\n<pre class=\"lang:PowerShell\" title=\"Get-Counter Script for % Total Processor Time\">\"Average Processor Time for 60 seconds: $([math]::round((get-counter -Counter \"\\Processor(_Total)\\% Processor Time\" -SampleInterval 1 -MaxSamples 60 |  select -ExpandProperty countersamples | select -ExpandProperty cookedvalue | Measure-Object -Average).average,2))%\"<\/pre>\n\n\n\n<p>Our challenge was to be able to do this per core, over the same time period, and get the average for each core, so that we could measure the output accordingly. I had been working on a script that was able to run the command, but not in a parallel fashion. The script was running in sequence and was taking way longer than one minute to complete. Frustrating to say the least.<\/p>\n\n\n\n<p>In comes Jason Field, showing me the meaning and value of the back tick  as well has how to run and monitor job functions in a PowerShell Script so that the task could be completed, as needed, across a server array.<\/p>\n\n\n\n<p>The main purpose of the (back tick) is that it allows for variables to be used in the script block on the remote server instead of being filled in before creating the script block. <br><\/p>\n\n\n\n<h4 class=\"wp-block-heading\"><em>Here&nbsp;is&nbsp;the&nbsp;script:<\/em><\/h4>\n\n\n<pre class=\"lang:PowerShell\" title=\"CPUProcTimeForArray.ps1\"><# CPUProcTimeForArray.ps1 - This Script is prepared by Jason Field. Modified by Lance Lingerfelt - LDLNET LLC. #> \n<# The script has been prepared and tested in Powershell 4.0. So when you run this script, please make sure that the Powershell version is 4.0 or above. #> \n<# This script will measure the Percentage Processor Time of each CPU core in each target server in your server array for one minute and average it for a total of four cores per processor. The results will be exported to a CSV file in C:\\Reports #> \n<# Please Adjust the Script as needed for your Server Array and number of total Processor Cores that need to be measured. #> \n<# While this script has been tested multiple times, it is recommended that you test it in a test environment before using it in a production environment. #> \n<# While every attempt has been made to make this script error free, we do not take any responsibility for any consequence that would happen while running the script. Modifications to the script are not our responsibility either.#>\n\nWrite-Host \"This script will measure the Percentage Processor Time of each CPU core in each target server in your server array for one minute and average it for a total of four cores per processor. The results will be exported to a CSV file in C:\\Reports\" -ForegroundColor Green\nWrite-Host \"Please Adjust the Script as needed for your Server Array and number of total Processor Cores that need to be measured.\" -ForegroundColor Yellow\n\n$results=@()\n$jobs=@()\n$date = Get-Date -Format G\n\n\n#Set your Server array of hosts to be processed.\n$servers = \"Server01\",\"Server02\",\"Server03\",\"Server04\",\"Server05\",\"Server06\"\n\nForeach($server in $servers){\nIf($server -eq $env:computername){\n               \n               $script = \"\n\n               `$counter = Get-Counter -ComputerName $server '\\Processor(*)\\% Processor Time' -SampleInterval 1 -MaxSamples 60\n               `$Counter = `$counter.Countersamples\n               `$Core1 = [math]::Round(((`$counter | where{`$_.instancename -eq '0'} | Measure-Object -Property CookedValue -Average).average),2)\n               `$Core2 = [math]::Round(((`$counter | where{`$_.instancename -eq '1'} | Measure-Object -Property CookedValue -Average).average),2)\n               `$Core3 = [math]::Round(((`$counter | where{`$_.instancename -eq '2'} | Measure-Object -Property CookedValue -Average).average),2)\n               `$Core4 = [math]::Round(((`$counter | where{`$_.instancename -eq '3'} | Measure-Object -Property CookedValue -Average).average),2)\n               `$ALLCores = [math]::Round(((`$counter[0..3] | Measure-Object -Property Cookedvalue -Average).average),2)\n\n               `$ServerReport = New-Object -TypeName PSObject -Property @{\n               Server = '$server'\n               LongJoins = `$longJoin\n               Core1 = `$Core1\n               Core2 = `$Core2\n               Core3 = `$Core3\n               Core4 = `$Core4\n               ALLCores =`$ALLCores\n\n                              }\n               `$ServerReport   \n               \"\n               \n               $scriptblock = [scriptblock]::Create($Script)\n               \n               $Session = New-PSSession  \n                              \n               $jobs+=Invoke-Command -Session $Session -ErrorAction 'SilentlyContinue' -ScriptBlock $scriptblock -asjob\n               \n               } \n\nElse{\n               $Session = New-PSSession -ComputerName $server \n                              \n               $script = \"\n\n               `$counter = Get-Counter -ComputerName $server '\\Processor(*)\\% Processor Time' -SampleInterval 1 -MaxSamples 60 \n               `$Counter = `$counter.Countersamples\n               `$Core1 = [math]::Round(((`$counter | where{`$_.instancename -eq '0'} | Measure-Object -Property CookedValue -Average).average),2)\n               `$Core2 = [math]::Round(((`$counter | where{`$_.instancename -eq '1'} | Measure-Object -Property CookedValue -Average).average),2)\n               `$Core3 = [math]::Round(((`$counter | where{`$_.instancename -eq '2'} | Measure-Object -Property CookedValue -Average).average),2)\n               `$Core4 = [math]::Round(((`$counter | where{`$_.instancename -eq '3'} | Measure-Object -Property CookedValue -Average).average),2)\n               `$ALLCores = [math]::Round(((`$counter[0..3] | Measure-Object -Property Cookedvalue -Average).average),2)\n\n               `$ServerReport = New-Object -TypeName PSObject -Property @{\n               Server = '$server'\n               LongJoins = `$longJoin\n               Core1 = `$Core1\n               Core2 = `$Core2\n               Core3 = `$Core3\n               Core4 = `$Core4\n               ALLCores =`$ALLCores\n\n                              }\n               `$ServerReport   \n               \"\n\n                              $scriptblock = [scriptblock]::Create($Script)\n                              $jobs+=Invoke-Command -Session $Session -ErrorAction 'SilentlyContinue' -ScriptBlock $scriptblock -asjob\n               }\n}\n               \n$ActiveJobs=Get-Job\n               while ($ActiveJobs){\n               $CompletedJobs=Get-Job -State 'Completed' \n               if ($CompletedJobs) {\n                              Write-output (\"Checking {0} job(s) out of remaining {1}\" -f $CompletedJobs.count, $ActiveJobs.count)\n                              foreach ($job in $CompletedJobs) {\n                                             #Adds completed jobs to Results \n                                             $results+=Receive-Job -Id $job.ID\n                                             Remove-Job -Id $job.id\n                              }\n               }\n               #Checks for failed jobs and reports on failed jobs\n               $FailedJobs=Get-Job -State 'FAILED'\n               if ($FailedJobs) {\n                              Write-output (\"Checking failed jobs\")\n                              foreach ($job in $FailedJobs) {$cpu\n                                             Write-Output (\"Failed Job Removed\")                                    \n                                             $results+=Receive-Job -Id $job.ID\n                                             Remove-Job -Id $job.id\n                              }\n               \n                                             }\n               \n                              $ActiveJobs=Get-Job\n                              if($ActiveJobs) {sleep 30}\n               }\n               \n#Remove Sessions\nGet-PSSession | Remove-PSSession\n\n#Gathers Results\n$date\n$results | Select Server,Core1,Core2,Core3,Core4,ALLCores\n\n#Exports Results to CSV\n$results | Select Server,Core1,Core2,Core3,Core4,ALLCores | Export-csv c:\\Reports\\CPUProcTimeForArray.csv -NoTypeInformation<\/pre>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter is-resized\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/itblog.ldlnet.net\/wp-content\/uploads\/2019\/01\/CPUProcTimeForArray-1024x364.png\" alt=\"\" class=\"wp-image-171\" width=\"698\" height=\"248\" srcset=\"https:\/\/itblog.ldlnet.net\/wp-content\/uploads\/2019\/01\/CPUProcTimeForArray-1024x364.png 1024w, https:\/\/itblog.ldlnet.net\/wp-content\/uploads\/2019\/01\/CPUProcTimeForArray-300x107.png 300w, https:\/\/itblog.ldlnet.net\/wp-content\/uploads\/2019\/01\/CPUProcTimeForArray-768x273.png 768w, https:\/\/itblog.ldlnet.net\/wp-content\/uploads\/2019\/01\/CPUProcTimeForArray.png 1705w\" sizes=\"auto, (max-width: 698px) 100vw, 698px\" \/><figcaption><em>Sample Output from the Script.<\/em><\/figcaption><\/figure><\/div>\n\n\n\n<p>What I learned from this script is that the back tick <strong>&#8221; ` &#8220;<\/strong> allows for multiple commands to be run in a sub-routine within the script job and be gathered before the main script command is run and the output given. This gets past the multi-threading issue I was having with my original script. The script can then be run across multiple servers using the Invoke-Command cmdlet or over a remote PowerShell session as a Job. The jobs can then be monitored as the scripts finish across the multiple servers in the time period given for the samples. I had modified the script to do the multiple samples and then take the average of the CookedValue per the original cmdlet. I could not, however, get the ExpandProperty parameter to work with the script.<\/p>\n\n\n\n<p style=\"text-align:center\" class=\"has-text-color has-small-font-size has-medium-pink-color\"><strong><em>Please,&nbsp;as I am still learning, if&nbsp;you&nbsp;see&nbsp;an&nbsp;error&nbsp;with&nbsp;this&nbsp;script,&nbsp;please&nbsp;alert&nbsp;me&nbsp;with&nbsp;a&nbsp;comment&nbsp;or&nbsp;contact&nbsp;me&nbsp;directly&nbsp;so&nbsp;that&nbsp;I&nbsp;can&nbsp;update&nbsp;the&nbsp;script&nbsp;properly.&nbsp;<\/em><\/strong><\/p>\n\n\n\n<p>Thanks again Jason! It really was like a light bulb going <em>&#8220;DING&#8221;<\/em> when I figured it out with concern to the back tick. I had also been having issues with the active job monitoring process. It was a real help!<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" style=\"text-align:center\">PLEASE COMMENT, SHARE, AND HAPPY TROUBLESHOOTING!<\/h2>\n","protected":false},"excerpt":{"rendered":"<p>I want to thank Jason Field for the bulk of this script! Our team was presented with an issue where we needed<\/p>\n<p class=\"link-more\"><a class=\"myButt \" href=\"https:\/\/itblog.ldlnet.net\/index.php\/2019\/01\/29\/measuring-cpu-processor-times-per-core-across-multiple-servers-through-powershell\/\">Read More<\/a><\/p>\n","protected":false},"author":1,"featured_media":159,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2,3,16],"tags":[66,15,68,19,25,8,67,13],"class_list":["post-170","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-general","category-powershell","category-windows","tag-back-tick","tag-cmdlet","tag-jobs","tag-perfmon","tag-performance","tag-powershell","tag-powershell-jobs","tag-script","odd"],"_links":{"self":[{"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/posts\/170","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/comments?post=170"}],"version-history":[{"count":6,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/posts\/170\/revisions"}],"predecessor-version":[{"id":183,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/posts\/170\/revisions\/183"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/media\/159"}],"wp:attachment":[{"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/media?parent=170"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/categories?post=170"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itblog.ldlnet.net\/index.php\/wp-json\/wp\/v2\/tags?post=170"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}