Powershell close multiple windows / end processes based on name - powershell

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

Related

How to use Powershell Invoke-Item with a gci search?

I'm trying to build a Powershell script that uses the Invoke-Item cmdlet once I've found the files using the following script:
gci -Recurse -File *.xls* C:\folder_example\'  |  sort LastWriteTime | Select -last 2 | 
I'm not sure how best to implement the Invoke-Item cmdlet from here?
In its simplest usage, Invoke-Item (aliased as ii) just needs a path given to it either through pipeline or through a parameter.
In this case, it could be as simple as adding | Invoke-Item to the end of your command:
gci -Recurse -File *.xls* C:\folder_example\ | sort LastWriteTime | select -Last 2 | Invoke-Item
One thing I will mention, is that I have found that certain programs cannot handle a bunch of files thrown at them in quick succession like this script will do.
I usually run into this when trying to open a bunch of files in Notepad++.
I'm going to simplify the command a bit just to keep it short...but usually one of these two changes will fix my problem:
Get-ChildItem -Filter *.xls* | ForEach-Object { Invoke-Item $_.FullName }
Placing the call into a ForEach-Object script block will sometimes fix this. I'm not 100% why this fixes it, I have some theories but that's all they are, so I will keep them out of this answer. But it always fixes the issue for me when using Invoke-Item on Notepad++ files.
Some programs, like Excel, have a start up splash screen and some lag before they eventually open. So you could always throw a sleep in there just to help slow things down a bit in case you are still having trouble:
Get-ChildItem -Filter *.xls* | ForEach-Object { Start-Sleep 0.1; Invoke-Item $_.FullName }
That will add a small 100ms pause just to give whatever application you are running to have a little time to process.

Scripts executed by a WinRar self-extracting archive not behaving as expected

I have a self-extracting WinRar archive set up to run a powershell script upon completion. The script will launch, but specific commands do not give expected results.
In particular, I have the following command to find the installation path of an installed game (Risk of Rain 2).
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath } | Where-Object {$_.DisplayName -like 'Risk of Rain 2'} | Select InstallLocation -ExpandProperty InstallLocation
When running the script by itself, I get the install path as expected.
F:\SteamLibrary\steamapps\common\Risk of Rain 2
When the script is launched (either before or after extraction), the command seems to run, but outputs nothing.
In testing, I removed everything but the following:
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath }
This still works, outputting a list of installed applications. When I add the pipe to the "Where-Object" portion, it starts to fail.
My only guess is that WinRar is starting the scripts with some other parameters set.
I tried having Winrar start a .bat that will then run the .ps1 file, but had the same result. Same goes for running the archive as an administrator.
Is something funky with my powershell script, or am I just missing something with how Winrar handles things?
Thanks!
So according to your comment the archive uses underscore in place of spaces. So looking at your code we see this originally
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $.PsPath } | Where-Object {$.DisplayName -like 'Risk of Rain 2'} | Select InstallLocation -ExpandProperty InstallLocation
Your error occurs when we try to include the Where-object. So I believe the solution to your problem should be to modify your code as such:
Get-ChildItem HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | % { Get-ItemProperty $_.PsPath } | Where-Object {$_.DisplayName -like 'Risk_of_Rain_2'} | Select InstallLocation -ExpandProperty InstallLocation
Essentially we changed the -like from 'Risk of Rain 2' to 'Risk_of_Rain_2'
I believe this should solve the problem as it is called by the WinRar it probably still uses the underscore name. Since you are checking for a like name that only indicates that it can include any number and type of characters after or before the words in the like string. The like string itself is exact.
So...WinRAR gives options for the SFX module used. I was using the default Zip.SFX module when I should have been using Zip64.SFX.
The powershell session it opened previously was 32-bit, which gives a different result when reading the installed programs from the registry.
If you have anything 32/64 bit specific in the commands being run after an extraction, make sure the right module is selected in the Advanced SFX options.
Thank you all for the help!
Advanced SFX options

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

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.