Skip to content

Process Management

Note

Find, start, stop, and monitor running processes with Get-Process, Start-Process, and Stop-Process.

Overview

Whether you're killing a hung application, launching an external tool from a script, or watching for a runaway process eating CPU, PowerShell's process cmdlets give you the same control as Task Manager — scriptable and filterable. Get-Process reads, Start-Process launches, Stop-Process kills.

Basic Syntax

Get-Process -Name "notepad"
Start-Process -FilePath "notepad.exe"
Stop-Process -Name "notepad"
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5

Key Points

  • Get-Process -Name doesn't need the .exe extension
  • Stop-Process kills immediately — there's no graceful shutdown request, use -Force only when a normal Stop-Process doesn't work
  • Start-Process -Wait blocks the script until the launched process exits
  • Process IDs (-Id) are more precise than names when multiple instances are running

Finding Processes

# All processes
Get-Process

# By name (wildcards supported)
Get-Process -Name "chrome*"

# By process ID
Get-Process -Id 4832

# Top CPU consumers
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10 Name, CPU, Id

# Top memory consumers (WorkingSet is in bytes)
Get-Process | Sort-Object WorkingSet -Descending |
    Select-Object -First 10 Name, @{N="MemoryMB";E={[math]::Round($_.WorkingSet / 1MB, 1)}}

Output:

Handles  NPM(K)    PM(K)      WS(K)     CPU(s)     Id  ProcessName
-------  ------    -----      -----     ------     --  -----------
    845      41    89452      92104      12.45   4832  chrome
    312      18    24012      31556       3.20   9944  notepad

Filtering by Resource Usage

# Processes using more than 500MB
Get-Process | Where-Object { $_.WorkingSet -gt 500MB }

# Processes that have been running more than an hour
Get-Process | Where-Object { $_.StartTime -lt (Get-Date).AddHours(-1) }

# Processes with no window (background/service-hosted processes)
Get-Process | Where-Object { $_.MainWindowTitle -eq "" }

Starting Processes

# Launch an application
Start-Process -FilePath "notepad.exe"

# Launch with arguments
Start-Process -FilePath "notepad.exe" -ArgumentList "C:\Temp\notes.txt"

# Launch and wait for it to close before continuing
Start-Process -FilePath "msiexec.exe" -ArgumentList "/i app.msi /qn" -Wait

# Launch minimized/hidden
Start-Process -FilePath "backup.exe" -WindowStyle Hidden

# Run elevated (triggers a UAC prompt)
Start-Process -FilePath "powershell.exe" -Verb RunAs

# Capture exit code from a launched process
$proc = Start-Process -FilePath "robocopy.exe" -ArgumentList "C:\Src C:\Dst /MIR" -Wait -PassThru
$proc.ExitCode

-Wait -PassThru Is How You Get an Exit Code

Start-Process normally returns nothing (or immediately hands control back to your script). Combine -Wait (block until it finishes) with -PassThru (return the process object) to capture .ExitCode — essential when a script needs to know whether the launched program actually succeeded.

Stopping Processes

# Stop by name
Stop-Process -Name "notepad"

# Stop by process ID (safer when multiple instances exist)
Stop-Process -Id 4832

# Force-kill a process that won't close normally
Stop-Process -Name "notepad" -Force

# Preview before killing anything
Stop-Process -Name "chrome" -WhatIf

# Stop all processes matching a pattern
Get-Process -Name "chrome*" | Stop-Process -Force

Stop-Process Doesn't Ask the App to Close

# BAD (for anything with unsaved work) - immediately kills the process
Stop-Process -Name "notepad" -Force

# BETTER - ask the process to close its main window first (gives it a chance to prompt "Save changes?")
(Get-Process -Name "notepad").CloseMainWindow()

# Fall back to Stop-Process only if CloseMainWindow() doesn't work
Stop-Process is the equivalent of pulling the power cord, not clicking the X. Use CloseMainWindow() first for interactive applications where data loss matters.

Monitoring Processes

# Snapshot CPU/memory right now
Get-Process -Name "sqlservr" | Select-Object Name, CPU, WorkingSet, Threads

# Watch a process over time (simple polling loop)
1..10 | ForEach-Object {
    Get-Process -Name "myapp" | Select-Object Name, CPU, WorkingSet
    Start-Sleep -Seconds 5
}

# Count instances of a process across the system
(Get-Process -Name "chrome" -ErrorAction SilentlyContinue).Count

CPU Property Is Cumulative, Not Instantaneous

$process.CPU is total processor time consumed since the process started, in seconds — not a percentage of current usage. To get percentage-style CPU usage, sample the CPU value twice with a known delay and calculate the delta, or use Get-Counter against the \Process(*)\% Processor Time performance counter.

Important Parameters

Parameter Type Description Example
-Name String[] Process name, no .exe, supports wildcards Get-Process -Name "chrome*"
-Id Int[] Process ID Get-Process -Id 4832
-FilePath String Start-Process: executable to launch Start-Process -FilePath "app.exe"
-ArgumentList String Start-Process: command-line arguments -ArgumentList "/silent"
-Wait Switch Start-Process: block until it exits Start-Process -Wait
-PassThru Switch Start-Process: return the process object Start-Process -PassThru
-Verb String Start-Process: RunAs for elevation Start-Process -Verb RunAs
-Force Switch Stop-Process: kill without confirmation prompt Stop-Process -Force

Common Patterns

# Pattern 1: Kill a process only if it's running (avoid errors on missing process)
$proc = Get-Process -Name "hungapp" -ErrorAction SilentlyContinue
if ($proc) {
    Stop-Process -InputObject $proc -Force
}

# Pattern 2: Run an external tool and check success
$result = Start-Process -FilePath "robocopy.exe" -ArgumentList "C:\Src C:\Dst /MIR" -Wait -PassThru
if ($result.ExitCode -ge 8) {
    Write-Error "Robocopy failed with exit code $($result.ExitCode)"
}

# Pattern 3: Top resource consumers report
Get-Process | Sort-Object CPU -Descending | Select-Object -First 5 Name, Id, CPU,
    @{N="MemoryMB"; E={[math]::Round($_.WorkingSet / 1MB, 1)}}

Real-World Examples

Example: Restart a Hung Application

Scenario: Check if a specific application is unresponsive (not responding to the UI), and if so, kill and relaunch it.

$appName = "myapp"
$appPath = "C:\Program Files\MyApp\myapp.exe"

$process = Get-Process -Name $appName -ErrorAction SilentlyContinue

if ($process -and -not $process.Responding) {
    Write-Output "$appName is not responding, restarting..."
    Stop-Process -InputObject $process -Force
    Start-Sleep -Seconds 2
    Start-Process -FilePath $appPath
} elseif (-not $process) {
    Write-Output "$appName is not running, starting it"
    Start-Process -FilePath $appPath
} else {
    Write-Output "$appName is running normally"
}

Explanation: .Responding is a boolean on the process object that reflects whether the app's UI thread is processing messages — the same check Task Manager uses to flag "(Not Responding)". Combining it with existence checks covers all three states: running fine, hung, and not running.

Tips & Tricks

Get the Owning Executable's Full Path

(Get-Process -Name "notepad").Path
Useful for confirming exactly which binary (and from which folder) is actually running, especially when duplicate-named executables exist in different locations.

Stopping the Wrong Process by Name

# BAD - kills EVERY process named "python", including ones you didn't start
Stop-Process -Name "python" -Force

# GOOD - target the specific instance by Id
Stop-Process -Id 8842 -Force
Multiple unrelated instances of the same executable (Python, Node, Java) are common. Prefer -Id when precision matters.

Additional Resources