cheat sheet
Sysinternals
Bootstrap and drive the headless Sysinternals utilities — PsExec, Handle, PsList, Autoruns, ProcMon, ListDLLs — for process spelunking, file-lock hunting, autostart auditing and scripted system tracing on Windows.
Sysinternals — PsExec, Handle, ProcMon and the Sysadmin Toolkit
What it is
The Sysinternals Suite is a collection of ~70 advanced Windows utilities originally written by Mark Russinovich and Bryce Cogswell at Sysinternals.com, now maintained by Microsoft. Where the in-box tasklist and taskkill answer only the most basic process questions, Sysinternals tools go several layers deeper: which file handle is locking a binary, which DLL is loaded by which process, what every autostart entry does at boot, and what a process actually touches on disk and registry from the moment it spawns. Reach for Sysinternals when the built-in CLI doesn't tell you enough — and reach for the headless variants (PsExec, Handle, PsList, autorunsc, ProcMon's /BackingFile, ListDLLs) when you need to script the answer rather than click through a GUI.
This page is a compendium covering the six tools most often used from the command line. All of them are EULA-gated on first launch; bypass the dialog non-interactively with -accepteula (or /accepteula for ProcMon).
What's new in 2026
Microsoft shipped a broad Sysinternals refresh on May 7, 2026 — keep your local copies current, several of the command-line tools picked up scriptable features:
| Tool | New version | What changed |
|---|---|---|
Autoruns / autorunsc.exe | v14.2 | First-class support for Windows packaged (MSIX/AppX) auto-start entries — the headless autorunsc -a * now surfaces Store apps that used to be invisible. |
| ProcDump | v12.0 | New -pt (process-tree) flag — dump the target and every descendant in one command, which closes the long-standing gap when triaging short-lived child processes. |
Process Monitor (procmon.exe) | v4.02 | Stability and filter-engine fixes; the /BackingFile switch remains the way to capture headlessly. |
| Process Explorer | v17.12 | New event-monitoring details and bug fixes for Windows 11 26x builds. |
| DebugView | v5.01 | Reinstated Windows 10 support, added per-PID highlighting. |
| ZoomIt | v12.0 | Webcam overlay for video capture, video-trim append — relevant when recording demos from a console session. |
| NotMyFault | v4.5 | Refreshed driver signing for current Windows builds. |
| RAMMap / Sysmon / Coreinfo | v1.63 / v15.2 / v4.0 | Minor refreshes through Dec 2025 – May 2026. |
Linux ports of the Sysinternals family (Sysmon for Linux, ProcMon for Linux, ProcDump for Linux, the new jcd directory navigator) now officially support RHEL 10, Debian 13, and Fedora 43. On Windows, all tools have first-class ARM64 builds — grab the SysinternalsSuite-ARM64.zip bundle for Snapdragon X devices instead of running x64 binaries under emulation.
Refresh your local toolkit:
# Re-download the full suite (x64)
Invoke-WebRequest https://download.sysinternals.com/files/SysinternalsSuite.zip -OutFile $env:TEMP\sys.zip
Expand-Archive $env:TEMP\sys.zip -DestinationPath "C:\Tools\Sysinternals" -Force
Install
The whole suite installs as a single zip from Microsoft or via either of the two major Windows package managers. WinGet is the most maintained channel; Chocolatey ships an equivalent metapackage.
rem WinGet (Windows 10 1809+ / 11) — installs to %ProgramFiles%\Sysinternals
winget install --id Microsoft.Sysinternals.Suite -e
rem Chocolatey — installs to C:\ProgramData\chocolatey\bin
choco install sysinternals -y
rem Scoop — extras bucket
scoop bucket add extras
scoop install sysinternals
rem Live network share (no install, always latest) — open in Explorer
start \\live.sysinternals.com\tools\
Output: (none — exits 0 on success)
The recommended PATH addition after install:
setx PATH "%PATH%;C:\ProgramData\chocolatey\lib\sysinternals\tools" /M
Output:
SUCCESS: Specified value was saved.
Choosing between the tools
The six headless tools below overlap on "what is this process doing" but each owns a specific axis. Pick by question:
| Question | Tool | Why |
|---|---|---|
| Run a command on a remote machine | psexec | Live remote interactive or silent exec |
| Which process has this file open? | handle | Searches handle tables system-wide |
| What handles does PID X own? | handle -p PID | Per-process handle dump |
| Headless replacement for Task Manager | pslist | Plain-text process snapshot with CPU/memory |
| What autostarts at boot/logon? | autorunsc | Enumerates every autostart hook (~50 categories) |
| What files/registry does this process touch? | procmon /BackingFile | Real-time file + registry + network trace |
| Which DLLs are loaded by PID X? | listdlls | Per-process loaded-module list |
Most Sysinternals CLI tools accept
-accepteulaso they never block on the first-run EULA dialog. Add it to every scripted invocation. ProcMon uses the/AcceptEulaform (slash + camel-case).
PsExec — remote and elevated process execution
PsExec launches a process on a local or remote machine. Under the hood it copies a small service binary (psexesvc.exe) to the target's ADMIN$ share, registers and starts it, then proxies stdin/stdout back to the caller. Use it to run interactive shells in the NT AUTHORITY\SYSTEM context, to execute setup scripts across a fleet, or to grab a session in another user's logon — anything that requires "run this over there but pretend it's here".
Syntax
The base form is psexec [\\target] [options] command [args]. Without \\target, PsExec runs locally — the elevated/SYSTEM features still work.
psexec [\\computer[,...] | @file] [-u user [-p pass]] [-s|-e|-h|-i [n]] [-d] [-w dir] cmd [args]
Output: (none — exits 0 on success)
Essential options
| Switch | Meaning |
|---|---|
\\name | Target computer (or \\host1,host2 or @hostlist.txt) |
-u user | Username for the remote logon |
-p pass | Password (omit to prompt; passing on CLI exposes in process list) |
-s | Run as NT AUTHORITY\SYSTEM (local SYSTEM service) |
-i [session] | Interactive — show GUI on the target's console (-i 0 = console session) |
-h | Run elevated (use the High integrity token) |
-e | Don't load the user's profile (faster on remote, no %USERPROFILE%) |
-d | Don't wait — fire-and-forget |
-w dir | Set working directory on the target |
-c | Copy the program to the target first |
-accepteula | Suppress the EULA dialog |
-nobanner | Suppress the copyright banner |
Launch a local SYSTEM shell
The classic "look under the hood" move — opens a cmd.exe running as NT AUTHORITY\SYSTEM rather than your admin account. Useful for poking at services and registry keys protected from administrators.
psexec -s -i -accepteula cmd.exe
Output:
PsExec v2.43 - Execute processes remotely
Copyright (C) 2001-2023 Mark Russinovich
Sysinternals - www.sysinternals.com
(new cmd window opens; running 'whoami' inside it prints:)
nt authority\system
Run a command on a remote machine
The most common everyday use — silent execution of a command on a server without RDP'ing in. The -h switch is important when the target has UAC enabled and you want the elevated token.
psexec \\myhost -u DOMAIN\alicedev -h -accepteula ipconfig /all
Output:
PsExec v2.43 - Execute processes remotely
Copyright (C) 2001-2023 Mark Russinovich
(ipconfig output streamed back)
Windows IP Configuration
Host Name . . . . . . . . . . . . : MYHOST
Primary Dns Suffix . . . . . . . : example.com
...
ipconfig exited on myhost with error code 0.
Run a command across many machines from a host list
PsExec accepts a @file of newline-separated hostnames and parallelises across them. Combine with -d to fire-and-forget for fast fan-out.
rem Roll out a hotfix script silently across the fleet
psexec @hosts.txt -u DOMAIN\alicedev -h -d -c -accepteula C:\scripts\hotfix.cmd
Output:
PsExec v2.43 - Execute processes remotely
...
Started hotfix.cmd on MYHOST with process ID 4521.
Started hotfix.cmd on FILESERVER with process ID 3320.
Started hotfix.cmd on WEB01 with process ID 7710.
Interactive remote GUI launch
-i 0 launches into the console session (session 0 on older Windows, the active user session on modern Windows when combined with -i <session>). Useful for kiosk troubleshooting where you want the GUI to actually appear on a user's screen.
psexec \\myhost -u DOMAIN\alicedev -i 1 -d -accepteula notepad.exe
Output:
notepad.exe started on myhost with process ID 5430.
Common PsExec pitfalls
- AV flags
psexec.exe— Defender and most AV products quarantine the binary as a "hacktool" because of its abuse in pentests. Whitelist it explicitly for sysadmin workstations. ADMIN$share required — the target machine must haveADMIN$reachable; modern domain isolation policies sometimes block it. Test withdir \\target\ADMIN$.- Password on CLI leaks —
-p hunter2shows up in process listings on the source machine. Prefer omitting-pand being prompted, or use-uonly and a saved Windows credential. - PsExec leaves
psexesvc.exerunning on disconnect — if you Ctrl-C aggressively, the service may not get cleaned up. Remove withsc \\target stop psexesvc && sc \\target delete psexesvc.
Handle — find and dump open handles
handle.exe enumerates kernel handles — files, directories, registry keys, mutants, named pipes, sections, processes — and the processes that own them. Its killer feature is the "what has this file open?" query: when an installer says "the file is in use by another process", Handle tells you exactly which PID it is.
Syntax
handle [-a] [-l] [-u] [-c handle [-y]] [-s] [-p PID|name] [name]
handle [-a] [-p PID|name] [filename-fragment]
Output: (none — exits 0 on success)
Essential options
| Switch | Meaning |
|---|---|
-a | All handle types (default is files only) |
-l | List page-file backed sections (pagefile-backed memory) |
-u | Show username owning each handle |
-c | Close a specific handle (dangerous — see pitfall) |
-s | Print a summary count per handle type |
-p | Filter by PID or process name |
-accepteula | Suppress EULA |
Find which process holds a file open
The bread-and-butter query. Pass any substring of the filename — Handle does a case-insensitive match across every file handle in the system.
handle -accepteula myapp.exe.config
Output:
Handle v5.0
Copyright (C) 1997-2022 Mark Russinovich
myapp.exe pid: 7890 type: File 348: C:\Program Files\MyApp\myapp.exe.config
explorer.exe pid: 3456 type: File 9D4: C:\Program Files\MyApp\myapp.exe.config
Per-process handle dump
-p narrows to a specific PID or process name. Combined with -a you get every handle that process owns, not just files.
handle -accepteula -p 7890 -a
Output:
myapp.exe pid: 7890 DOMAIN\alicedev
18: File C:\Program Files\MyApp\myapp.exe
1C: File C:\Windows\System32
20: Key HKLM\SOFTWARE\MyApp
24: Mutant \Sessions\1\BaseNamedObjects\MyAppSingleton
28: Event \Sessions\1\BaseNamedObjects\MyApp.Shutdown
2C: File C:\Users\alicedev\AppData\Local\MyApp\state.db
Summary counts
-s lists every handle type currently in use across the system with a count — a quick health check for handle leaks. A handle count climbing without bound is a classic memory-leak symptom.
handle -accepteula -s -p 7890
Output:
Handle type summary:
ALPC Port : 4
Directory : 3
Event : 76
File : 28
IoCompletion : 12
Key : 19
Mutant : 8
Section : 15
Semaphore : 4
Thread : 23
Token : 3
WindowStation : 1
Total handles: 196
Common Handle pitfalls
-ccan crash applications — closing a handle the owning process still needs typically causes it to crash or hang. Use only as a last resort when restarting the process isn't possible.- Output is a point-in-time snapshot — a process that opens and closes a file in a loop may not show up. Run repeatedly or use ProcMon for continuous tracing.
- Wildcards don't work — Handle does substring matching only;
handle "*.log"matches the literal asterisk, not all log files. Just usehandle .log.
PsList — text-mode Task Manager
pslist.exe is a fast, text-mode equivalent of Task Manager's Details tab. It's faster than tasklist /v and produces output that's easier to parse in scripts — fixed columns, no localisation surprises.
Syntax
pslist [-d] [-m] [-x] [-t] [-s [n]] [-r n] [\\computer] [name|PID]
Output: (none — exits 0 on success)
Essential options
| Switch | Meaning |
|---|---|
-d | Per-thread detail (shows each thread state and CPU time) |
-m | Memory detail (working set, peak, virtual size, paged pool) |
-x | Combined — process + memory + thread |
-t | Tree view (parent-child) |
-s [n] | Sample CPU usage every second for n seconds |
-r n | Refresh every n seconds (live monitor) |
\\computer | Query a remote machine |
Memory snapshot
The default columns are useful but -m gives the most actionable data for a memory-leak triage.
pslist -accepteula -m
Output:
PsList v1.4 - Process information lister
Copyright (C) 2000-2021 Mark Russinovich
Process memory detail for MYHOST:
Name Pid VM WS Priv Priv Pk Faults NonP Page
Idle 0 0 8 0 0 0 0 0
System 4 14620 1440 40 48 43 0 0
smss 412 4448 992 328 376 385 4 4
csrss 680 9024 5124 1632 1768 2120 8 9
chrome 6124 234080 512340 189440 201230 480231 32 42
notepad 8420 65280 23456 8120 9540 18421 8 9
Process tree
-t indents children under parents — invaluable for spotting which process spawned a rogue child. Combine with -s 5 to also see a 5-second CPU sample.
pslist -accepteula -t
Output:
Process Pid Pri Thd Hnd VM WS Priv
Idle 0 0 8 0 0 8 0
System 4 8 195 4920 14620 1440 40
smss 412 11 2 53 4448 992 328
csrss 680 13 11 595 9024 5124 1632
wininit 720 13 1 88 9224 5640 1432
services 812 9 13 580 12880 7240 4320
svchost 960 8 19 680 24580 18420 9430
RuntimeBroker 4521 8 16 380 16240 13340 8420
spoolsv 2580 8 12 410 18880 8460 4920
explorer 3456 8 82 2100 890000 65420 38420
chrome 6124 8 42 1850 234080 512340 189440
chrome 6130 8 18 580 80000 65280 42880
Autoruns CLI (autorunsc) — every autostart hook on the box
autorunsc.exe is the headless sibling of the famous Autoruns GUI. It enumerates every mechanism Windows uses to start something automatically — Run keys, Services, Scheduled Tasks, Winlogon, Print Monitors, Image File Execution Options, Boot Execute, AppInit DLLs, and dozens more. Used in incident response, malware triage, and "why is my laptop so slow at login" debugging.
Syntax
autorunsc [-a *|<categories>] [-c|-ct|-h|-m|-s|-t] [-u] [-f|-x] [-vt] [user]
Output: (none — exits 0 on success)
Essential options
| Switch | Meaning |
|---|---|
-a * | All autostart categories (recommended — use -a then category letters to narrow) |
-c | CSV output |
-ct | Tab-separated output |
-h | Show file hashes (MD5/SHA1/SHA256/IMP) |
-s | Verify digital signatures |
-v | Query VirusTotal — -v rs to skip already-scanned files |
-vt | Submit unknown files to VT (consent flag) |
-u | Hide signed Microsoft entries (focus on third-party) |
-f | Show files-not-found entries (broken autostarts) |
-x | XML output |
-m | Don't show Microsoft entries (alias -u + signed-MS filter) |
user | Target a specific user profile |
A full system snapshot to CSV for triage
The recommended IR command: every category, hashes, signature verification, CSV output for diffing or pivoting in Excel.
autorunsc -accepteula -a * -c -h -s > C:\IR\autoruns_%COMPUTERNAME%_%DATE:~10,4%%DATE:~4,2%%DATE:~7,2%.csv
Output:
(none — file written; CSV header is:)
Time,Entry Location,Entry,Enabled,Category,Profile,Description,Signer,Company,Image Path,Version,Launch String,MD5,SHA-1,PESHA-1,PESHA-256,SHA-256,IMP
Show only suspicious (third-party + unsigned) entries
Cut the signal-to-noise by hiding signed Microsoft entries. This is the first command in many malware triage runbooks.
autorunsc -accepteula -a * -m -s
Output:
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
WeirdApp C:\Users\alicedev\AppData\Local\Temp\wapp.exe
(Not verified) Unknown Publisher
File not signed
Modified: 2026-05-22 02:18
Task Scheduler
\Updater\Reflector
(Not verified)
C:\ProgramData\reflector\update.exe /quiet
Modified: 2026-05-23 14:02
Compare snapshots over time
Save daily snapshots and diff them — any new line is something that just installed itself.
autorunsc -accepteula -a * -c -h -nobanner > today.csv
fc /n yesterday.csv today.csv
Output:
Comparing files YESTERDAY.CSV and TODAY.CSV
***** YESTERDAY.CSV
312: HKCU\...\Run,GoodApp,Enabled,Logon,...
***** TODAY.CSV
312: HKCU\...\Run,GoodApp,Enabled,Logon,...
313: HKCU\...\Run,WeirdApp,Enabled,Logon,...
*****
Autoruns category codes
When you don't need all 50 categories, narrow with letter codes:
| Code | Category |
|---|---|
b | Boot execute |
d | Appinit DLLs |
e | Explorer add-ons |
g | Sidebar gadgets |
h | Image hijacks (IFEO) |
i | Internet Explorer add-ons |
k | Known DLLs |
l | Logon entries (Run/RunOnce/RunOnceEx, Userinit, Shell) |
m | WMI providers |
n | Winsock providers |
o | Codecs |
p | Printer monitor DLLs |
r | LSA providers |
s | Services |
t | Scheduled tasks |
w | Winlogon entries |
x | Sidebar gadgets |
rem Just logon + services + scheduled tasks
autorunsc -accepteula -a lst -c -h
Output: (CSV with only those 3 categories)
ProcMon — scripted file/registry/network tracing
procmon.exe (Process Monitor) shows every file, registry, network, and process operation a system performs in real-time. Most people know it as a GUI; the CLI mode (/BackingFile, /AcceptEula, /Quiet, /Minimized, /Terminate) makes it scriptable for unattended capture — invaluable for catching what an installer or service does on a customer machine when you can't be there.
Syntax
ProcMon's CLI flags use /Slash rather than -dash, and there is no shortened headless binary — you drive the same procmon.exe (or procmon64.exe) that opens the GUI.
procmon /AcceptEula /Quiet /Minimized /BackingFile <pml> [/LoadConfig <pmc>] [/Runtime <sec>]
procmon /Terminate
Output: (none — exits 0 on success)
Essential options
| Switch | Meaning |
|---|---|
/AcceptEula | Suppress EULA dialog |
/Quiet | Don't show splash screen |
/Minimized | Start minimised |
/BackingFile <pml> | Write events to a .pml log file (must be specified for scripted capture) |
/LoadConfig <pmc> | Load a saved filter set |
/Runtime <sec> | Auto-stop after N seconds |
/Terminate | Stop the currently running ProcMon instance |
/PagingFile <pmb> | Use a paging file for very large captures |
| `/SaveAs <csv | xml>` |
/OpenLog <pml> | Open an existing capture (GUI mode) |
/Profiling | Enable thread-profiling events |
Capture 60 seconds of activity to a file
The minimal scripted capture — write a 60-second trace to a .pml log for later analysis in the ProcMon GUI on your own workstation.
procmon /AcceptEula /Quiet /Minimized /BackingFile C:\Traces\boot.pml /Runtime 60
Output: (none — file C:\Traces\boot.pml is created)
Capture until manually stopped
For longer captures, omit /Runtime and stop with /Terminate from a second prompt or after the repro step.
rem Terminal 1: start capture
procmon /AcceptEula /Quiet /Minimized /BackingFile C:\Traces\repro.pml
rem (run the repro on the same machine)
rem Terminal 2: stop the capture
procmon /Terminate
Output: (none — capture file written)
Boot logging (capture from system start)
/EnableBootLogging writes events that occurred before user logon — the earliest stages of boot. Re-run ProcMon after reboot with /Convert to materialise the boot log.
procmon /AcceptEula /EnableBootLogging
shutdown /r /t 0
rem After reboot, convert the boot log:
procmon /AcceptEula /ConvertBootLog C:\Traces\boot.pml
Output:
(none — file C:\Traces\boot.pml is created)
Convert a .pml to CSV for grep/scripting
ProcMon logs are a binary .pml format. For grep-friendly analysis, convert to CSV.
procmon /OpenLog C:\Traces\repro.pml /SaveAs C:\Traces\repro.csv
Output: (none — CSV file written)
Common ProcMon pitfalls
- Capture files balloon fast — on a busy server, a 60-second capture can be 500 MB+. Always set
/BackingFileto a drive with space, and use saved filters (/LoadConfig) to prefilter at capture time. /Runtimenot honoured if the kernel driver crashes — rare, but if you see no file produced, look at the System event log forPROCMON23errors.- GUI must be installed and run once interactively — first run of
procmon.exewrites per-user settings; on a server you'll see nothing on subsequent silent runs. Pre-warm by RDP'ing in once and clicking "OK" on the EULA, then script with/AcceptEulaafterwards.
ListDLLs — modules loaded by a process
listdlls.exe enumerates DLLs loaded into a process's address space — their name, base address, size, and digital-signature status. Use it to confirm an antivirus DLL is injected into your service, to spot a stale version of a shared library, or to verify a recompiled DLL is being loaded.
Syntax
listdlls [-r] [-u] [-v] [-d dllname] [process | PID]
Output: (none — exits 0 on success)
Essential options
| Switch | Meaning |
|---|---|
-r | Show DLLs that were relocated (loaded at a non-preferred base) |
-u | Only unsigned DLLs (essential for malware triage) |
-v | Verbose — include version info |
-d dllname | Find which processes have loaded a specific DLL |
What's loaded by a PID
listdlls -accepteula -v 7890
Output:
ListDLLs v3.2 - Listing DLLs
myapp.exe pid: 7890
Command line: "C:\Program Files\MyApp\myapp.exe" --quiet
Base Size Version Path
0x00007ff60a000000 0x42000 1.4.2.0 C:\Program Files\MyApp\myapp.exe
Publisher: Acme Software Inc.
Description: MyApp
0x00007ffe1f000000 0x1ed000 10.0.22621.1 C:\Windows\System32\ntdll.dll
Publisher: Microsoft Windows
0x00007ffe1e500000 0xb6000 10.0.22621.1 C:\Windows\System32\KERNEL32.DLL
0x00007ffe1c200000 0x312000 10.0.22621.1 C:\Windows\System32\KERNELBASE.dll
0x00007ffe17000000 0x88000 2.4.0.0 C:\Program Files\MyApp\plugins\authz.dll
Publisher: Acme Software Inc.
Which processes have loaded a specific DLL
-d is the inverse query — useful for "is this AV product hooked into my service?".
listdlls -accepteula -d defender.dll
Output:
explorer.exe pid: 3456
0x00007ffe0a000000 0xc8000 Defender.dll
chrome.exe pid: 6124
0x00007ffe0a000000 0xc8000 Defender.dll
myapp.exe pid: 7890
0x00007ffe0a000000 0xc8000 Defender.dll
Find unsigned DLLs loaded into a process
Critical malware-triage move — an unsigned DLL inside a signed Microsoft process is a strong injection indicator.
listdlls -accepteula -u 7890
Output:
myapp.exe pid: 7890
Base Size Path
0x00000000601f0000 0x42000 C:\Users\alicedev\AppData\Local\Temp\suspicious.dll
Verified: Unsigned
Common pitfalls (across the suite)
- The EULA dialog blocks scripted use — every tool needs
-accepteula(or/AcceptEulafor ProcMon) on first run on a given user account. Pre-set it system-wide by importing the registry:reg add "HKCU\Software\Sysinternals\<ToolName>" /v EulaAccepted /t REG_DWORD /d 1 /f. - Most need elevation — handles owned by other users, services, kernel objects, and protected processes are invisible to a non-elevated prompt. Always run from an elevated cmd or PowerShell.
- AV alarms on the tools themselves — PsExec, PsKill, ProcDump, and Mimikatz-adjacent utilities trip every endpoint product. Maintain an allowlist for admin workstations and never copy these onto a regular user's machine.
- PsTools service residue on remote hosts — interrupted PsExec sessions leave
psexesvc.exerunning on the target. Clean up withsc \\target stop psexesvc && sc \\target delete psexesvconce a week on infrastructure servers. - Tool versions diverge — the WinGet, Chocolatey, and live network share publish at different cadences. If
autorunscis missing a category you expected, you may be on an older build; the live share at\\live.sysinternals.com\tools\is always current. - ProcMon filters are stored per-user — a saved
.pmcfilter file is portable, but the default filters live inHKCU\Software\Sysinternals\Process Monitor. Use/LoadConfigto guarantee deterministic captures across machines.
Real-world recipes
"What has this file open?" — three answers
The single most common Sysinternals question. Handle is the canonical tool, but on modern Windows the in-box openfiles and PowerShell's Get-Process | Where-Object can sometimes substitute.
rem Handle (best)
handle -accepteula -nobanner C:\path\to\locked.dll
rem In-box openfiles (must be enabled first: openfiles /local on, then reboot)
openfiles /query /v | findstr /i "locked.dll"
rem PowerShell — slower, but no extra binary required
Get-Process | Where-Object { $_.Modules.FileName -match 'locked.dll' } | Select-Object Name, Id
Output (Handle):
explorer.exe pid: 3456 type: File 348: C:\path\to\locked.dll
myapp.exe pid: 7890 type: File 9D4: C:\path\to\locked.dll
"Capture every file touched during install"
Use ProcMon to record what an installer does. The /Runtime flag self-terminates so the script can move on.
@echo off
md C:\Traces 2>NUL
procmon /AcceptEula /Quiet /Minimized /BackingFile C:\Traces\install.pml /Runtime 300
start /wait installer.exe /silent
procmon /Terminate
procmon /OpenLog C:\Traces\install.pml /SaveAs C:\Traces\install.csv
echo Trace saved to C:\Traces\install.csv
Output:
Trace saved to C:\Traces\install.csv
"Daily autoruns snapshot, alert on change"
Use autorunsc + fc for a poor-man's HIDS — alert any time a new autostart entry appears.
@echo off
setlocal
set DATEKEY=%DATE:~10,4%%DATE:~4,2%%DATE:~7,2%
set OUT=C:\IR\autoruns_%DATEKEY%.csv
set PREV=C:\IR\autoruns_prev.csv
autorunsc -accepteula -a * -c -h -s -nobanner > "%OUT%"
if exist "%PREV%" (
fc /n "%PREV%" "%OUT%" > C:\IR\diff_%DATEKEY%.txt
findstr /R "^\*\*\*\*\* " C:\IR\diff_%DATEKEY%.txt > NUL
if not errorlevel 1 (
echo Autoruns changed - see C:\IR\diff_%DATEKEY%.txt
)
)
copy /Y "%OUT%" "%PREV%" > NUL
Output:
Autoruns changed - see C:\IR\diff_20260524.txt
"Run a one-off command as SYSTEM"
The local-SYSTEM shell trick — useful for resetting permissions on protected directories or reading TrustedInstaller-owned keys.
psexec -s -i -accepteula reg query "HKLM\SECURITY"
Output:
(SYSTEM-owned subkeys printed; same query as administrator returns "Access is denied.")
HKEY_LOCAL_MACHINE\SECURITY\Cache
HKEY_LOCAL_MACHINE\SECURITY\Policy
HKEY_LOCAL_MACHINE\SECURITY\Policy\Accounts
...
"List every unsigned DLL in every running process"
A wider malware sweep — combine pslist for PIDs and listdlls -u per process. Slow but thorough.
for /f "skip=8 tokens=2" %P in ('pslist -accepteula -nobanner') do (
listdlls -accepteula -u -nobanner %P 2>NUL | findstr /R "Unsigned 0x"
)
Output:
myapp.exe pid: 7890
0x00000000601f0000 0x42000 C:\Users\alicedev\AppData\Local\Temp\suspicious.dll Verified: Unsigned
chrome.exe pid: 6124
0x00000000700a0000 0x18000 C:\Program Files\Acme\plugin.dll Verified: Unsigned
"Push a script to 50 machines and collect output"
PsExec's parallel @file mode with capture redirection.
psexec @servers.txt -u DOMAIN\alicedev -h -accepteula systeminfo > C:\IR\sysinfo_all.txt 2>&1
findstr /B "Host Name" C:\IR\sysinfo_all.txt
Output:
Host Name: MYHOST01
Host Name: MYHOST02
Host Name: MYHOST03
...
Tips
Sysinternals tools are stateless and per-binary — copying just
handle.exeto a target is enough, you don't need the whole suite. Keep a small "field kit" withhandle,procexp,procmon,psexec, andautorunson a USB drive for on-site triage.
ProcMon's binary
.pmlfiles compress at roughly 10:1 with 7-Zip. Always compress before emailing a trace to a colleague — a 500 MB raw log becomes a 50 MB attachment.
The
pspingutility (also Sysinternals) measures TCP/UDP latency much more accurately thanping— useful when troubleshooting application connectivity between hosts where ICMP is blocked.