Kill PID exceeding threshold - powershell

I'm trying to write use a script as a workaround for a software bug for my org where the symptom is a specific PID will use endless threads. I want the script to kill a single PID (PID since there will be more than one with the process name) if it is using more than X threads. I'm testing with Chrome since it is easy to spawn multiple processes. I've been able to piece together a script for listing processes and thread usage but not sure how to then pipe/feed that into stopping the process. eg:
Get-Process -processname chrome |
Select-Object ID, #{Name='ThreadCount';Expression ={$_.Threads.Count}} |
foreach
if ($_.ThreadCount -gt 30) {stop-process -Force}
Thanks in advance

Use Where-Object to filter the processes of interest and pipe them to Stop-Process:
Get-Process chrome |
Where-Object { $_.Threads.Count -ge 30 } |
Stop-Process -Force

Related

Why is remote Powershell job consuming so much host memory over time?

Using powershell, I am creating jobs to run a command block on remote servers. The command scans folders looking for certain files and returns the contents via the output buffer. So - I poll the job every so often (say 10s) - and use receive-job to clear the output buffer. Even then, the memory consumed on the host machine continues to grow by megabytes (memory consumption on client stays low throughout). I don't see anything in other job buffers (error, warning, etc.). The total amount of data received via receive-job ends up being maybe 300k... but the memory consumption is around 400mb. When I remove-job and force garbage collection, the memory is released.
The consumption is gradual, and the growth rate is fairly constant as the job runs. (well - it jumps 3-6mb every so often...)
Invoke-Command ComputerName=$vweb -ScriptBlock {
param($domainsRoot, $filter, $newFileKey, $sitesList)
Get-ChildItem -Path $domainsRoot -ErrorAction SilentlyContinue | Where-Object {$sitesList.Contains($_.Name)} |
ForEach-Object -Process {
Get-ChildItem -Path (Join-Path (Join-Path $domainsRoot $_) "wwwroot/v/*") -filter $filter -recurse -ErrorAction SilentlyContinue |
ForEach-Object -Process {
Write-Output ($newFileKey + ($_.FullName.replace($domainsRoot,'')))
Write-Output (Get-Content -Path $_.FullName)
}
}
} -ArgumentList $domainsRoot, $filter, $global:newFileKey, $sitesList -AsJob -JobName $($vweb)
The command block basically scans a folder ($domainsRoot) looking for target folders (found in $sitesList array) - scans a subfolder of that (wwwroot/v/*) looking for files that match a filter ($filter). (the purpose is to scan iis websites on multiple servers for *.asp files)
Is it something in my command block - or am I misunderstanding how jobs work?
ps version: 5.1.19041.1320, windows 10 host/clients
When you create a remote job, two jobs are created - one for the host and a child job (also on the host) for the remote job. When I used receive-job on the parent, I expected this to clear out all output streams (parent and child). It turned out that the child job still had a fully populated field $childJob.output.
I ended up using receive-job on the child job, and then immediately cleared its output using $childJob.output.clear().
In my tests, this didn't have any adverse affects - but, I wouldn't completely trust this method for more critical tasks without better testing.
After I did this, the memory consumption problem was resolved.

Powershell Stop-Process Many Instances

I have a remote access program that does not clean up after itself after it is closed. In Task Manager, I oftentimes find 5 to 10 instances of the program running. For instance:
XYZ.exe
XYZ.exe
XYZ.exe
XYZ.exe
XYZ.exe
I have a simple Powershell script to stop these processes, but the problem is I want to close n-1 out of n processes.
> Stop-Process -Force -Name XYZ*
kills n out of n processes.
Is there a way to kill all processes of a program while leaving open the newest (e.g. XYZ.exe #5)?
Use Get-Process to discover all matching processes ahead of time, then simply remove one of them before killing the rest:
Get-Process -Name XYZ* |Select -Skip 1 |Stop-Process -Force
Try this: it closes all non responding processes
Get-Process -name XYZ.exe| Where-Object -FilterScript {$_.Responding -eq $false} | Stop-Process

Kill a task based on its windows title

I'm looking to kill a process using it PID when a particular file is open on my computer, so that it doesn't interfere with another script
I have an excel sheet that is referenced by other parts of my system, it is fed information from many different sources I want to automate my workflow to work more smoothly.
Get-Process |where {$_.mainWindowTItle -eq "RASP transfer.xlsx - Excel"} |Write-Output
I'm stuck on how to extract the PID and use it as a variable in a task Stop-Process -ID PID
maybe I'm missing something help
in the end it should look something like this
Get-Process |
Where {$_.mainWindowTItle -eq "RASP transfer.xlsx - Excel"} |
Write-Output $pid=id |
Stop-Process -ID $PID
edit: 6/6/19
Currently I'm able to identify the PID of the specific workbook
by running
Get-Process |where {$_.mainWindowTItle -eq "RASP transfer.xlsx - Excel"} |Write-Output
which I can identify here in the taskmanager
However when the files are run with scripts the excel file is hidden and can't be searched with the windows title....
One of the nice features of Powershell is that you can pass an object on the pipeline. You don't even need the Process ID:
Get-Process | Where {$_.mainWindowTItle -eq "RASP transfer.xlsx - Excel"} | Stop-Process
However it's important to know what type of object you're passing along at each stage in the pipeline. The input to Stop-Process in the line above is a Process object, that has an ID property.
If you wanted to get the Process ID you could assign it to a variable.
$PID = (Get-Process | Where {$_.mainWindowTItle -eq "RASP transfer.xlsx - Excel"}).ID
... which will usually only get a single Process ID because Excel doesn't allow opening the same spreadsheet in two windows. But you can't rely on the window title to be unique because it would be the same if you opened two copies of the same spreadsheet from different folders.
If you wanted to close all Excel windows, this code would get all the Excel windows' processes into an Object[] array:
$ExcelProcs = Get-Process | Where {$_.mainWindowTItle -like "* - Excel"}
Stop-Process is smart enough to use the array of [Object] as input and stop all their processes:
$ExcelProcs | Stop-Process
Why not just re- enable the visibility before you check for the open sheet with:
$x1.Visible = $true
$PID = (Get-Process | Where {$_.mainWindowTItle -eq "RASP transfer.xlsx - Excel"}).ID

Powershell close multiple windows / end processes based on name

I have a pretty neat mess of batch/python scripts that install a program called MATRIS, followed by about 15 exe updates.
Around 11 of these updates open a window telling me the that the update was successful.
Now it would be really fun to run a batch or powershell script which closes all of these windows for me.
The last thing I tried was Get-Process | Where-Object {$_.Path -like "MatrisInstaller.APCIPLUS"} | Stop-Process -WhatIf
I wasn't sure if it was the name as read in task manager, or like the title of the window, but I tried both.
Please note that a couple of these are (32 bit) - I'm not sure if that would impact the script.
I was able to run tasklist followed by kill {PID} but PIDs change: I'm not sure how to script it.
Please reply if you need any clarification, I've historically been poor at wording my questions.
In your example, Path is pointing to the executable file on disk, so while possible to use (if it is consistent), it won't match the name you find in the processes tab of Task Manager. Typically, people will use the name as shown on the Details tab of Task manager. For example, with Outlook on my system, these three possibilities are:
Path: C:\Program Files\Microsoft Office\Office16\OUTLOOK.EXE
Processes tab: Microsoft Outlook
Details tab: outlook.exe
So, you need a command like this:
Get-Process | Where Name -eq 'Outlook' | Stop-Process
or, better:
Get-Process -Name 'Outlook' | Stop-Process
Note that PowerShell expects you to remove the '.exe' you see in Task manager.
EDIT: Additional technique
If you know the names of the processes, then you can simplify your script by doing something like this:
$processList = "Process1","Process2","Process3" # Add all process names to the list
$processList |
ForEach-Object {
Get-Process -Name $_ | Stop-Process
}
You were almost there, just need to change "Path" to "ProcessName" like so:
Get-Process | Where-Object {$_.ProcessName -like "MatrisInstaller.APCIPLUS"} | Stop-Process -WhatIf

Kill process by filename

I have 3 instances of application running from different places. All processes have similar names.
How can I kill process that was launched from specific place?
You can get the application path:
Get-Process | Where-Object {$_.Path -like "*something*"} | Stop-Process -WhatIf
That will work for the local machine only. To terminate remote processes:
Get-WmiObject Win32_Process -Filter "ExecutablePath LIKE '%something%'" -ComputerName server1 | Invoke-WmiMethod -Name Terminate
I would like to slightly improve Shay Levy's answer, as it didn't work work well on my setup (version 4 of powershell)
Get-Process | Where-Object {$_.Path -like "*something*"} | Stop-Process -Force -processname {$_.ProcessName}
You can take a look at the MainModule property inside of the Process class (which can be invoked via powershell).
foreach (Process process in Process.GetProcesses())
{
if (process.MainModule.FileName == location)
{
process.Kill();
}
}
I'd also consider the possible exceptions that can occur while calling this code. This might occur if you're trying to access processes that are no longer present (killed since the last time GetProcess was called) or processes for while you do not have permissions.
Try this:
http://technet.microsoft.com/en-us/library/ee177004.aspx
Stop-Process -processname notepad
The below command kills processes wherein "something" is part of the path or is a command line parameter. It also proves useful for terminating powershell scripts such as powershell -command c:\my-place\something.ps1 running something.ps1 from place c:\my-place:
gwmi win32_process | Where-Object {$_.CommandLine -like "*something*"} | % { "$(Stop-Process $_.ProcessID)" }
The solution works locally on my 64bit Windows 10 machine.