CPU usage in percentage in Powershell - powershell

I want the CPU to be displayed as a percentage at the end of the code I wrote. Is there a way?
this is my code
Get-Process svchost | % $_.CPU
Hardly made it this far, only last episode left

Thanks #Santiago for pointing out the issue that it was the reading for the same svchost instance everytime, this is fixed now.
The code below borrows heavily from this thread: Powershell Get a specific process counter with id process
to get the correct reading.
This gets you the Path, the Id and %.
$procResult = Get-Process -Name svchost
$resultObjects = #();
foreach ($result in $procResult) {
$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}})
$target = $p | where { $_.PID -eq $result.Id }
$counterResult = Get-Counter -Counter "\Process($($target.InstanceName+$target.InstanceId))\% Processor Time" -ErrorAction SilentlyContinue
if ($null -eq $counterResult) {
continue;
}
$resultObjects += [PSCustomObject]#{
Path = $result.Path
Id = $result.Id
CPU = $counterResult.CounterSamples[0].CookedValue
}
}
$resultObjects | ft
You won't get the CPU usage in % with your code above. I really do not know why you insist on not changing the structure of your code as the structure of code is irrelevant as long as it is readable and get the job done.

Related

PowerShell Test-Connection -efficient Method

One Bronze medal = Newbi 😊, have scoured this site for years, so a million belated thanks, once again!
Just finished up a few different PowerShell ver 5.1 scripts that perform a test-connection on the same 2000 devices regularly.
Out to a csv file
And they are all slow, some minor speed improvements when tweaking it down to the bare bones.
I’ve scaled the script to the minimal, IPADDRESS and NAME only
I’ve run a few comparison tests against a batch file (ping 123.456.789.001 >> PingTest.txt ) and these tests APPEAR to run quicker than my PS script (will run a full apple to apples test tomorrow), but confident something is amiss in the PS code.
Am looking at arrays, and how piping works, but am afraid I’m putting the cart in front of the horse, or there is something going on with how PS handles the csv format and/or ping list in its memory
My most efficient current script below,
Is the following link pointing me in the right direction,? Specifically the asJob switch
PowerShell Mass Test-Connection
$info = "" | Select IPaddress,Name
$OutputFile = new-item -itemType File -path C:\Temp\Results.csv -force -value "IPaddress,Name`r`n" | out-null
Import-csv C:\Temp\GetList.csv | ForEach-Object {
if ($_.IPaddress) {
if (-Not (Test-Connection -ComputerName $_.IPaddress -Quiet -Count 2 -ErrorAction SilentlyContinue)) {
$info.IPaddress = $_.IPaddress
$info.Name = $_.Name
add-content -value "$($info.IPaddress),$($info.Name)" -path C:\Temp\Results.CSV
}
}
}
The export-csv is faster, thank you. I'm not sure if I have it in the right place, but it works, will run some tests on it tomorrow. I may have to include the passes tests though , still getting my head around the get-job cmdlet.
$info = "" | Select IPaddress,Name,Status
Import-csv c:\Temp\GetList.csv | ForEach-Object {
if($_.Ipaddress) {
if (-Not(Test-Connection -ComputerName $_.IPaddress -Quiet -Count 2 -ErrorAction SilentlyContinue)) {
$info.IPaddress = $_.IPaddress
$info.Name = $_.Name
$info.Status = "Failed"
$info | export-csv C:\Temp\Results1.csv -Force -Notypeinformation -Append
}
}
}
$list = Import-Csv C:\Temp\GetList.csv
ForEach ($item In $list) {
Start-Job -ScriptBlock {
param($item)
if (Test-Connection -Computername $item.IPaddress -Quiet -Count 1) {
Add-Content -value "$($item.IPaddress),$($item.Name),$($item.Stauts)" -Path C:\Temp\xlistlist.csv
$list | Export-csv c:\Temp\xCSvreults.csv -Force -NoTypeInformation -Append
}
} -argumentlist $list
}
Thanks Santiago, I did some exploring here, just ran out of time for the day. THANK YOU you for the code examples they cleared a few things up for me :-) –
Have Computer
Dec 2 at 3:59
Would you mind adding some inline comments so I can follow along? Just trynna understand multi-threading (using runspaces) a bit better. –
Abraham Zinala
Dec 2 at 4:58
1
#AbrahamZinala is there a specific part you're struggling to understand? i'm not an expert on this and wouldn't like to give false information. Might be better to pick up all the parts you don't understand and ask a new question –
Santiago Squarzon
Dec 2 at 12:19
Nah man, sorry, I figured it out lol –
Abraham Zinala
Dec 2 at 13:43
1
#AbrahamZinala the only hard part to understand is the [powershell] instance part imo, and you can think of it as a Start-Job but much faster and less memory consuming, you add your scriptblock with .AddScript({...}) and then the parameters with .AddParameters([hashtablehere]). It's important to save the PSInstance in a variable so that we can get the output out of it and it's handler (Status = $psinstance.BeginInvoke()) to know when the instance has completed. The rest is just pure blueprint, once you have one you can copy paste it :P –
Santiago Squarzon
Dec 2 at 13:50
#HaveComputer I have no idea what your comment means. –
Santiago Squarzon
Dec 5 at 1:10
the 2 solutions presented work much faster, my code however is lacking. –
Have Computer
Dec 5 at 1:16
#HaveComputer I know that, this can perform 50x faster or even more depending on hardware and bandwidth. –
Santiago Squarzon
This is a good place where you can use runspaces, I would love to test if Test-Connection -AsJob performs better than this but for some reason it is not available on PS Core on Linux.
Code below took around 10 seconds to scan 254 IPs using my private network IP range. There is a lot of tweaking that can be done, i.e. you can poke around the $Threshold variable, it's currently running 100 runspaces at a time, Count and TimeoutSeconds for Test-Connection have been set to 2 you can tweak that too.
$results variable can be exported using Export-Csv.
# Change this value for tweaking
$Threshold = 100
$RunspacePool = [runspacefactory]::CreateRunspacePool(1, $Threshold)
$RunspacePool.Open()
# This is for testing, use your CSV here instead
# => $list = Import-Csv C:\Temp\GetList.csv
$list = 1..254 | ForEach-Object {
[pscustomobject]#{
IPAddress = "192.168.1.$_"
Hostname = "ExampleHost$_"
}
}
$scriptBlock = {
param($ip, $hostname)
$params = #{
Quiet = $true
Count = 2
TimeoutSeconds = 2
ComputerName = $ip
}
$status = Test-Connection #params
[pscustomobject]#{
Hostname = $hostname
IPAddress = $ip
Status = ('Failed','Success')[[int]$status]
}
}
$runspaces = foreach($line in $list)
{
$params = #{
ip = $line.IPAddress
hostname = $line.Hostname
}
$psinstance = [powershell]::Create().AddScript($scriptBlock).AddParameters($params)
$psinstance.RunspacePool = $RunspacePool
[pscustomobject]#{
Instance = $psinstance
Status = $psinstance.BeginInvoke()
}
}
while($runspaces.Status.IsCompleted -contains $false)
{
Start-Sleep -Milliseconds 500
}
$results = $runspaces.ForEach({ $_.Instance.EndInvoke($_.Status) })
$RunspacePool.Dispose()
$results Sample:
Hostname IPAddress Status
-------- --------- ------
ExampleHost1 192.168.1.1 Success
ExampleHost2 192.168.1.2 Failed
ExampleHost3 192.168.1.3 Success
ExampleHost4 192.168.1.4 Failed
ExampleHost5 192.168.1.5 Success
ExampleHost6 192.168.1.6 Failed
ExampleHost7 192.168.1.7 Failed
ExampleHost8 192.168.1.8 Failed
ExampleHost9 192.168.1.9 Failed
ExampleHost10 192.168.1.10 Failed
...
...
Start-Job -ScriptBlock { Test-Connection -computername (Get-Content -Path “C:\Temp\GetList.csv”) }
Its lacking the fundamentals, works, DE fast.

\network adapter(*)\bytes total/sec vs. task manager/performance -powershell

On Windows 10, in task manager/performance it gives the values for 'Receive' and 'Send' for network adapters. I got curious as to how MS does this so I thought of performance counters in powershell. So I cobbled together a quick bit of code to experiment with, put it in a background job, this:
$Computer = hostname;
$sndrecsum = {((get-counter -Counter '\network adapter(*)\Bytes Received/sec' -MaxSamples 30).CounterSamples | measure cookedvalue –Sum).Sum};
$sptstb = New-Object System.Net.WebClient;
$sptstb.DownloadFile('http://client.akamai.com/install/test-objects/10MB.bin', 'Out-Null');
Start-Job -Name sxrxs -scriptblock $sndrecsum -ArgumentList $Computer;
Get-Job -Name sxrxs | Wait-Job; $sndrecsumout = Get-Job -Name sxrxs | Receive-Job; ($sndrecsumout | measure -Maximum).Maximum
here's the issue. The output '($sndrecsumout | measure -Maximum).Maximum' should be getting the maximum value in the array $sndrecsumout. It does do that but the max value in the array is always wayyyy lower than it should be and never matches that shown in task manager/performance for 'Receive' and 'Send' (after conversion to the prevailing units shown in task manager/performance at the same time). So i'm not sure if task manager/performance is using performance counters or if i'm screwing up somewhere.
Anyway, two questions: First, how does task manager/performance get the values for 'Receive' and 'Send'? - and - Two, am I screwing up with the way i'm trying to do this?
Thanks for replies and advice in advance.
ok, think i've got it figured out here, at least a little, maybe. This tracks with the Windows 10 performance monitor for the interface;
$sptst = New-Object System.Net.WebClient; $Computer = hostname; $strlf += $("" | Out-String);
$totx = {
get-counter -Counter '\Network Interface(Intel[R] Ethernet Connection [2] I218-V)\Bytes Total/sec' -MaxSamples 40 | ForEach {[math]::Round((($_.countersamples.cookedvalue | measure -sum).sum / 1Mb), 4)}
};
$recx = {
get-counter -Counter '\network Interface(Intel[R] Ethernet Connection [2] I218-V)\Bytes Received/sec' -MaxSamples 40 | ForEach {[math]::Round((($_.countersamples.cookedvalue | measure -sum).sum / 1Mb), 4)}
};
$sntx = {
get-counter -Counter '\network Interface(Intel[R] Ethernet Connection [2] I218-V)\Bytes Sent/sec' -MaxSamples 40 | ForEach {[math]::Round((($_.countersamples.cookedvalue | measure -sum).sum / 1Mb), 4)}
};
Start-Job -Name xtot -scriptblock $totx -ArgumentList $Computer;
Start-Job -Name xrec -scriptblock $recx -ArgumentList $Computer;
Start-Job -Name xsnt -scriptblock $sntx -ArgumentList $Computer;
$ts = Measure-Command -Expression {$sptst.DownloadFile('http://testmy.net/dl-10MB', 'Out-Null')}; $dxtmex = [math]::Round($ts.TotalSeconds, 4);
Get-Job -Name xtot -HasMoreData $True | Wait-Job ; $outxtot = Get-Job -Name xtot | Receive-Job;
$xthrx = ($outxtot | measure -Maximum).Maximum; $testnuma = $xthrx -match '^[\d\.]+$'; if ($testnuma -eq 'True') {$MBxthrx = $xthrx; $Mbpsxthrx = $xthrx / 0.125};
Get-Job -Name xrec -HasMoreData $True | Wait-Job; $outxrec = Get-Job -Name xrec | Receive-Job;
$xrecx = ($outxrec | measure -Maximum).Maximum ; $testnumb = $xrecx -match '^[\d\.]+$'; if ($testnumb -eq 'True') {$MBxrecx = $xrecx; $Mbpsxrecx = $xrecx / 0.125};
Get-Job -Name xsnt -HasMoreData $True | Wait-Job; $outxsnt = Get-Job -Name xsnt | Receive-Job;
$xsntx = ($outxsnt | measure -Maximum).Maximum ; $testnumb = $xsntx -match '^[\d\.]+$'; if ($testnumb -eq 'True') {$MBxsntx = $xsntx; $Mbpsxsntx = $xsntx / 0.125};
$txtl = '|Throughput = ' + $Mbpsxthrx + ' Mbps (' + $MBxthrx + ' MB/s) [ Test Time = ' + $dxtmex + ' seconds ]';
$rxsx = 'Received (D/L) : ' + $Mbpsxrecx + ' Mbps (' + $MBxrecx + ' MB/s)' + ' / Sent (U/L) : ' + $Mbpsxsntx + ' Mbps (' + $MBxsntx + ' MB/s)';
Return $txtl + $strlf + $rxsx
Edit: removed previous answer - this one is much better and improved. Ignore the labels 'Throughput' - 'Received (D/L)' - 'Sent (U/L)' as just called them something to differentiate while playing around with it so call them anything you wish if desired. 'Throughput' in the windows performance monitor is expressed as a percentage and not like this anyway but the results expressed in 'Throughput' above code when converted for percentage in math (not shown in above code) seem to track with the perf monitor which is why I chose the label 'Throughput' here. Also during this figured out how to get the correct instance name for the interface for use in the counters, I don't show its use (or the code for it) this post, and just put the interface name in above code, to keep strictly on topic but if someone wants to see it and its OK to do i'll post it here also. I'll just probably come back later and post it anyway if its Ok in this post and if not ya'll can remove it if you wish if it would be off topic some. Any improvements/suggestions welcome.
Thank You.

Get CPU % of a particular process using powershell

I want to get the CPU usage % (not processor time) of a particular process using a powershell command.
Example: (Windows 8 Task Manager)
I want to get that 2.9% with a command.
Here is the correct answer which is support case then you have multiple processs with same name https://stackoverflow.com/a/34844682/483997
# To get the PID of the process (this will give you the first occurrance if multiple matches)
$proc_pid = (get-process "slack").Id[0]
# To match the CPU usage to for example Process Explorer you need to divide by the number of cores
$cpu_cores = (Get-WMIObject Win32_ComputerSystem).NumberOfLogicalProcessors
# This is to find the exact counter path, as you might have multiple processes with the same name
$proc_path = ((Get-Counter "\Process(*)\ID Process").CounterSamples | ? {$_.RawValue -eq $proc_pid}).Path
# We now get the CPU percentage
$prod_percentage_cpu = [Math]::Round(((Get-Counter ($proc_path -replace "\\id process$","\% Processor Time")).CounterSamples.CookedValue) / $cpu_cores)
Get-Process -Name system | select CPU
Get the cpu time at 2 instance as (cpu2-cpu1)/(t2-t1)*100. You will get CPU value in %.
Get-Process -Name system | select CPU # Get the cpu time at 2 instance as (cpu2-cpu1)/(t2-t1)*100. You will get CPU value in %.
$processName = 'OUTLOOK'
$sleep_time = 1 # value in seconds
while (1) {
$CPU_t1 = Get-Process -Name $processName | Select CPU
$CPU_t1_sec = $($CPU_t1.CPU)
#Write-Host "CPU_t1: $($CPU_t1.CPU)"
$date1 = (Get-Date)
sleep -Seconds $sleep_time
$CPU_t2=Get-Process -Name $processName | Select CPU
#Write-Host "CPU_t2: $($CPU_t2.CPU)"
$CPU_t2_sec = $($CPU_t2.CPU)
$date2 = (Get-Date)
$date_diff = $date2 - $date1
$diff_time = $date_diff.seconds
#Write-Host "TimeDiff: $diff_time"
#compute them to get the percentage
$CPU_Utilization = ($CPU_t2_sec - $CPU_t1_sec)/$diff_time
$CPU_Utilization_per = $CPU_Utilization * 100
#Sleep $sleep_time
Clear-Host Write-Host "CPU_Utilization_Per: $CPU_Utilization_per"
#Write-Host "====================="
}
Get-Process -Name PowerShell | Select CPU
Is this what you're looking for?
Or something more monitoring based?
param
(
[String]
[Parameter(Mandatory)]
$Title
)
do
{
$process = Get-Process -Name $Title
$process
Start-Sleep -Seconds 1
} while ($process)

Pipe answer from tasklist to check mem usage of process and kill if exceeding threshold

I found a powershell version that does the job but it uses WMI and thats the process i have issue with, its leaking and hits the 512MB roof and stops working "out of memory".
$processToMonitor = 'wmiprvse.exe'
$threshold = 513MB
Register-WmiEvent -Query "SELECT * FROM __InstanceModificationEvent WITHIN 5 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.Name='$processToMonitor' AND TargetInstance.WorkingSetSize > $threshold" -Action { Get-Process -PID $event.SourceEventArgs.NewEvent.TargetInstance.ProcessId | Stop-Process -Force -ErrorAction SilentlyContinue | Out-Null }
So the above will not work when WMI is out of memory, so could i use some other way of doing the same thing?
If i use:
tasklist | find "WmiPrvSE.exe"
It spits out the current WmiPrvSE processes with pid, and memory usage. And ideas of how i can use that?
There is a patch for this WMI leak issue but i cant patch all servers as soon as i want.
try this:
$task = (tasklist | select-string 'Wmiprvse.exe') -split '\s+'
$proc = $task[0] -replace '\.exe'
[int]$mem = $task[-2] -replace '\.'
if ($mem -gt (513MB /1KB) )
{
(get-process $proc).kill()
}
but this is equivalent and preferable ( two session of wmiprvse.exe can exist!):
Get-Process wmiprvse | ? { $_.ws -gt 513MB } | Stop-Process -Force

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