Retrieve average CPU-workload with Get-Counter - powershell

I am looking for a way to retrieve the average CPU-workload with PowerShell.
At the beginning of a script, I want to start the tracking of the CPU-workload and when it is finished I want to get the average CPU-workload between. (like 71.5%)
After a research on the web I started using a (PowerShell-)"job" for this purpose, but I was not able to get it working. This is the reduced code I have till now:
$JobObject = Start-Job -Name "MyJob" -ScriptBlock {
Get-Counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -Continuous
}
Start-Sleep -Seconds 5
$Result = Receive-Job -Job $JobObject
I was not able to simple get the average of captured values.
How to get this working?
Thank you
Edit: It is not a requirement by me to make use of jobs.

You could calculate the average separately after receiving the job:
$JobObject = Start-Job -Name "MyJob" -ScriptBlock {
Get-Counter -Counter "\Processor(_Total)\% Processor Time" -SampleInterval 1 -Continuous
}
Start-Sleep -Seconds 5
$Result = Receive-Job -Job $JobObject
$Result.Readings | Foreach-Object { ($_ -split ':')[-1].Trim() } |
Measure-Object -Average | Select-Object #{n='Average';e={"{0:f2}" -f $_.Average}}
Explanation:
$Result.Readings contains all of your sample readings in string format. You will have to parse the CPU percentage from that.
-split ':' creates an array by separating the input string by :. The resulting array contains as many elements as there are : characters. Since we only want the number after the final :, index [-1] is used.
The format operator -f requires a specific syntax. The {0} syntax represents a placeholder for the first object after the -f. {1} would represent the second object. A trivial example would be "{0}=={1}" -f $var1,$var2, which will output string versions of $var1 and $var2 separated by a ==. The {0:f2} tells PowerShell to format the first object (indicated by 0) using a fixed decimal (indicated by f) to two places (indicated by 2).

Related

Why does my Powershell IF...Else loop always do the ELSE statement, no matter what the variable result is?

I am making a simple script for my internship in powershell, that uses simple stuff like variables, the IF...ELSE statement, as well as Get-Counter.
$CpuLoad = "\Processor(_Total)\% Processor Time"
$Threshold = 50
Get-Counter -Counter $CpuLoad -SampleInterval 1 -MaxSamples 10
IF($CpuLoad -gt $Threshold) {
Write-Host "CPU Utilizacija ir lielaka par 50 procentiem!"
} Else {
Write-Host "Viss ok!"
}
That is the script. No matter what the CPU utilization percentage is, it will always say the ELSE write-host statement, not the IF write-host statement. Do not worry. I am not trying to cheat or anything of the sort ;). I'm simply dumb-founded as to how such a simple script can break so easily! Any help is appreciated!
Comparing the string "\Processor(_Total)\% Processor Time" to the number 50 doesn't make much sense.
Instead, use Where-Object to test if any of the counter samples returned by Get-Counter exceeds the threshold:
$CpuLoad = "\Processor(_Total)\% Processor Time"
$Threshold = 50
$samplesExceedingThreshold = Get-Counter -Counter $CpuLoad -SampleInterval 1 -MaxSamples 10 |ForEach-Object CounterSamples |Where-Object CookedValue -gt $threshold |Select-Object -First 1
if($samplesExcheedingThreshold){
Write-Host "CPU Utilizacija ir lielaka par 50 procentiem!"
} else {
Write-Host "Viss ok!"
}

Get-Job Format-Table with Runtimes of Jobs

I am trying to write a PowerShell 5.1 script for monitoring jobs.
I am having a problem writing a proper Get-Job table, the following is what I have.
Get-Job | Format-Table -AutoSize -Property name, state, #{name = 'Runtime'; Expression = {$((get-date)-($_.psbegintime)).ToString('HH:mm')}}
What this code returns is a table of named jobs and states, but does populate the runtime column. It works if I remove the .ToString('HH:mm') from the code but that populates the runtime column with Hour:Minute:Second:Millisecond in this format HH:mm:ss:fffffff. How do I remove the Seconds and Milliseconds part?
The reason why .ToString(HH:mm) doesn't work is because the result of:
Get-Date - $_.PSBeginTime
Is not a datetime object, it's a timespan object. Calling .ToString(HH:mm) on a timespan object throws the following exception:
MethodInvocationException: Exception calling "ToString" with "1" argument(s): "Input string was not in a correct format."
According to TimeSpan.ToString MS Docs formatting is possible however the format is .ToString('hh\:mm\:ss').
Here you have an example of how to achieve what you're looking for:
$testJobs = 5
$jobs = 1..$testJobs | ForEach-Object {
Start-Job {
'Hello from Job {0}' -f $using:_
Start-Sleep ([random]::new().Next(5,10))
}
}
while($jobs.State -contains 'Running')
{
Clear-Host
Get-Job | Format-Table -AutoSize -Property Name, State, #{
Name = 'Runtime'
Expression = {
([datetime]::Now - $_.PSBeginTime).ToString('hh\:mm\:ss')
# .ToString('hh\:mm') for Hours and Minutes only.
}
}
Start-Sleep 1
}
$jobs | Receive-Job -Wait -AutoRemoveJob
This answer shows a similar, more developed alternative, using a function to wait for Jobs with progress and a optional TimeOut parameter.

Using Get-Job to test-connection, but quite different [duplicate]

This question already has answers here:
If using Test-Connection on multiple computers with -Quiet how do I know which result is for which computer?
(2 answers)
Closed 2 years ago.
It's my first post here, I'm tring to write scripts on PS on my own, now my target is to write script that checks if computer is online at network, for example: test-Connection 192.168.0.1, 2, 3 etc. Doing this one by one on loop for takes some time if some computers are offline, I've found some tutorials on this site to use -AsJob param, but I'm not really Sure how could it work. I mean I'd like to output every checked PC to excel, so i need if operator. eg:
if (Job1 completed successfull (computer pings)){
do smth}...
I need to get output from Job boolean (true/false), but one by one. I'm taking my first steps in PS, I've made program that checks it one by one in for loop, but as i said it take some time till my excel file fill...
I can see, that AsJob makes working more effective and I think it's important to understand it
Thanks and sorry for bad text formatting, by the time I'll go on with this!
In your example, in the Start-Job scriptblock you are trying to access $_ which is not available in the codeblock scope. If you replace $_ with $args[0] it should work since you are passing in the $ip value as an argument
Your Example
$ipki = Get-Content 'C:\Users\pchor\Desktop\ipki.txt'
foreach ($ip in $ipki) {
Start-Job -Name "$ip" -ScriptBlock {
Test-Connection $_ -Count 1 # <---- replace $_ with $args[0]
} -ArgumentList $_ # <----- change $_ to $ip
}
You'll probably also want to wait for all the jobs to finish. I recommend something like this
$computers = #(
'www.google.com'
'www.yahoo.com'
)
$jobs = $computers |
ForEach-Object {
Start-Job -ScriptBlock {
[pscustomobject]#{
Computer = $using:_
Alive = Test-Connection $using:_ -Count 1 -Quiet
}
}
}
# Loop until all jobs have stopped running
While ($jobs |
Where-Object { $_.state -eq 'Running' }) {
"# of jobs still running $( ($jobs | Where-Object {$_.state -eq 'Running'}).Count )";
Start-Sleep -Seconds 2
}
$results = $jobs | Receive-Job | Select-Object Computer, Alive
$results | Format-Table
Output
Computer Alive
-------- -----
www.google.com True
www.yahoo.com True
To modify the properties to what you want there are different ways of doing this. Easiest in this case is probably to use a calculated property
$newResults = $results |
Select-Object Computer,
#{Label = 'State'; Expression = { if ($_.Alive) { 'Online' } else { 'Offline' } } }
Objects will now look like this (I added another fake address to illustrate offline state)
Computer State
-------- -----
www.google.com Online
www.yahoo.com Online
xxx.NotAValidAddress.xxx Offline
You can then export the objects to csv using Export-csv
$newResults | Export-Csv -Path c:\temp\output.csv

Powershell memory load percentage

I currently have this script which I am trying to get to display the % of processor load. Its returns results and seemingly reports correctly but it doesnt show the actual % in the output:
SCRIPT:
$Servers = Get-QADComputer -sizelimit 0 | where {$_.Name -like "*MYSERVER*"} | select Name | sort name
# Best practice: avoid magic numbers; readonly variable for
new-variable -name CPULIMIT -value 75 -option readonly
foreach($Server in $Servers){
$result = Get-WmiObject win32_processor -ComputerName $Server.Name
# TODO: add error handler here in case $server is unavailable
# Compare the wmi query result to the limit constant
if($result.LoadPercentage -le $CPULIMIT){
# Write a formatted string that contains the server name and current load
Write-Host $("Less than 75% Processor Load on {0} ({1}%)" -f $server.name, $result.LoadPercentage) -ForegroundColor "Green"
} else {
# A warning message would be usefull too
Write-Host $("More than 75% Processor Load on {0} ({1}%)" -f $server.name, $result.LoadPercentage) -ForegroundColor "Red"
}
}
OUTPUT:
Less than 75% CPU Load on MYSERVER1 (%)
Less than 75% CPU Load on MYSERVER2 (%)
Less than 75% CPU Load on MYSERVER3 (%)
Less than 75% CPU Load on MYSERVER4 (%)
As you can see there is now over all (%) displayed.
Any ideas would be greatly apprecaited.
Thanks
Jon Z adjustement of $result[0].LoadPercentage worked perfectly. Thank you.

Powershell Get a specific process counter with id process

I want to get specific counters for processes that I have process id's for. However I can't think of a way to use where-object to match the process for the counter.
Like
Where Gc '\process(*)\id process -eq 456 gc '\process($name)\working set'
So use the process id to retrieve the name and get the working set (or something to that effect).
It seems a bit convoluted to get the correct performance counter path for a process with multiple instances of the same process name:
$proc_id=6580
$proc_path=((Get-Counter "\Process(*)\ID Process").CounterSamples | ? {$_.RawValue -eq $proc_id}).Path
Get-Counter ($proc_path -replace "\\id process$","\% Processor Time")
Timestamp CounterSamples
--------- --------------
11/20/2014 5:39:15 PM \\myhost\process(conhost#2)\% processor time :
0
You can get counters for a process name so first get the process name by using its Id and then embed the process name in the counter. For example:
$id = # your process id
$proc = (Get-Process -Id $id).Name
Get-Counter -Counter "\Process($proc)\% Processor Time"
If you want a solution that also include process with multiple instance IDs you can use :
$p = $((Get-Counter '\Process(*)\ID Process' -ErrorAction SilentlyContinue).CounterSamples | % {[regex]$a = "^.*\($([regex]::Escape($_.InstanceName))(.*)\).*$";[PSCustomObject]#{InstanceName=$_.InstanceName;PID=$_.CookedValue;InstanceId=$a.Matches($($_.Path)).groups[1].value}})
# In french, use '\processus(*)\id de processus' for the counter name
$id = # your process id
$p1 = $p | where {$_.PID -eq $id}
Get-Counter -Counter "\Process($($p1.InstanceName+$p1.InstanceId))\% Processor Time"
# In french, use "\Processus($($p1.InstanceName+$p1.InstanceId))\% temps processeur" for the counter name
Or if you avoid to use Get-Counter and wait the sample interval, try use WMI:
$id = YourProcessIdHere
(gwmi -class Win32_PerfRawData_PerfProc_Process -Namespace "root\CIMV2" | ? {$_.IdProcess -eq $id}).Name;
It is possible to obtain some performance information with the Get-Process commandlet directly and avoid the need to resolve an instance ID.
For the case of the memory working set, just filter the output for the process id you want using where-object, then select the parameters you're interested in:
get-process | where-object{ $_.id -eq 456 } | select name,workingset