cheat sheet

tasklist

Display all running processes on a local or remote Windows machine with PID, memory usage, session, and optional service or module details — the cmd.exe equivalent of Task Manager for scripts.

tasklist — List Running Processes

What it is

tasklist is a built-in Windows command that enumerates all running processes and reports their image name, PID, session name, session number, and memory usage. It can optionally list the services hosted by a process (/svc), the DLLs loaded by a process (/m), and supports filter expressions to narrow the output. Use tasklist when you need a scriptable process snapshot — particularly in combination with taskkill to find and terminate specific processes. The PowerShell equivalent is Get-Process.

Availability

tasklist ships as C:\Windows\System32\tasklist.exe on Windows XP and later.

cmd
tasklist /?

Output:

css
TASKLIST [/S system [/U username [/P [password]]]]
         [/M [module] | /SVC | /V] [/FI filter] [/FO format] [/NH]

Syntax

cmd
tasklist [/S host] [/U user] [/P pass] [/M [module]] [/SVC] [/V] [/FI filter] [/FO TABLE|LIST|CSV] [/NH]

Output: (process list)

Essential options

SwitchMeaning
/FO TABLETabular output (default)
/FO LISTOne field per line
/FO CSVComma-separated values — best for scripting
/NHSuppress column headers
/VVerbose: add window title, CPU time, user name
/M [module]List DLLs loaded by each process (optionally filter by module name)
/SVCShow services hosted in each process
/FI filterApply a filter expression (see filter section below)
/S hostQuery a remote machine
/U domain\userCredentials for remote query
/P passwordPassword for /U

Basic process list

Running tasklist without arguments produces a table of every process with PID, session, and memory usage.

cmd
tasklist

Output:

arduino
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
System Idle Process              0 Services                   0          8 K
System                           4 Services                   0      1,440 K
Registry                       100 Services                   0     42,440 K
smss.exe                       412 Services                   0        992 K
csrss.exe                      680 Services                   0      5,124 K
...
notepad.exe                   8420 Console                    1     23,456 K

CSV format for scripting

/FO CSV outputs a header row followed by one data row per process, suitable for parsing with for /f or importing into Excel or a SIEM.

cmd
tasklist /fo csv

Output:

arduino
"Image Name","PID","Session Name","Session#","Mem Usage"
"System Idle Process","0","Services","0","8 K"
"System","4","Services","0","1,440 K"
...
"notepad.exe","8420","Console","1","23,456 K"
cmd
tasklist /fo csv /nh

Output:

arduino
"System Idle Process","0","Services","0","8 K"
"System","4","Services","0","1,440 K"
...

Filtering with /FI

/FI applies a filter using fieldname operator value syntax. Multiple /FI flags are ANDed together. Supported operators: eq, ne, gt, lt, ge, le.

Filter fieldTypeExample
IMAGENAMEstring/FI "IMAGENAME eq notepad.exe"
PIDnumeric/FI "PID eq 8420"
SESSIONnumeric/FI "SESSION eq 1"
SESSIONNAMEstring/FI "SESSIONNAME eq Console"
STATUSstring/FI "STATUS eq Not Responding"
MEMUSAGEnumeric (KB)/FI "MEMUSAGE gt 100000"
USERNAMEstring/FI "USERNAME eq alicedev"
SERVICESstring/FI "SERVICES eq wuauserv"
WINDOWTITLEstring/FI "WINDOWTITLE eq Untitled*"
MODULESstring/FI "MODULES eq ntdll.dll"
CPUTIMEstring (HH:MM:SS)/FI "CPUTIME gt 00:10:00"
cmd
tasklist /fi "IMAGENAME eq notepad.exe"

Output:

arduino
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
notepad.exe                   8420 Console                    1     23,456 K
cmd
rem All processes using more than 100 MB
tasklist /fi "MEMUSAGE gt 102400"

Output:

arduino
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
chrome.exe                    6124 Console                    1    512,340 K
explorer.exe                  3456 Console                    1    145,232 K
cmd
rem Find non-responding processes
tasklist /fi "STATUS eq Not Responding"

Output:

arduino
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
myapp.exe                     7890 Console                    1    234,567 K

Services per process (/SVC)

/SVC adds a Services column listing every Windows service hosted within each svchost.exe instance — essential for identifying which service group owns a given svchost PID.

cmd
tasklist /svc

Output:

css
Image Name                     PID Services
========================= ======== ============================================
System Idle Process              0 N/A
System                           4 N/A
svchost.exe                    960 DcomLaunch, PlugPlay, Power
svchost.exe                   1256 RpcEptMapper, RpcSs
svchost.exe                   1488 BrokerInfrastructure, DPS, ...
...
notepad.exe                   8420 N/A
cmd
rem Find the svchost hosting the Windows Update service
tasklist /svc | findstr "wuauserv"

Output:

yaml
svchost.exe                   2340 wuauserv

Loaded modules (/M)

/M lists every DLL loaded by each process. Optionally provide a DLL name fragment to filter to only processes loading that module.

cmd
tasklist /m ntdll.dll

Output:

css
Image Name                     PID Modules
========================= ======== ============
System Idle Process              0 N/A
smss.exe                       412 ntdll.dll
csrss.exe                      680 ntdll.dll
...

Verbose output (/V)

/V adds window title, CPU time, and the user account owning each process — the closest equivalent to Task Manager's Details view.

cmd
tasklist /v /fi "IMAGENAME eq notepad.exe"

Output:

sql
Image Name    PID   Session Name  Ses#  Mem Usage  Status    User Name   CPU Time   Window Title
============= ===== ============= ===== =========  ========= =========== ========== ===============
notepad.exe   8420  Console          1    23,456 K  Running   myhost\alicedev  0:00:00  Untitled - Notepad

Remote process list (/S)

/S queries a remote machine. Requires network access and the Remote Registry service running on the target.

cmd
tasklist /s myhost /u DOMAIN\alicedev

Output:

makefile
Password: (prompted)

Image Name                     PID Session Name        Session#    Mem Usage
...

Common pitfalls

  1. No wildcard in /FI IMAGENAMEIMAGENAME eq note* does not work; use findstr to filter output instead: tasklist | findstr "note".
  2. "INFO: No tasks are running…" — the filter matched nothing; this is not an error but has exit code 0; check errorlevel is unreliable for detecting missing processes.
  3. /M without a module name lists all DLLs — output can be very large; always filter with a module name or pipe to findstr.
  4. Remote /S needs Remote Registry service — the service must be running on the target machine; it is disabled by default on modern Windows.
  5. /V adds CPU time, not CPU % — for live CPU percentage, use PowerShell Get-Process or Task Manager.

Real-world recipes

Check whether a process is running in a script

cmd
@echo off
tasklist /fi "IMAGENAME eq myapp.exe" 2>NUL | findstr "myapp.exe" >NUL
if errorlevel 1 (
    echo myapp.exe is not running
) else (
    echo myapp.exe is running
)

Output:

arduino
myapp.exe is not running

Get PID of a named process for use with taskkill

cmd
for /f "tokens=2" %p in ('tasklist /fi "IMAGENAME eq notepad.exe" /fo csv /nh') do (
    echo Notepad PID: %~p
)

Output:

yaml
Notepad PID: 8420

Export full process snapshot for a support ticket

cmd
tasklist /v /fo csv > %TEMP%\procs_%COMPUTERNAME%.csv
echo Saved to %TEMP%\procs_%COMPUTERNAME%.csv

Output:

css
Saved to C:\Users\alicedev\AppData\Local\Temp\procs_MYHOST.csv

Find all svchost PIDs and their services

cmd
tasklist /svc /fi "IMAGENAME eq svchost.exe" /fo list

Output:

yaml
Image Name:   svchost.exe
PID:          960
Services:     DcomLaunch, PlugPlay, Power

Image Name:   svchost.exe
PID:          1256
Services:     RpcEptMapper, RpcSs
...

Filter operators in depth

The /FI filter language uses three-token expressions of the form FIELD OP VALUE. The operator set is small but the field-to-operator mapping is strict — numeric operators on string fields, or vice versa, produce "Invalid argument/option" with exit code 1 rather than empty output. Knowing which operators are legal per field saves a lot of script debugging.

cmd
rem Operators by field type
rem  - String fields: eq, ne  (no greater-than/less-than)
rem  - Numeric fields: eq, ne, gt, lt, ge, le
rem  - Status field:  eq, ne against "Running" | "Not Responding" | "Unknown"

Output: (none — comments only, reference for the table below)

cmd
rem Multiple /FI flags are ANDed; there is no OR within tasklist itself
tasklist /fi "USERNAME eq myhost\alicedev" /fi "MEMUSAGE gt 100000" /fi "STATUS eq Running"

Output:

arduino
Image Name                     PID Session Name        Session#    Mem Usage
========================= ======== ================ =========== ============
chrome.exe                    6124 Console                    1    512,340 K
code.exe                      8732 Console                    1    287,116 K

For OR-logic, run two tasklist invocations and merge the output:

cmd
( tasklist /fi "IMAGENAME eq chrome.exe" /fo csv /nh ^
& tasklist /fi "IMAGENAME eq msedge.exe" /fo csv /nh ) > browsers.csv

Output: (no console output — browsers.csv contains both result sets)

PowerShell equivalents

PowerShell's Get-Process (alias gps/ps) is the modern replacement for tasklist. It returns rich System.Diagnostics.Process objects instead of fixed-width text, so filtering and aggregation use the pipeline rather than a custom mini-language. Reach for it whenever you need CPU%, parent PID, start time, or anything else tasklist cannot show.

Basic listing

powershell
Get-Process

Output:

scss
 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName
 ------    -----      -----     ------      --  -- -----------
     11     2.41       8.31       0.06    8420   1 notepad
     45    96.15     145.22     124.50    6124   1 chrome

Filtering with the pipeline

powershell
Get-Process | Where-Object { $_.WorkingSet64 -gt 100MB } |
    Sort-Object WorkingSet64 -Descending |
    Select-Object -First 10 Name, Id, @{N='WS(MB)';E={[int]($_.WorkingSet64/1MB)}}

Output:

yaml
Name        Id WS(MB)
----        -- ------
chrome    6124    512
explorer  3456    145
code      8732    287

Properties tasklist cannot show

powershell
Get-Process notepad | Select-Object Id, ProcessName, StartTime, Path,
    @{N='CPU%';E={(Get-Counter "\Process($($_.Name))\% Processor Time").CounterSamples.CookedValue}}

Output:

yaml
Id          : 8420
ProcessName : notepad
StartTime   : 5/24/2026 9:14:22 AM
Path        : C:\Windows\System32\notepad.exe
CPU%        : 0.12

Parent PID, command line, and ownership via CIM

Get-Process does not expose the command line or parent PID directly. Use Get-CimInstance Win32_Process for those — it's also the documented replacement for the now-deprecated Get-WmiObject cmdlet.

powershell
Get-CimInstance Win32_Process -Filter "Name='notepad.exe'" |
    Select-Object ProcessId, ParentProcessId, CommandLine,
        @{N='Owner';E={ (Invoke-CimMethod $_ -MethodName GetOwner).User }}

Output:

yaml
ProcessId       : 8420
ParentProcessId : 3456
CommandLine     : "C:\Windows\System32\notepad.exe" C:\temp\notes.txt
Owner           : alicedev

Get-WmiObject is deprecated in PowerShell 7+ and removed from PowerShell Core entirely. New scripts targeting cross-version PowerShell should always use Get-CimInstance and Invoke-CimMethod — they speak WS-MAN over WinRM remotely and are noticeably faster for local queries too.

Sysinternals PsList for richer detail

The Sysinternals pslist tool (see Sysinternals) is a drop-in upgrade when tasklist is too limited. It can show per-process CPU% sampled over an interval, full thread enumeration, memory categories (private bytes vs working set vs virtual), and per-process uptime. Unlike Get-Process, it stays purely command-line — no PowerShell required.

cmd
rem One-shot snapshot — like tasklist but with CPU and elapsed time
pslist -accepteula notepad

Output:

css
Name                Pid  Pri Thd  Hnd      Priv        CPU Time     Elapsed Time
notepad            8420    8   4  287     5,432     0:00:00.046     0:14:22.812
cmd
rem Sample CPU usage for 5 seconds — gives a real % instead of cumulative time
pslist -s 5 -accepteula

Output:

yaml
Name             Pid  CPU      Time
chrome          6124  12.4%   2:15:33
code            8732   3.1%   0:42:18
explorer        3456   0.2%   1:14:55

The Sysinternals deep-dive covers the full toolkit including handle, procmon, and listdlls for when even pslist isn't enough.

Comparison: tasklist vs Get-Process vs wmic vs pslist

Pick a tool by the question being asked. All four are scriptable; they differ in machine-readability, available properties, and platform survival.

CapabilitytasklistGet-ProcessGet-CimInstance Win32_Processpslist
Built-inyesyes (PowerShell)yes (PowerShell)no — Sysinternals
CPU percentnoindirectnoyes
Command linenonoyesno
Parent PIDnono (ParentId in PS7+)yesyes
Process ownerwith /V onlynovia GetOwner() methodno
Loaded modulesyes (/m)yes (.Modules)nono (use listdlls)
Services hostedyes (/svc)noindirectno
Remote machineyes (/S)yes (-ComputerName)yes (-ComputerName)yes (\\host)
Survives 2025+ Windowsyesyesyesyes
Object pipelineno — fixed textyesyesno

A useful heuristic: use tasklist for batch scripts and quick checks, Get-Process for any logic that needs to compose with other PowerShell, Get-CimInstance Win32_Process when you specifically need command line or parent PID, and pslist when you need CPU% from a non-PowerShell shell.

Exit codes and detecting "no match"

tasklist returns 0 in nearly every scenario — including the "no match found" case, which prints to stderr but does not raise an error level. Scripts must scan the output rather than trust %ERRORLEVEL%.

cmd
tasklist /fi "IMAGENAME eq notarealprocess.exe"
echo Exit code: %ERRORLEVEL%

Output:

sql
INFO: No tasks are running which match the specified criteria.
Exit code: 0

The canonical "is it running?" check uses findstr as the actual predicate:

cmd
tasklist /fi "IMAGENAME eq myapp.exe" 2>nul | findstr /I /C:"myapp.exe" >nul
if errorlevel 1 (
    echo NOT running
) else (
    echo running
)

Output:

arduino
NOT running

PowerShell's equivalent is cleaner because it returns $null rather than printing:

powershell
if (Get-Process myapp -ErrorAction SilentlyContinue) {
    Write-Host "running"
} else {
    Write-Host "NOT running"
}

Output:

arduino
NOT running

Memory units and accuracy

Mem Usage in tasklist is the working set in KB — the resident set, comparable to RSS on Linux. It does not include paged-out memory, kernel-paged pool, or commit charge. For accurate memory analysis prefer one of the following.

MetricWhat it meansWhere to get it
Working Set (Mem Usage)Resident pages in RAM right nowtasklist, Get-Process.WorkingSet64
Private BytesPages backed only by paging file (a process's "real" footprint)Get-Process.PrivateMemorySize64, pslist
Commit SizeMemory the process has reserved (committed)Get-CimInstance Win32_Process.VirtualSize
Virtual SizeTotal address space — includes shared imagesSame as above
Pagefile UsageBytes paged outGet-CimInstance.PageFileUsage
powershell
Get-Process chrome |
  Select-Object Id,
    @{N='WS(MB)';E={[int]($_.WorkingSet64/1MB)}},
    @{N='Private(MB)';E={[int]($_.PrivateMemorySize64/1MB)}},
    @{N='VM(MB)';E={[int]($_.VirtualMemorySize64/1MB)}}

Output:

scss
   Id WS(MB) Private(MB) VM(MB)
   -- ------ ----------- ------
 6124    512         478   2104
 6130    214         189    980

Performance and remote queries

tasklist is fast on a local machine (~30–80 ms cold, mostly spent walking the process list once). Remote queries via /S are an order of magnitude slower because the call traverses the Remote Registry service over RPC.

ModeTypical wall time on a healthy fleet box
Local tasklist30–80 ms
Local tasklist /v /svc200–500 ms (enumerates services + window titles)
Remote tasklist /s host1.5–5 s (RPC handshake dominates)
Get-Process -ComputerName host1–3 s (WMI/CIM, slightly faster than /S)
Get-Process over Invoke-Command -Session $s~200 ms after first call (WinRM session reuse)

For repeated remote polls in a monitoring loop, open a persistent WinRM session and reuse it rather than spawning tasklist /S every iteration:

powershell
$s = New-PSSession -ComputerName myhost
Invoke-Command -Session $s -ScriptBlock {
    Get-Process | Where-Object WorkingSet64 -gt 200MB
}
Remove-PSSession $s

Output:

scss
 NPM(K)    PM(M)      WS(M)     CPU(s)      Id  SI ProcessName  PSComputerName
 ------    -----      -----     ------      --  -- -----------  --------------
     45    96.15     512.40   1240.10    6124   1 chrome       myhost
     38    78.50     287.11    412.30    8732   1 code         myhost

Cross-platform comparison: tasklist vs ps/htop

Coming from Linux, the closest analogues are ps, pgrep, and htop (see the htop deep-dive). The semantics diverge in two important ways: Windows process trees flatten more aggressively (orphans reparent to PID 4 System), and Windows distinguishes session IDs (TS sessions, not just controlling terminals).

LinuxWindows equivalent
ps auxtasklist /v
ps -ef --foresttasklist /v /svc (no built-in tree; use pslist -t)
pgrep -f "notepad"tasklist /fi "IMAGENAME eq notepad.exe"
ps -o pid,comm,%cpu,%mem`Get-Process
top / htop`Get-Process
pidof myappfor /f "tokens=2" %P in ('tasklist /fi "imagename eq myapp.exe" /fo csv /nh') do @echo %P
ps --ppid 1234Get-CimInstance Win32_Process -Filter "ParentProcessId=1234"
lsof -p 1234handle -p 1234 (Sysinternals)

tasklist does not show a process tree. For a visual hierarchy from the command line, use pslist -t -accepteula (Sysinternals) — it indents children under their parents the same way pstree does on Linux.

Real-world deep recipes

Top-10 memory consumers as a one-liner

cmd
tasklist /fo csv /nh > %TEMP%\plist.csv
powershell -NoProfile -Command ^
    "Import-Csv %TEMP%\plist.csv -Header 'Image','PID','Sess','S#','Mem' | ^
     ForEach-Object { $_.Mem = [int]($_.Mem -replace '[^0-9]','') ; $_ } | ^
     Sort-Object Mem -Descending | Select-Object -First 10 | Format-Table"

Output:

arduino
Image            PID  Sess     S#   Mem
-----            ---  ----     --   ---
chrome.exe       6124 Console  1   512340
code.exe         8732 Console  1   287116
explorer.exe     3456 Console  1   145232
...

Wait for a process to exit then run a follow-up

cmd
@echo off
:wait_loop
tasklist /fi "IMAGENAME eq longjob.exe" 2>nul | findstr /I /C:"longjob.exe" >nul
if not errorlevel 1 (
    timeout /t 5 /nobreak >nul
    goto wait_loop
)
echo longjob.exe finished; running follow-up...
call post_job.bat

Output:

arduino
longjob.exe finished; running follow-up...

Audit all processes loading a suspect DLL

When IT/security wants to find every process loading bad.dll across an audit run, tasklist /m is the simplest discovery tool. Pipe through findstr to drop "N/A" rows and keep only matches:

cmd
tasklist /m bad.dll 2>nul | findstr /V "N/A" | findstr /V "^Image Name" | findstr /V "^="

Output:

yaml
suspectapp.exe              7890 bad.dll
otherapp.exe               12044 bad.dll

Snapshot to JSON for ingest by an observability pipeline

tasklist itself cannot emit JSON. Pipe through PowerShell to convert:

cmd
tasklist /v /fo csv > %TEMP%\snap.csv
powershell -NoProfile -Command ^
    "Import-Csv %TEMP%\snap.csv | ConvertTo-Json -Depth 3" > %TEMP%\snap.json

Output: (none — written to %TEMP%\snap.json)

json
[
  { "Image Name": "notepad.exe", "PID": "8420", "Session Name": "Console",
    "Session#": "1", "Mem Usage": "23,456 K", "Status": "Running",
    "User Name": "myhost\\alicedev", "CPU Time": "0:00:00", "Window Title": "Untitled - Notepad" }
]

Compare two snapshots to find new processes

powershell
$before = tasklist /fo csv | ConvertFrom-Csv
Start-Sleep 30
$after  = tasklist /fo csv | ConvertFrom-Csv

Compare-Object $before $after -Property PID -PassThru |
    Where-Object SideIndicator -eq '=>' |
    Select-Object PID, 'Image Name', 'Mem Usage'

Output:

css
PID    Image Name        Mem Usage
---    ----------        ---------
14228  msedge.exe        212,500 K
14290  msedgewebview2.exe 88,310 K

Security and forensics notes

tasklist itself is unprivileged — any user can list processes they have query access to. Several caveats matter for IR and audit work:

  • Protected processes (csrss.exe, antivirus engines, LSASS on modern Windows) refuse to expose their command line or modules to non-SYSTEM callers; tasklist /m simply omits them with no warning.
  • Hidden processes via rootkit are invisible to tasklist because it relies on the documented Toolhelp32/NtQuerySystemInformation paths the rootkit will have hooked. For forensic snapshots use a kernel-level tool — Sysinternals pslist queries the same APIs but procmon and handle reach into the kernel handle tables.
  • Username field can be spoofed in older Windows by token impersonation; cross-check with Get-CimInstance Win32_Process and (Invoke-CimMethod -MethodName GetOwner) for the authoritative owner SID.
  • Remote /S without explicit /U uses the current credentials — easy to leak admin credentials onto a compromised host. In hardened environments use a dedicated audit account.

See also

Sources

learn.microsoft.com — tasklist · learn.microsoft.com — Get-Process · learn.microsoft.com — Get-CimInstance