Table of Contents
You can use the Process cmdlets to manage local and remote processes with PowerShell. To find out all the PowerShell cmdlets that deal with Processes, use the following command.
PS C:\> Get-Command -Noun Process
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet Debug-Process 3.1.0.0 Microsoft.PowerShell.Management
Cmdlet Get-Process 3.1.0.0 Microsoft.PowerShell.Management
Cmdlet Start-Process 3.1.0.0 Microsoft.PowerShell.Management
Cmdlet Stop-Process 3.1.0.0 Microsoft.PowerShell.Management
Cmdlet Wait-Process 3.1.0.0 Microsoft.PowerShell.Management
Getting Processes
To get the processes running on the a computer, you can use the Get-Process cmdlet with no parameters.
PS C:\> Get-Process
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
435 27 21940 4464 0.00 26568 1 AcrobatNotificationClient
4973 905 10066700 678764 379.45 25528 1 Adobe Premiere Pro
421 20 4912 19792 0.03 24144 1 AdobeCollabSync
543 27 8616 23400 25.28 24292 1 AdobeCollabSync
199 16 4080 13136 1.63 3456 1 AdobeIPCBroker
...
You can get particular process by specifying their process names or process IDs. The following command gets the notepad process.
PS C:\> Get-Process -Name notepad
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
872 43 80376 108924 14.30 19380 1 Notepad
PS C:\> Get-Process -Id 19380
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
872 43 80376 108924 14.30 19380 1 Notepad
The name parameter is default. You can omit the -Name keyword and directly type the name of process you want to list. The Get-Process cmdlet also accepts the wildcards (*) to refer multiple processes starting or ending with same name. For example, to get all the processes with the name starting with P, use the following command:
PS C:\> Get-Process -Name p*
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
1005 93 182244 152504 80.80 26812 1 pCloud
3428 100 82000 154768 3.42 22892 1 PhoneExperienceHost
790 31 122236 94752 0.08 2684 1 powershell
919 51 216764 217856 4.48 45572 1 powershell
708 37 10600 32476 1.36 10208 1 PowerToys
206 12 18152 4728 6.97 10600 1 PowerToys.AlwaysOnTop
650 44 13012 20088 1.48 10028 1 PowerToys.Awake
339 23 72296 28804 4.77 476 1 PowerToys.FancyZones
138 9 14836 1920 1.02 8124 1 PowerToys.KeyboardManagerEngine
1158 89 95636 71108 128.25 1820 1 PowerToys.Peek.UI
1137 154 275524 216564 18.77 2580 1 PowerToys.PowerLauncher
317 43 12484 11536 0.09 5692 1 PowerToys.PowerOCR
324 21 6908 26392 129.66 30440 1 putty
1152 141 199716 303564 13.33 4468 1 pwsh
971 96 71452 96256 3.80 24432 1 pwsh
Remember that the process name for an executable never includes the .exe at the end of the executable name. The Get-Process cmdlet also accepts multiple comma-separated values for the Name parameter as shown below:
PS C:\> Get-Process powershell, notepad
Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName
------- ------ ----- ----- ------ -- -- -----------
872 43 80376 108924 14.30 19380 1 Notepad
790 31 122236 94752 0.08 2684 1 powershell
876 51 216760 217856 4.48 45572 1 powershell
The following command gets all the processes that have a main window title, and it displays them in a table with the process ID and the process name.
The mainWindowTitle is the property of System.Diagnostics.Process object that Get-Process cmdlet returns.
PS C:\> gps | ? {$_.mainWindowTitle} | ft Id, Name, mainWindowTitle -AutoSize
Id Name MainWindowTitle
-- ---- ---------------
25528 Adobe Premiere Pro Adobe Premiere Pro 2023
15540 ApplicationFrameHost Media Player
47168 Microsoft.Media.Player Media Player
15336 ONENOTE Bonguides.com - OneNote
45800 SystemSettings Settings
7188 TeamViewer TeamViewer
22648 TextInputHost Windows Input Experience
46900 WindowsTerminal Administrator: Windows PowerShell
You can use the ComputerName parameter of Get-Process cmdlet to get processes from remote computers. For example, the following command gets the powershell processes running on the two remote computers (DC1 and DC2).
PS c:\> Get-Process -Name powershell -ComputerName DC1, DC2
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
302 23 62964 66180 601 4580 powershell
340 25 61488 65904 609 6120 powershell
The computer names are not displayed by default, but they are stored in the MachineName property of the process object. The following command uses the Format-Table cmdlet to display the ProcessName, Process ID, and MachineName properties of the process objects.
PS C:\> gps -Name powershell -ComputerName DC1, DC2 | FT -Property ProcessName, ID, MachineName
ProcessName Id MachineName
----------- -- -----------
powershell 4580 DC1
powershell 6120 DC2
Stopping Processes
Windows PowerShell gives you Stop-Process cmdlet for stopping a process. The Stop-Process cmdlet takes a Name or ID to specify a process you want to stop. Your ability to stop processes depends on your permissions. Some processes cannot be stopped. For example, if you try to stop the antivirus process Notepad, you get the error as shown below:
Stop-Process -Name notepad
PowerShell did not confirm whether you want to stop the process. It closed the notepad immediately. You can manually add Confirm parameter if you want PowerShell to display confirmation prompt as shown below:
PS C:\> Stop-Process -Name notepad -Confirm
Confirm
Are you sure you want to perform this action?
Performing the operation "Stop-Process" on target "notepad (6416)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"):
Also note that you have many choices at confirmation prompt like Y, A, N, L, S but the default is Y (YES). This means if you do not type any choice and press Enter key, the Y will be considered by default.
Windows PowerShell can stop a process; it doesn’t seem interesting. You can always stop any process if it is responding. To make it more interesting lets find out a way to stop a process which is hung or not responding. To investigate what properties do Process object holds, use Get-Member cmdlet.
PS C:\> Get-Process | Get-Member -MemberType Properties
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
...
Responding Property bool Responding {get;}
...
Because a Process object has a Responding property that is true when it is responding.
PS C:\> (Get-Process notepad).Responding
True
When the process is no longer responding, the property returns False. You can stop all non-responsive applications with the following command:
PS C:\> (Get-Process notepad).Responding
False
PS C:\> (Get-Process) | ?{$_.Responding -eq $false}
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
82 8 323920 329256 405 4.77 14188 notepad
PS C:\> Get-Process | Where-Object {$_.Responding -eq $false} | Stop-Process -Verbose
VERBOSE: Performing the operation "Stop-Process" on target "notepad (14188)".
The above example shows that notepad which has stopped responding in my computer, is closed by Stop-Process cmdlet. The application is forcefully closed; means that any data which is not yet saved will be lost.
For instance, if you run Stop-Process command against Microsoft Excel; any unsaved data in excel spreadsheet will be lost. Let’s consider another example of Microsoft Outlook which is most widely used email client in most of companies.
If you always keep using Stop-Process against Microsoft Outlook, the data file (PST) will get corrupted and it will need a repair before it can be used again. We have to investigate some more safer solution of closing the application without killing the process itself. Let’s take a look at the members of Get-Process cmdlet.
PS C:\> Get-Process | Get-Member -MemberType Method
TypeName: System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
BeginErrorReadLine Method void BeginErrorReadLine()
BeginOutputReadLine Method void BeginOutputReadLine()
CancelErrorRead Method void CancelErrorRead()
CancelOutputRead Method void CancelOutputRead()
Close Method void Close()
CloseMainWindow Method bool CloseMainWindow()
CreateObjRef Method System.Runtime.Remoting.ObjRef
Dispose Method void Dispose(), void IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Kill Method void Kill()
Refresh Method void Refresh()
Start Method bool Start()
ToString Method string ToString()
WaitForExit Method bool WaitForExit(int milliseconds),
WaitForInputIdle Method bool WaitForInputIdle(int milliseconds),
Notice that Get-Process cmdlet has a CloseMainWindow method. You can use this method to safely close Microsoft Outlook as shown below:
PS C:\> Get-Process Outlook | Where-Object {$_.CloseMainWindow()}
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
1453 70 71992 77580 613 2.27 16084 OUTLOOK
The benefit of using this method is that it does not forcefully end the process; instead it gracefully exits the Outlook window. The other benefit of using this method is that if any user is writing an email message, he/she will be prompted with 3 options:YES, NO, and CANCEL.
- If user selects YES, the message will be saved to Drafts and Outlook will be Closed.
- If user selects NO, the message will not be saved to Drafts and Outlook will be Closed.
- If user selects CANCEL, the user can continue writing email message and Outlook will not be Closed.
Stopping All Other PowerShell Sessions
Sometimes it may be useful to be able to stop all running Windows PowerShell sessions other than the current session. If a session is using too many resources or is inaccessible (it may be running remotely or in another desktop session), you may not be able to directly stop it. If you try to stop all running sessions, however, the current session may also be terminated.
Each Windows PowerShell session has an environment variable PID that contains the Id of the Windows PowerShell process. You can check the $PID against the Id of each session and terminate only Windows PowerShell sessions that have a different Id. The following pipeline command does this and returns the list of terminated sessions with the help of PassThru parameter.
PS C:\> gps -Name powershell | Where-Object -FilterScript {$_.Id -ne $PID} | Stop-Process -PassThru
Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
402 25 142392 4968 621 0.89 10248 powershell
448 24 99988 101928 618 0.53 11548 powershell
601 26 114108 116168 619 0.67 16532 powershell
Using above command, all the other PowerShell sessions will be closed except current session where you run this command.
Start New Processes
The Start-Process cmdlet starts one or more processes on the local computer. To specify the program that runs in the process, enter an executable file or script file, or a file that can be opened by using a program on the computer. If you specify a non-executable file, Start-Process starts the program that is associated with the file, much like the Invoke-Item cmdlet.
You can use the parameters of Start-Process to specify options, such as loading a user profile, starting the process in a new window, or using alternate credentials. The following command starts a new PowerShell process with Run as Administrator permissions.
Start-Process Powershell -Verb runAs -wait -windowstyle Maximized
The -wait -windowstyle Maximized operators maximizes the window and retains the window until the process the completes.
Wait-Process
The Wait-Process cmdlet waits for one or more running processes to be stopped before accepting input. In the Windows PowerShell console, this cmdlet suppresses the command prompt until the processes are stopped. You can specify a process by process name or process ID (PID), or pipe a process object to Wait-Process.
The Wait-Process works only on processes running on the local computer and you can use this cmdlet in your PowerShell script to wait for one command to complete before the next command executes.
The Wait-Process cmdlet can be used in 3 different ways. The syntax is shown below:
Wait-Process [-Id] <Int32[]> [[-Timeout] <int>] [<CommonParameters>]
Wait-Process -InputObject <Process[]> [[-Timeout] <int>] [<CommonParameters>]
Wait-Process [-Name] <string[]> [[-Timeout] <int>] [<CommonParameters>]
Debug-Process
The Debug-Process cmdlet attaches a debugger to one or more running processes on a local computer. You can specify the processes by their process name or process ID (PID), or you can pipe process objects to Debug-Process.
Debug-Process attaches the debugger that is currently registered for the process. Before using this cmdlet, verify that a debugger is downloaded and correctly configured.
The syntax is shown below:
Debug-Process [-Name] <string[]> [-Confirm] [-WhatIf] [<CommonParameters>]
The following command attaches a debugger to the PowerShell process on the computer.
Select Property vs ExpandProperty
The pipeline ability of PowerShell is really amazing that allows you to input the result of one cmdlet to another. You know the Select-Object cmdlet is used for filtering the result based on selected properties.
For instance, let’s pipe the result of Get-Process cmdlet into the Select-Object as shown below:
PS C:\> Get-Process | Select-Object -Property ProcessName
ProcessName
-----------
PS C:\> Get-Process | Select-Object ProcessName
ProcessName
-----------
This command will show only one column with ProcessName header. Since -Property is a default parameter for Select-Object cmdlet, you could even shorten the above command like Get-Process | Select ProcessName.
If you run the following command, you will see that the output of command is actually an object of Selected.System.Diagnostics.Process type.
PS C:\> Get-Process | Select -Property ProcessName | Get-Member
TypeName: Selected.System.Diagnostics.Process
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
notepad NoteProperty object notepad=null
You can see that the output of Get-Process cmdlet is a System.Diagnostics.Process object data type. But what if you want to pipe the output of Get-Process command into another cmdlet which is expecting a string data type as an input instead of an object? Well, in that case you need to use -ExpandProperty parameter instead of -Property as shown below:
PS C:\> Get-Process | Select -ExpandProperty ProcessName
AcrobatNotificationClient
Adobe Premiere Pro
AdobeCollabSync
AdobeCollabSync
AdobeIPCBroker
This command will generate a similar output but without the ProcessName header. If you run the following command, you will see this time the output is not an object but a normal string:
PS C:\> Get-Process | Select -ExpandProperty ProcessName | Get-Member
TypeName: System.String
Name MemberType Definition
---- ---------- ----------
GetType Method type GetType()
ToUpperInvariant Method string ToUpperInvariant()
Trim Method string Trim(Params char[] trimChars), string Trim()
TrimEnd Method string TrimEnd(Params char[] trimChars)
TrimStart Method string TrimStart(Params char[] trimChars)
Chars ParameterizedProperty char Chars(int index) {get;}
Length Property int Length {get;}
...
The -ExpandProperty is particularly useful when the other cmdlet down the pipeline is expecting a string data type instead of object. The command also shows that there are a whole lot of different methods that you can perform on a string data type that were not possible on System.Diagnostics.Process object.
So in the end, use of -Property and -ExpandProperty parameters really depend upon what you want to do with the output.
This is all about Managing Windows Processes using PowerShell.