cheat sheet
taskkill
End one or more running Windows processes by PID or image name from the command prompt, with options for force termination, process tree killing, filtering, and remote targets.
taskkill — Terminate Processes
What it is
taskkill is a built-in Windows command that terminates one or more running processes, identified by PID (/PID) or image name (/IM). By default it sends a graceful shutdown signal (WM_CLOSE) and waits for the process to exit; the /F flag forces immediate termination (TerminateProcess). The /T flag kills the entire process tree rooted at the target — essential for shutting down applications that spawn child processes. In scripts, taskkill is almost always paired with tasklist to first confirm the process is running and obtain its PID.
Availability
taskkill ships as C:\Windows\System32\taskkill.exe on Windows XP and later. PowerShell equivalent: Stop-Process.
taskkill /?
Output:
TASKKILL [/S system [/U username [/P [password]]]]
{ [/FI filter] [/PID processid | /IM imagename] } [/T] [/F]
Syntax
taskkill [/S host] [/U user] [/P pass] { [/FI filter] [/PID pid | /IM image] } [/T] [/F]
Output: (success or error message per process)
Essential options
| Switch | Meaning |
|---|---|
/PID pid | Target process by numeric PID |
/IM image | Target process by image name (*.exe); wildcards allowed |
/F | Force-terminate (TerminateProcess) — no graceful shutdown |
/T | Kill the process and all child processes it spawned |
/FI filter | Apply a filter (same syntax as tasklist /FI) |
/S host | Remote machine |
/U domain\user | Credentials for remote kill |
/P password | Password for /U |
Kill by PID
/PID targets a specific process by its unique numeric ID — safer than killing by name when multiple instances of an executable are running.
taskkill /PID 8420
Output:
SUCCESS: Sent termination signal to the process with PID 8420.
rem Multiple PIDs in one command
taskkill /PID 8420 /PID 8421 /PID 8422
Output:
SUCCESS: Sent termination signal to the process with PID 8420.
SUCCESS: Sent termination signal to the process with PID 8421.
SUCCESS: Sent termination signal to the process with PID 8422.
Kill by image name
/IM kills all processes whose executable name matches. Wildcards (*) are supported — * alone matches everything, which terminates all user processes.
taskkill /IM notepad.exe
Output:
SUCCESS: Sent termination signal to the process "notepad.exe" with PID 8420.
rem Kill all chrome instances
taskkill /IM chrome.exe
Output:
SUCCESS: Sent termination signal to the process "chrome.exe" with PID 6124.
SUCCESS: Sent termination signal to the process "chrome.exe" with PID 6130.
Force termination (/F)
Without /F, taskkill sends a graceful close message; if the process ignores it or is frozen, the call returns success but the process stays running. /F calls TerminateProcess immediately — no cleanup, no save dialogs.
taskkill /F /IM myapp.exe
Output:
SUCCESS: The process "myapp.exe" with PID 7890 has been terminated.
taskkill /F /PID 8420
Output:
SUCCESS: The process with PID 8420 has been terminated.
Kill process tree (/T)
/T walks the process tree and terminates the target together with all descendants. This is essential for applications like build tools or test runners that spawn child processes — without /T, orphan children continue running.
taskkill /T /F /PID 5432
Output:
SUCCESS: The process with PID 5432 has been terminated.
SUCCESS: The process with PID 5433 has been terminated.
SUCCESS: The process with PID 5434 has been terminated.
rem Kill a node.js server and all its worker forks
taskkill /T /F /IM node.exe
Output:
SUCCESS: The process "node.exe" with PID 5432 has been terminated.
SUCCESS: The process "node.exe" with PID 5435 has been terminated.
Filter-based termination (/FI)
/FI accepts the same filter syntax as tasklist /FI, letting you target processes by memory usage, status, session, username, or other attributes.
rem Kill all non-responding processes
taskkill /F /FI "STATUS eq Not Responding"
Output:
SUCCESS: The process "myapp.exe" with PID 7890 has been terminated.
rem Kill all processes using more than 500 MB
taskkill /F /FI "MEMUSAGE gt 512000"
Output:
SUCCESS: The process "chrome.exe" with PID 6124 has been terminated.
rem Kill all processes in a specific session
taskkill /F /FI "SESSION eq 2"
Output:
SUCCESS: The process "explorer.exe" with PID 4200 has been terminated.
...
Remote process termination (/S)
/S targets a remote machine. Requires network access and appropriate permissions on the target.
taskkill /S myhost /U DOMAIN\alicedev /F /IM myapp.exe
Output:
Password: (prompted)
SUCCESS: The process "myapp.exe" with PID 7890 has been terminated.
Combining tasklist and taskkill
The canonical pattern for conditional termination: use tasklist to find the PID, then pass it to taskkill.
@echo off
for /f "tokens=2" %%p in ('tasklist /fi "IMAGENAME eq myapp.exe" /fo csv /nh 2^>NUL') do (
set PID=%%~p
)
if defined PID (
taskkill /F /PID %PID%
echo Killed PID %PID%.
) else (
echo myapp.exe not running.
)
Output:
Killed PID 7890.
Common pitfalls
- Graceful kill may silently fail — without
/F,taskkillreturns success even if the process ignores the close signal; always add/Fin scripts. /IM *kills everything — using a bare wildcard terminates all user-space processes includingexplorer.exe; be specific.- Cannot kill protected or system processes —
System,smss.exe, and other early-boot processes are protected; even with elevation they cannot be terminated withtaskkill. /Twithout/Fmay leave children — if children ignore the graceful signal, add/Fto force-terminate the whole tree.- "No tasks running" exit code is 128 —
taskkill /IM notrunning.exeexits with code 128 and prints an informational message, not an error; checkerrorlevel 128if you need to detect this. - Session vs PID targeting for multi-instance apps — for apps like
chrome.exerunning across sessions, combine/FI "SESSION eq N"with/IMto avoid killing processes in other user sessions.
Real-world recipes
Restart a service executable cleanly
@echo off
taskkill /F /IM myservice.exe
timeout /T 2 /NOBREAK > NUL
start "" "C:\Services\myservice.exe"
echo myservice restarted.
Output:
SUCCESS: The process "myservice.exe" with PID 4567 has been terminated.
myservice restarted.
Kill all non-responding processes in a maintenance script
@echo off
echo Checking for non-responding processes...
taskkill /F /FI "STATUS eq Not Responding" > NUL
echo Done.
Output:
Checking for non-responding processes...
Done.
Conditionally kill a process only if it is running
@echo off
tasklist /fi "IMAGENAME eq notepad.exe" 2>NUL | findstr "notepad.exe" >NUL
if not errorlevel 1 (
taskkill /F /IM notepad.exe
echo Notepad closed.
) else (
echo Notepad was not running.
)
Output:
SUCCESS: The process "notepad.exe" with PID 8420 has been terminated.
Notepad closed.
Kill a process tree by name for a test teardown
taskkill /T /F /IM pytest.exe > NUL 2>&1
taskkill /T /F /IM python.exe > NUL 2>&1
echo Test processes cleaned up.
Output:
Test processes cleaned up.
Graceful vs forced: what actually happens
taskkill without /F posts WM_CLOSE to every top-level window owned by the target thread; the application's message loop then has a chance to prompt for unsaved data and exit cleanly. /F skips all of that and calls TerminateProcess() — the kernel rips the process's address space out from under it with no atexit, no destructors, and no flushing of file buffers. Understanding which to use is the single most important taskkill decision.
| Signal sent | API used | What the process sees | Cleanup runs? |
|---|---|---|---|
| (no flag) | PostMessage(WM_CLOSE) to GUI threads | A "please close" hint | Yes (if it cooperates) |
/F | TerminateProcess() | Nothing — instant death | No |
/F /T | TerminateJobObject() plus per-PID TerminateProcess() | Nothing | No |
Ctrl+C (GenerateConsoleCtrlEvent) | Console signal | SetConsoleCtrlHandler fires | Yes (in handler) |
Practical implications:
- A console app with no GUI window will ignore the bare
taskkill— it never receivesWM_CLOSE. Always use/Ffor console apps. - A GUI app with an unsaved-changes prompt will show its "Save changes?" dialog and stay running until the user interacts. Use
/Ffor unattended scripts. - A process holding a file lock or pipe will leave that resource in a half-closed state after
/F. Other processes may need to retry I/O for a few seconds after the kill. - Database engines (SQL Server, PostgreSQL, etc.) treat
/Fas a crash and may run recovery on next startup. Prefersc stopor the engine's own shutdown path; only fall back totaskkill /Fwhen those hang.
rem Demonstrating graceful failure on a console app
taskkill /IM pythonw.exe
Output:
SUCCESS: Sent termination signal to the process "pythonw.exe" with PID 5432.
The "SUCCESS" message only confirms that the signal was sent — the process may still be alive. Verify with tasklist:
tasklist /fi "IMAGENAME eq pythonw.exe"
Output:
Image Name PID Session Name Session# Mem Usage
========================= ======== ================ =========== ============
pythonw.exe 5432 Console 1 42,332 K
Add /F to actually terminate it:
taskkill /F /IM pythonw.exe
Output:
SUCCESS: The process "pythonw.exe" with PID 5432 has been terminated.
Note the message wording difference: "Sent termination signal" (graceful) vs "has been terminated" (forced). When you read script logs, that wording is the only reliable indicator of which path was taken.
Exit codes in detail
taskkill is more careful than tasklist about distinguishing outcomes, which makes it scriptable in a way tasklist is not.
| Exit code | Condition |
|---|---|
0 | At least one process was killed (or signalled) successfully |
128 | No matching processes — "ERROR: The process … not found." |
255 | Access denied — caller lacks the required privilege |
1 | Bad parameters or filter syntax |
taskkill /IM doesnotexist.exe
echo Exit: %ERRORLEVEL%
Output:
ERROR: The process "doesnotexist.exe" not found.
Exit: 128
rem Permission denied on a protected process
taskkill /F /IM csrss.exe
echo Exit: %ERRORLEVEL%
Output:
ERROR: The process with PID 680 could not be terminated.
Reason: Access is denied.
Exit: 255
rem Defensive script that swallows "not found" but propagates real errors
taskkill /F /IM myapp.exe
if errorlevel 255 ( echo Hard error & exit /b 1 )
if errorlevel 128 ( echo Already gone & exit /b 0 )
echo Killed cleanly
Output:
Killed cleanly
PowerShell equivalent — Stop-Process
Stop-Process (alias kill/spps) is the modern replacement and what new PowerShell scripts should use. It always force-terminates — there is no graceful mode — but it accepts the pipeline so you can chain it with filters and confirmation logic that taskkill cannot express.
Direct equivalents
taskkill | Stop-Process |
|---|---|
taskkill /F /PID 8420 | Stop-Process -Id 8420 -Force |
taskkill /F /IM notepad.exe | Stop-Process -Name notepad -Force |
taskkill /F /IM "chrome.exe" (multiple) | Stop-Process -Name chrome -Force |
taskkill /S host /F /PID 8420 | Invoke-Command -ComputerName host { Stop-Process -Id 8420 -Force } |
Pipeline patterns
Get-Process notepad -ErrorAction SilentlyContinue | Stop-Process -Force
Output: (no output on success)
Get-Process | Where-Object { $_.WorkingSet64 -gt 500MB -and $_.Name -ne 'sqlservr' } |
Stop-Process -Force -WhatIf
Output:
What if: Performing the operation "Stop-Process" on target "chrome (6124)".
What if: Performing the operation "Stop-Process" on target "code (8732)".
-WhatIf is the safety net taskkill doesn't have — preview the kill list before committing. -Confirm prompts per process.
Stop-Process limitations vs taskkill
- No graceful mode.
Stop-Processis always force; if you needWM_CLOSEsemantics use(Get-Process notepad).CloseMainWindow()first and only callStop-Processas a fallback. - No
/Tflag — to kill a tree, enumerate children manually:
function Stop-ProcessTree {
param([int]$Id)
Get-CimInstance Win32_Process -Filter "ParentProcessId=$Id" |
ForEach-Object { Stop-ProcessTree -Id $_.ProcessId }
Stop-Process -Id $Id -Force -ErrorAction SilentlyContinue
}
Stop-ProcessTree -Id 5432
Output: (none on success — the tree under PID 5432 is gone)
Graceful close in PowerShell
$p = Get-Process notepad -ErrorAction SilentlyContinue
if ($p) {
$p | ForEach-Object { $_.CloseMainWindow() | Out-Null }
Start-Sleep -Seconds 3
$p | Where-Object { -not $_.HasExited } | Stop-Process -Force
}
Output: (none — closes Notepad gracefully if it has no unsaved changes, force-kills otherwise)
The /T flag and job objects
/T walks the process tree at kill-time by querying NtQuerySystemInformation for each process's ParentProcessId and recursively terminating. This has two pitfalls:
- Reparenting. When a parent exits and its child is still running, modern Windows reparents the child to PID 4 (
System) or an arbitrary ancestor — the original tree relationship is lost./Tcannot find children orphaned this way. - PID reuse. Windows recycles PIDs aggressively. If a parent process exits and Windows reuses its PID before
/Twalks the tree,taskkill /Tmay kill an unrelated process that happens to be the child of the recycled PID. Race-prone in fast-spawn workloads.
The robust alternative is Job Objects — Windows' native mechanism for grouping processes. Anything you launch via start /b or PowerShell's Start-Process can be assigned to a job; killing the job kills every member atomically. Sysinternals' pskill doesn't help here either, but Stop-Process plus a Win32_Process recursion is usually safer in PowerShell than taskkill /T.
function Stop-ProcessTreeJob {
param([int]$Id)
$children = Get-CimInstance Win32_Process -Filter "ParentProcessId=$Id"
foreach ($c in $children) { Stop-ProcessTreeJob -Id $c.ProcessId }
try { Stop-Process -Id $Id -Force -ErrorAction Stop }
catch [Microsoft.PowerShell.Commands.ProcessCommandException] { }
}
Output: (function definition — no console output)
Sysinternals PsKill
The Sysinternals pskill utility (see the Sysinternals deep-dive) is a richer kill tool worth knowing about even if you mostly stick with taskkill. It accepts PID or name, supports remote machines without DCOM, and has a useful -t (tree kill) that uses the same recursion as Stop-ProcessTree above.
pskill -accepteula 8420
pskill -t -accepteula notepad.exe
pskill \\myhost -u myhost\alicedev 8420
Output:
Process notepad.exe killed.
Why prefer pskill over taskkill:
- Cleaner remote semantics (works over SMB without requiring Remote Registry).
- Tree-kill is recursive via the same Win32 APIs, but pskill enumerates children at the moment of the kill rather than racing.
- Returns clean exit codes (0/1) with a single line of output, easier to parse than
taskkill's "SUCCESS: …".
Why stick with taskkill:
- In-box; no install required.
- Supports
/FIfilters likeSTATUS eq Not Respondingwhich pskill lacks. - Standardised across Windows 10/11 even on locked-down hosts where you can't drop binaries.
Comparison: taskkill vs Stop-Process vs pskill vs wmic
| Capability | taskkill | Stop-Process | pskill (Sysinternals) | wmic process call terminate |
|---|---|---|---|---|
| Built-in | yes | yes (PS) | no — install required | yes (deprecated) |
| Graceful close | yes (no /F) | only via .CloseMainWindow() | no | no |
| Force kill | /F | always | always | always |
| Tree kill | /T | manual via CIM | -t | no |
| Filter by status | /FI "STATUS eq Not Responding" | Where-Object Responding -eq $false | no | where "..." clauses |
| Remote | /S | Invoke-Command | \\host | /node:host |
| Survives 2025+ Windows | yes | yes | yes | no (24H2+) |
| Pipeline | no | yes | no | no |
Cross-platform: kill, killall, pkill vs taskkill
For Linux/macOS muscle memory, the closest equivalents are POSIX kill (by PID), killall (by exact name), and pkill (by name with regex). Conceptually they all take signal numbers rather than a force flag — the closest mapping:
| Linux | Windows equivalent | Notes |
|---|---|---|
kill 1234 (SIGTERM) | taskkill /PID 1234 | Graceful — process gets a chance to exit |
kill -9 1234 (SIGKILL) | taskkill /F /PID 1234 | Force — kernel terminates immediately |
killall notepad | taskkill /IM notepad.exe | By name, all instances |
killall -9 notepad | taskkill /F /IM notepad.exe | Force, by name |
pkill -f "node.*server" | no direct equivalent — use Get-CimInstance filter on CommandLine | |
kill -- -PGID (kill process group) | taskkill /T /F /PID PID (tree) | Job Objects are closer but require setup |
pkill --signal HUP (reload config) | no equivalent | Windows services use sc control |
Windows has no SIGHUP. Services that want a "reload config" path implement it via the SCM (
sc control SERVICE 128–255for user-defined control codes) or by watching a file for changes. Don't try to emulate SIGHUP withtaskkill.
Privilege requirements
Killing certain processes requires more than a standard admin token. The rules of thumb:
| Target | Minimum privilege |
|---|---|
| Your own user-space processes | None |
| Another user's processes in your session | Administrator |
| Processes in another session | Administrator |
Service processes (svchost, etc.) | Administrator |
csrss.exe, wininit.exe, services.exe | Cannot kill — critical, protected |
| Antimalware engines | Often Protected Process Light (PPL) — refuses even SYSTEM |
LSASS | Cannot kill — would crash the system |
To check whether your shell has the rights:
whoami /priv | findstr SeDebugPrivilege
Output:
SeDebugPrivilege Debug programs Disabled
The privilege exists but is Disabled; admins must enable it explicitly (it's enabled automatically for the SYSTEM account). Sysinternals psexec -s opens a cmd.exe running as SYSTEM with SeDebugPrivilege already enabled — the standard escalation path when taskkill /F returns "Access denied".
Defensive scripting patterns
Idempotent kill — "stop if running, don't fail if not"
@echo off
taskkill /F /IM myapp.exe >nul 2>&1
if errorlevel 128 (
rem 128 = not found — that's fine
exit /b 0
)
if errorlevel 1 (
echo Failed to kill myapp.exe ^(errorlevel %ERRORLEVEL%^)
exit /b 1
)
echo Killed myapp.exe
Output:
Killed myapp.exe
Bounded retry on a stubborn process
Some processes (notably anti-malware or DRM clients) take a few seconds to actually exit after a /F. Poll with tasklist until they disappear:
@echo off
setlocal
set TRIES=0
:retry
taskkill /F /IM stubborn.exe >nul 2>&1
timeout /t 1 /nobreak >nul
tasklist /fi "IMAGENAME eq stubborn.exe" 2>nul | findstr /I "stubborn.exe" >nul
if errorlevel 1 (
echo stubborn.exe is gone
exit /b 0
)
set /a TRIES+=1
if %TRIES% lss 10 goto retry
echo Failed after %TRIES% attempts
exit /b 1
Output:
stubborn.exe is gone
Drain a process tree before killing
The cleanest shutdown sequence for cooperative children is: stop accepting new work, ask gracefully, wait, then escalate. PowerShell makes this composable:
$root = Get-Process myservice -ErrorAction SilentlyContinue
if ($root) {
$root | ForEach-Object { $_.CloseMainWindow() } | Out-Null
Start-Sleep -Seconds 10
$still = Get-Process myservice -ErrorAction SilentlyContinue
if ($still) {
Write-Warning "Escalating to force-kill on $($still.Count) holdout(s)"
$still | Stop-Process -Force
}
}
Output:
WARNING: Escalating to force-kill on 1 holdout(s)
Kill by command-line substring (taskkill can't, but here's how)
taskkill has no CommandLine filter. Use CIM to find PIDs by command-line substring, then pipe them in:
Get-CimInstance Win32_Process -Filter "Name='node.exe'" |
Where-Object { $_.CommandLine -like '*--server*' } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force }
Output: (none on success)
Common pitfalls — extended
In addition to the basics above:
taskkilldoesn't release the file lock immediately. After/F, the Windows file system may keep the handle table dirty for a few hundred milliseconds. Subsequent file operations against the freshly-killed process's open files should retry onERROR_SHARING_VIOLATION./IM *is not safer with/F— it just makes the disaster faster. The shell that ran it survives only because cmd.exe is killed asynchronously after dispatching all the children.- Sessions don't isolate
/Fby default. A user in session 2 cannottaskkill /Fprocesses in session 1 unless they are an administrator — but admins can. Don't assume session boundary is a security barrier. - Antivirus may roll back
/F. Some EDRs treat ataskkill /Fagainst their agents as tampering and immediately relaunch the process. Use the vendor's own uninstall/stop path instead. /FI "STATUS eq Not Responding"is a snapshot. A process that's briefly busy may show "Not Responding" for one polling interval then recover. Re-check after a few seconds before killing.- Windows 11 24H2/25H2 Task Manager bug — Microsoft has acknowledged that closing Task Manager on 24H2/25H2 does not always terminate
Taskmgr.exe, so opening it again accumulates a fresh process each time. The clean-up is a singletaskkill /F /IM Taskmgr.exe(or the PowerShellStop-Process -Name Taskmgr -Force) — worth running before opening Task Manager to inspect memory usage on those builds.
Real-world deep recipes
Find the parent of a runaway process, kill the whole tree from the top
function Get-ProcessAncestry {
param([int]$Id)
$p = Get-CimInstance Win32_Process -Filter "ProcessId=$Id"
while ($p) {
$p | Select-Object ProcessId, Name, ParentProcessId
if ($p.ParentProcessId -eq 0) { break }
$p = Get-CimInstance Win32_Process -Filter "ProcessId=$($p.ParentProcessId)"
}
}
Get-ProcessAncestry -Id 5432
Output:
ProcessId Name ParentProcessId
--------- ---- ---------------
5432 worker.exe 4900
4900 launcher.exe 3456
3456 explorer.exe 3320
3320 userinit.exe 0
Cleanup orchestration for a CI test runner
@echo off
rem End-of-job teardown: kill everything we might have spawned
for %%P in (pytest.exe python.exe node.exe chromedriver.exe geckodriver.exe) do (
taskkill /F /T /IM %%P >nul 2>&1
)
rem Catch any lingering test browsers — but not the user's actual browser
taskkill /F /FI "WINDOWTITLE eq Selenium*" >nul 2>&1
echo Test harness cleaned up
Output:
Test harness cleaned up
Watchdog: kill any process that stays "Not Responding" for two consecutive minutes
$prevHung = @()
while ($true) {
$curHung = Get-Process | Where-Object { -not $_.Responding } | Select-Object -ExpandProperty Id
$dead = $prevHung | Where-Object { $_ -in $curHung }
foreach ($id in $dead) {
try {
$p = Get-Process -Id $id -ErrorAction Stop
Write-Host "Killing hung $($p.Name) ($id)"
Stop-Process -Id $id -Force
} catch { }
}
$prevHung = $curHung
Start-Sleep -Seconds 60
}
Output:
Killing hung notepad (8420)
See also
- tasklist — List Running Processes — find what to kill before killing it.
- sc — Service Control Manager CLI — preferred shutdown path for services; only fall back to
taskkill /Fifsc stophangs. - Sysinternals — PsExec, Handle, ProcMon and the Sysadmin Toolkit —
pskill,pslist, andhandlefor forensic process work. - wmic — Windows Management Instrumentation CLI —
wmic process call terminate(deprecated but sometimes the only option on legacy hosts). - htop — Interactive process viewer — the Linux side of the kill-by-name story.
Sources
learn.microsoft.com — taskkill · learn.microsoft.com — Stop-Process