Link to home
Start Free TrialLog in
Avatar of Robb Hill
Robb HillFlag for United States of America

asked on

Powershell script + checking for a process and determining cpu or memory

I have a process that runs...lets  call it process.exe.

There is always going to be more that one of this process running.  Lets say for example that I have 5 of process.exe running.  They would have whatever PID that was generated when the process is started.

I did some way to find the process,
get it id, memory, cpu utilization and store that individually so an alert can be sent for each PID.

I would want to make a summary of this...so pid1 + pid2 + pid3...etc    equals total utilization by the total processes.

Then if that total was over some "threshold"  say 50% as an example..

Then take some action.

For phase one of this I just want to execute an email with the info that the threshold was execeeded and then send the detailed info in the email.

Phase two I may want to actually stop and restart the process based on meeting that threshold and doing so to the Max of a PID cpu utilization in the loop of processes.  This phase 2 is out of scope for this ...but wanted to add that as a potential long term so I get this structure setup properly.

I also think running in parallel with this would be good to do the same with memory


Thanks,
Avatar of Coralon
Coralon
Flag of United States of America image

Something like this should get you started..

$ProcessName = 'taskhostw'
$CPUTotal = 0
$ProcList = @( )

Get-Process -name $ProcessName | foreach-object {
     $Proc = $_
     $Properties = @{ 
      'CPU' = $Proc.CPU
     'VirtualMemorySize' = $Proc.VirtualMemorySize
     'ID' = $Proc.ID
      }
     $ProcList += $(new-object -type PSCustomObject -property $Properties)
     $CPUTotal += $Proc.CPU
}

if ($CPUTotal -gt 50)
{
    Send-MailMessage -To user@domain.tld -From CPUReport@domain.tld -SmtpServer mail.domain.tld -Port 25 -Subject "CPU threshold for $ProcessName exceeded" -Body $ProcList 
}

Open in new window


Coralon
Avatar of Robb Hill

ASKER

testing ...now thanks
I am not sure this is working as expected.  Please elaborate.

So in order to test this on my machine I was using chrome ...running some videos..music. to get a higher cpu hit.  As a test I just replaced the email to stop the process in the if statement.

So setting the > 20...when I  could look at task manager and cpu% of "chrome" was not 20% it still stopped the chrome process.

How is this code really working.  

Thanks,




$ProcessName = 'chrome'
$CPUTotal = 0
$ProcList = @( )

Get-Process -name $ProcessName | foreach-object {
     $Proc = $_
     $Properties = @{ 
      'CPU' = $Proc.CPU
     'VirtualMemorySize' = $Proc.VirtualMemorySize
     'ID' = $Proc.ID
      }
     $ProcList += $(new-object -type PSCustomObject -property $Properties)
     $CPUTotal += $Proc.CPU
}

if ($CPUTotal -gt 20)
{
    Stop-Process -processname $ProcessName

}
    <#Send-MailMessage -To user@domain.tld -From CPUReport@domain.tld -SmtpServer mail.domain.tld -Port 25 -Subject "CPU threshold for $ProcessName exceeded" -Body $ProcList #>

Open in new window

It's pretty straightforward..

1.  We declare the process name, and set an initial CPUCount (% of CPU time) to 0
2.  Set up an empty array for all the process information. This array will hold hashtables of the properties of each instance.
3.  We get all the processes of the name specified above.. We could just put in the real name here, but it's easier to update & change if it isn't 'buried' at this step.
4.  We run that collection through a series of steps..  Grab the individual process $Proc = $_, and construct a hash table of the properties.
5.  We grab each property that we want, and give it a name, and then grab the actual property as the value.  'CPU' = $Proc.CPU.. we are creating a value in the hashtable of CPU and setting the value of it to the actual CPU count from the process. And of course we assign other properties & their values.
6.  Then we create the new custom with these properties, and add it to the collection from step 2.
7.  Then we add the value of the CPU value to the total from step 1.
8. Once all of the processes have been processed and added to the collection, we have a CPU total of all the processes.
9.  If the CPU total is greater than 50, then we send the mail message.

I re-read the help file for get-process, and it doesn't return the % of CPU time.. it returns the amount of CPU time in seconds.  (Apparently, this is a really common mistake).

This article may help.. https://www.petri.com/powershell-problem-solver-process-cpu-utilization  But that seems to get the % of the specific process by name, not the individual processes that share the name.. (i.e. using Filter = "Name = 'chrome'".   I'm not having any luck trying to get the individual % cpu time of these processes.. someone else may be able to?

One thing to be aware of.. you have to use the correct version of Powershell to match the version of Chrome.  If you are using 32bit chrome, you have to use 32bit powershell.  

Now the big thing --- I would *not* terminate the Chrome processes this way.  Chrome generates these extra processes to manage the tabs in the browser window (or multiple browser windows).. By unceremoniously terminating them, you could lose an unknown number of windows/tabs, possibly screwing up differing things.  Since it is just the browser process, It will recover.. but I still wouldn't do it.

Coralon
Chrome is just the example I was using to make this work..this is a 32 bit process.



I have to make this testable.

I was thinking of this in terms of how one views process monitory...clearly its more complicated.


Can you put a basic test for any solution we find...keeping the scope to lonly a local machine.
ok yes..the percentage is my issue...I will try and get this calculated
looks like this will get the process and make it a percentage..

now to combine the two pieces of code

# Option A: This is if you just have the name of the process; partial name OK
$ProcessName = “chrome”

# Option B: This is for if you just have the PID; it will get the name for you
#$ProcessPID = “6860”

#$ProcessName = (Get-Process -Id $ProcessPID).Name
$CpuCores = (Get-WMIObject Win32_ComputerSystem).NumberOfLogicalProcessors
$Samples = (Get-Counter “\Process($Processname*)\% Processor Time”).CounterSamples
$Samples | Select `
InstanceName,
@{Name=”CPU %”;Expression={[Decimal]::Round(($_.CookedValue / $CpuCores), 2)}}

Open in new window

any ideas on how to combine these two in one job?
We are talking about CPU load only (for now), correct?
$ProcessName = 'chrome'
$limit = 20

$CpuCores = (Get-WMIObject Win32_ComputerSystem).NumberOfLogicalProcessors
$load = (get-counter "\process($ProcessName*)\% processor time").CounterSamples | Measure-Object CookedValue | % { [math]::Round($_.Sum/$CpuCores,2) }

if ($load -gt $limit)
{
  #  ...
}

Open in new window

Yes basically I want to be able to kill a task that is eating up my cpu ...for example I have a task that generally runs 4 to 5 PIDs.

I would like to be able to kill a PID of this process if its over x amount of cpu.

Or even have the ability to take  a sum of all the values for this process's pids CPU value and if they exceed 60% or 80% ect the kill.

For example lets say process x is spawned as 4 pids.

process x pid 1
process x pid 2
process x pid 3
process x pid 4

When you visually see this in task manager it might say that pid 1 is 20% pid is 10, pid 2 is 16 and pid 3 25

So obviously I am kiling my cpu.

I need a way to prevent this.  

When this happens killing that PID and restarting it solves the issue.

But as you can see its not so much of an issue of one PID is 20.  Its when all 4 are high.

So this is where the sum of all come into play.

Please let me know if I can explain this issue more.
Isn't this a repeat of the other question from a few weeks ago?  

Coralon
no you were involved with it...this ticket is open since early February.
Such a check requires to perform more than a single snapshot, you need to look at sustained CPU load for at least several minutes, to get a suitable average. Otherwise temporary peaks can lead to undesirable actions.
Qlemo.  -  Understood.  I would be putting the basis of this in some type of wait command so If my criteria ( threshold) was met then I would go back and check again after x amount of time and take action.  

If I have this job running as often as it would these 4 processes should really never sustain over 50% of the cpu for a very long duration.
Spikes are fine..just not steady.  There is a hole in this application that allows a user to hit the system really hard...and this is a bandaid solution I am trying to put in place until a more programmed solution can be written.
ASKER CERTIFIED SOLUTION
Avatar of Qlemo
Qlemo
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial