Top 5 Processes with CPU % and Process ID using Powershell - powershell

I tried this script
Get-Counter -ErrorAction SilentlyContinue '\Process(*)\% Processor Time' |
Select -ExpandProperty countersamples |
?{$_.instanceName -notmatch "^(idle|_total|system)$"} |
Sort -Descending cookedvalue |
Select -First 5 #{
L='ProcessName';
E={[regex]::matches($_.Path,'.*process\((.*)\)\\% processor.*').groups[1].value}
},
#{
L='CPU';
E={($_.Cookedvalue/100/$env:NUMBER_OF_PROCESSORS).toString('P')}
},
#{
L='ProcessId';
E={((Get-Counter "\Process([regex]::matches($_.Path,'.*process\((.*)\)\\% processor.*').groups[1].value)\ID Process" -ErrorAction SilentlyContinue).CounterSamples).Cookedvalue}
}
I am able to get ProcessName and CPU % columns but not ProcessID
ProcessName CPU ProcessId
----------- --- ---------
firefox#4 0.58%
svchost#11 0.19%
firefox#6 0.19%
dwm 0.10%
svchost#39 0.10%

Make sure you request both the % Processor Time and ID Process counter from each counter instance, then use Group-Object to group them together.
Worth noting is that you don't need regex to correlate the two, simply group on the first part of the counter path (\Process(notepad#3)). Regex is also not needed for extracting the process name, since each sample already has an InstanceName property with the corresponding process name.
Once you've correlated name + process ID + sample value, you can start sorting, and then finally format the CPU percentage:
Get-Counter '\Process(*)\ID Process','\Process(*)\% Processor Time' -ErrorAction SilentlyContinue |
ForEach-Object {
$_.CounterSamples |
Where-Object InstanceName -NotMatch '^(?:idle|_total|system)$' |
Group-Object {Split-Path $_.Path} |
ForEach-Object {
[pscustomobject]#{
ProcessName = $_.Group[0].InstanceName
ProcessId = $_.Group |? Path -like '*\ID Process' |% RawValue
CPUCooked = $_.Group |? Path -like '*\% Processor Time' |% CookedValue
}
} |Sort-Object CPUCooked -Descending |
Select-Object -First 5 -Property *,#{Name='CPUPercentage';Expression={'{0:P}' -f ($_.CPUCooked / 100 / $env:NUMBER_OF_PROCESSORS)}} -ExcludeProperty CPUCooked
}

Related

Retrieving CPU details in Powershell

I am planning to extract the CPU details to my powershell requirement. Below is the highlighted parameter that I am trying to extract.
I have tried using Get-WmiObject Win32_Process or Get-Process but no luck with it. Can you guide with the cmdlet which can be helpful for this
Updated Question
Get-Counter '\Process(*)\% Processor Time' |
Select-Object -ExpandProperty countersamples |
Select-Object -Property instancename, cookedvalue|
Sort-Object -Property cookedvalue -Descending |
Select-Object| ft InstanceName,#{L='CPU';E={($_.Cookedvalue/100).toString('P')}} -AutoSize
I am using this code as suggested in the below comments. and below is the output which I am receiving.
However if you compare the value for PS output and the task manager screenshot, its quite different, since in task manager most of them are 0
Updated Part 2
I have extracted this code from another post.
$NumberOfLogicalProcessors=(Get-WmiObject -class Win32_processor | Measure-Object -Sum NumberOfLogicalProcessors).Sum
(Get-Counter '\Process(*)\% Processor Time').Countersamples | Sort cookedvalue -Desc | ft -a instancename, #{Name='CPU %';Expr={[Math]::Round($_.CookedValue / $NumberOfLogicalProcessors)}}
This may be working, but I would like to get your opinions on these since the value for this is dynamic and pretty difficult to verify
try this:
$Utilization = #()
Get-WmiObject Win32_PerfFormattedData_PerfProc_Process | Sort-Object -Property PercentProcessorTime -descending | ? { $_.name -inotmatch '_total|idle' } | % {$Utilization += [PSCustomObject]#{'Process Name' = $_.Name; 'pid' = $_.IDProcess; 'Usage' = $_.PercentProcessorTime}}

How can know the usage of CPU of a windows service in an interval of time with PowerShell?

I am a beginner with PowerShell, How can know the usage of CPU of a windows service in an interval of time (for example for one hour) with PowerShell?
Something like this:
Get-Service | Get-counter
Thank so much
For CPU usage you need to use the get-process commandlet and then map the process name with the corresponding service.
Here is one of the past discussion thread where the get-process is discussed
Listing processes by CPU usage percentage in powershell
Sample code here
$Details = #()
$AllRunningServices = Get-CimInstance -class win32_service | Where-Object {$_.State -eq 'Running'} | Select-Object ProcessId , Name
foreach($procid in $AllRunningServices)
{
$Details += Get-Process | Where-Object {$_.Id -eq $procid.ProcessId} | Select-Object ProcessName, Id, CPU , #{Name = "serviceName" ; Expression={$procid.Name}}
}
$Details |Sort-Object -Property CPU -Descending | ft

Gathering the average values of Get-Counter outputs

I am currently trying to gather the average performance values of processes over a long period of time. Unfortunately, my script is only able to average all the gathered values, rather than the averages of the individual processes.
The script below is what I ended up with, which unfortunately doesn't give an output for each respective process:
Write-Output (Get-Counter -Counter "\Processor(_Total)\% Processor Time","\Process(Chrome)\% Processor Time" -SampleInterval 1 -MaxSamples 25 |
Select-Object -ExpandProperty CounterSamples |
Select-Object -ExpandProperty CookedValue |
Measure-Object -Average).Average
Ideally, I'd like to have an object with the output values formatted like so:
Output.chrome = 5.1283123
Output.total = 23.128732
This works for me:
Get-Counter -Counter "\Processor(_Total)\% Processor Time","\Process(Chrome)\% Processor Time" -SampleInterval 1 -MaxSamples 25 `
| Select-Object -ExpandProperty CounterSamples `
| Group-Object -Property InstanceName `
| ForEach-Object {
$_ | Select-Object -Property Name, #{n='Average';e={($_.Group.CookedValue | Measure-Object -Average).Average}};
} `
| Format-Table -AutoSize;
Output:
Name Average
---- -------
_total 11.8878325281858
chrome 4.80058851283048
It'd be easy enough to conditionally rename the names.
EDIT: Try this for PowerShell v2.0:
Get-Counter -Counter "\Processor(_Total)\% Processor Time","\Process(Chrome)\% Processor Time" -SampleInterval 1 -MaxSamples 25 `
| Select-Object -ExpandProperty CounterSamples `
| Group-Object -Property InstanceName `
| ForEach-Object {
$_ | Select-Object -Property Name, #{n='Average';e={(($_.Group | Measure-Object -Property CookedValue -Average).Average)}};
} `
| Format-Table -AutoSize;
Here is an approach:
$chrome = #()
$total = #()
$counterName = "\Processor(_Total)\% Processor Time","\Process(Chrome)\% Processor Time"
Get-Counter -Counter $counterName -SampleInterval 1 -MaxSamples 10 |
Select-Object -ExpandProperty countersamples | % {
$object = New-Object psobject -Property #{
InstanceName = $_.InstanceName
CookedValue = $_.CookedValue
}
if($object.InstanceName -eq "Chrome") {
$chrome += $object
} else {
$total += $object
}
}
$output = [PSCustomObject]#{
Chrome = ($chrome | Measure-Object -Average CookedValue).Average
Total = ($total| Measure-Object -Average CookedValue).Average
}
$output
Output:
Chrome Total
------ -----
5,61702990401208 31,4667298163454

Fine-tuning Get-Counter script for quicker execution

Below is my script to get process utilization of individual w3wp.exe app pools, the problem is each iteration takes about 2 seconds there are about 25 app pools. Can you please help me to fine tune the below script for faster execution.
gwmi win32_process -filter 'name="w3wp.exe"' | % {
$name=$_.name
$cmd = $pattern.Match($_.commandline).Groups[1].Value
$procid = $_.ProcessId
$tmp = (Get-Counter "\Process(*)\ID Process").CounterSamples | Where-Object {$_.CookedValue -eq $procid} | select -expand Path
$calc = [regex]::match($tmp,'\(([^\)]+)\)').Groups[1].Value
$cooked = (Get-Counter "\Process($calc)\% Processor Time").CounterSamples | Where-Object {$_.InstanceName -notlike '_total'} | select -expand CookedValue
$cpuper = [Math]::Round( ($cooked/2), 0)
echo $cpuper
}
It looks like Get-Counter has a minimum sample time of 1 second. Resulting in a minimum execution time of 1 second per call. Your best bet would be to get all the counters up front and then look for the counters you are interested in.
This does something like what you were doing. It prints the process ID and % processor time in a table.
$proc = 'w3wp'
$samples = get-counter '\Process($proc*)\ID Process', '\Process($proc*)\% Processor Time' | select -expand countersamples
$samples | group { Split-Path $_.Path } | ft #{ N='ID'; E={$_.Group[0].CookedValue} }, #{ N='% Processor'; E={[Math]::Round($_.Group[1].CookedValue/2, 0)} }

Disks' counters tabular format

Get-Counter '\PhysicalDisk(*)\% Idle Time', '\LogicalDisk(*)\Free Megabytes','\PhysicalDisk(*)\Avg. Disk sec/Read','\PhysicalDisk(*)\Avg. Disk Queue Length'|Select-Object -expandProperty countersamples|Select-Object -Property instancename, cookedvalue | ft -AutoSize
How can I format the output of the 'Get-counter' command like this.
$counters="\PhysicalDisk(*)\% Idle Time","\PhysicalDisk(*)\Avg. Disk sec/Read","\PhysicalDisk(*)\Avg. Disk Queue Length","\PhysicalDisk(*)\Avg. Disk sec/Write"
Get-Counter $counters |Select-Object -expandProperty CounterSamples | group InstanceName | foreach{
$ht=New-Object System.Collections.Specialized.OrderedDictionary
$ht.Add("Drive",$_.Name.ToUpper().Replace("_",""))
foreach($item in $_.Group){
$perfCName=$item.Path.Replace(("(" + $item.InstanceName + ")"),"").Split("\")[3,4] -join "\"
$ht.Add($perfCName,$item.CookedValue)
}
New-Object PSObject -Property $ht
} | ft