Running Processes - Paths - Hashes (Sensor)
A Tanium sensor that lists the full path of every program running on each endpoint, with an optional MD5, SHA1, or SHA256 hash of the file. One sensor covers Windows and Linux.
It does the same job as the Running Processes with MD5 Hash sensor from Incident Response content, without needing Incident Response tools on the endpoint. See Compared with built-in content.
What it returns: one row per unique running executable, with its path and hash. A program running ten times on a machine appears once.
Use cases
Checking whether an old runtime is actually in use before removing it. Installed Applications shows that Java 6, an old .NET runtime, or an old Python is installed. It doesn't show whether anything is running it. Ask this sensor with a path filter, such as \jre6\ for Java 6, across every machine that has it installed. Machines that return nothing for that path had no process running from it when you asked. It is a point-in-time check, so combine it with Java - Last Run - Prefetch and Java - Scheduled Tasks for Java, and get the application owner's sign-off before removing anything from a server.
Sweeping the fleet for a known-bad file. A security advisory or threat report gives you a SHA256 for a malicious or vulnerable binary. Filter on that hash to find every machine running it right now, whatever the file is named and wherever it was copied.
Finding software that runs from user folders. Programs running from \AppData\, \Downloads\, \Temp\, or C:\ProgramData\ were usually installed per user, outside your software deployment process. Per-user installs don't show up in machine-wide Installed Applications, and they don't get patched. The Remove Zoom User Install and Remove VS Code User Install packages handle two common cases.
Spotting version drift or a replaced binary. Ask without Computer Name, filtered to one path. Each unique hash becomes its own row, and Count shows how many machines have it. One path with several hashes means machines are on different versions of that program, or one copy was replaced. A hash that appears on only one or two machines is the one to look at first.
Finding remote access tools. Filter on the program names your organization does not approve, such as TeamViewer, AnyDesk, or ScreenConnect. The path shows whether each one is a machine-wide install or a copy running from a user folder.
Finding Linux services still running a replaced binary. When a package upgrade replaces a program while it is running, Linux reports the path with (deleted) at the end. The service is still running the old version until it restarts. Filter on (deleted) after a patch cycle to find services that need a restart. This only covers the program file itself. A service that still has an old shared library loaded, such as OpenSSL after an update, keeps its normal path and does not show up here.
Building an application allowlist. Before writing allow rules for an application control tool, collect the SHA256 of every program that actually runs on a group of machines. That is a better starting list than a scan of every executable on disk.
Confirming a remediation worked. After an uninstall or upgrade, ask again with the old path or hash. If it still shows, the old program is still running and the machine needs a restart, or the remediation did not apply.
When not to use it
- You need the command line, user, process ID, parent process, or start time. This sensor returns only the path and hash. Command lines often hold passwords, so they are left out on purpose.
- You need to know what ran in the past. It only sees what is running at the moment the question is asked. On Windows, Prefetch shows what ran recently. See Java - Last Run - Prefetch for the Java version.
- The tenant has Incident Response or Threat Response tools on every endpoint. The built-in sensor already works there.
What it returns
Sample results from one Windows workstation, with hashes shortened:
| Path | Hash |
|---|---|
C:\Program Files (x86)\Google\Chrome\Application\chrome.exe |
645d9a01... |
C:\Program Files (x86)\TeamViewer\TeamViewer_Service.exe |
1b3b4498... |
C:\WINDOWS\Explorer.EXE |
967bca06... |
C:\WINDOWS\system32\lsass.exe |
fd9b7c6b... |
C:\WINDOWS\system32\svchost.exe |
d122d210... |
C:\Program Files\Microsoft OneDrive\OneDrive.exe |
67e33a15... |
With NONE, the Hash column is empty and the sensor returns faster.
Output columns
| Column | Type | Contents |
|---|---|---|
| Path | Text | Full path of the running program, in the case Windows recorded it (C:\WINDOWS\system32\... and C:\Windows\System32\... both occur). On Linux, the path as the process sees it. |
| Hash | Text | Lowercase hex hash of the file, using the algorithm chosen in HashType. Empty when HashType is NONE or the file could not be hashed. |
Status results
These appear in the Path column with the Hash column empty.
| Result | Meaning |
|---|---|
Error hashing <path>: <reason> |
That one file could not be hashed. The other rows are still returned. |
Error: Unsupported HashType '<value>'... |
The parameter value was not MD5, SHA1, SHA256, or NONE. |
Error: Unable to query Win32_Process: <reason> |
WMI did not answer on that Windows machine. |
Error: md5sum not found on this endpoint. |
Linux endpoint without the coreutils hash tool for the chosen algorithm. |
N/A |
A platform with no script, such as macOS. |
How it works
Windows
- Reads every running process from WMI (
Win32_Process) and keeps the unique executable paths. WMI returns full paths for both 32-bit and 64-bit processes. - Opens each file read-only, with sharing set so files in use and files marked for deletion can still be read, and hashes it with the .NET hash classes.
- Skips the hash for files over 1 GB.
Why the Sysnative mapping matters. The Tanium Client is a 32-bit program on most installs (C:\Program Files (x86)\Tanium\Tanium Client), so the sensor runs in 32-bit PowerShell. Windows quietly redirects a 32-bit program's reads from C:\Windows\System32 to C:\Windows\SysWOW64. Without a fix, two things go wrong:
- Files that exist only as 64-bit, such as
dwm.exe,lsass.exe, andwinlogon.exe, returnCannot find path ... because it does not exist. - Files that exist in both folders, such as
svchost.exe, return the hash of the 32-bit copy, not the file that is running. On one test machine the first version returnedc3c6de0c...forsvchost.exe. The fixed version returnedd122d210..., which is the real 64-bit file.
The script detects 32-bit PowerShell on 64-bit Windows and reads System32 files through C:\Windows\Sysnative, which bypasses the redirection. The Path column still shows the real System32 path. DriverStore paths were never affected, because Windows excludes that folder from redirection.
Linux
- Lists every process in
/procand reads the/proc/<pid>/exelink to get the program path. Kernel threads have no program file and are skipped. - Hashes
/proc/<pid>/exeitself, not the path it points to. That link always opens the file the process is actually running, so a binary that was replaced or deleted after the process started still hashes correctly, and so does a process inside a container. - Uses
md5sum,sha1sum, orsha256sumfrom coreutils.
Parameters
| Key | Label | Type | Values | Default |
|---|---|---|---|---|
HashType |
Hash Type | Drop-down list | MD5, SHA1, SHA256, NONE |
MD5 |
NONEreturns paths only. Use it when you only care which programs are running. It is much faster because no files are read.SHA256is the one to use for threat intelligence lookups, since most advisories publish SHA256.- MD5 on FIPS-enforced Windows machines. When the Windows FIPS policy is enforced, .NET may refuse MD5 and every file returns an
Error hashingrow. UseSHA256on those machines. The Linux script is not affected.
Each parameter value is cached separately, so [MD5] and [NONE] each keep their own result for the Max Sensor Age.
Requirements
- Windows: PowerShell 5.1. Works under both 32-bit and 64-bit Tanium Clients.
- Linux:
sh,readlink,stat,sort,awk, and the coreutils hash tools. These are present on standard installs. - No Python, Tanium Python modules, or Incident Response tools.
- A Tanium account with permission to create sensors.
Create the sensor
Step 1: Open a new sensor
On the Tanium Console:
- Sign in to the Tanium Console.
- Open the main menu, then go to Administration > Content > Sensors.
- Click Create Sensor.
Step 2: Details section
| Field | Value |
|---|---|
| Name | Running Processes - Paths - Hashes |
| Description | Returns the full executable path of each running process, with an optional file hash. Windows (PowerShell) and Linux (shell). Does not require Incident Response or Threat Response tools. Parameter HashType accepts MD5, SHA1, SHA256, or NONE (default MD5). Use NONE for path-only results, which is faster. Files over 1 GB are not hashed. On FIPS-enforced Windows hosts MD5 returns an error; use SHA256 instead. On Linux, paths ending in "(deleted)" mean the binary was replaced or removed while the process was running. Output columns: Path, Hash. |
| Content Set | Your own custom content set, restricted to your endpoint team |
Step 3: Settings section
| Field | Value |
|---|---|
| Category | Processes (or any category you use for custom sensors) |
| Result Type | Text |
| Max Sensor Age | 10 and set the unit dropdown to Minutes. Running processes change quickly |
| Max String Age | Leave Enable unchecked |
| Max Strings | Leave Enable unchecked |
| Ignore case in result values | Checked |
| Hide this sensor from sensor lists and parse results | Unchecked |
| Split into multiple columns | Checked |
Step 4: Column settings
- Set Delimiter to
|#. - Add these 2 columns in this order.
| Index | Column Name | Value Type | Ignore case | Hidden |
|---|---|---|---|---|
| 0 | Path | Text | Checked | Unchecked |
| 1 | Hash | Text | Checked | Unchecked |
Why |# and not |
The other sensors on this site use |. This one uses |#, the same delimiter as the Incident Response sensor it replaces, so saved questions and reports built on that sensor's output keep working. It also avoids splitting a Linux path, which can legally contain |.
Step 5: Parameters section
- Click Add Parameter and choose Drop-Down List.
- Set Key to
HashType. It must match the||HashType||placeholder in the scripts exactly, including capitalization. - Set Label to
Hash Type. - Add the values
MD5,SHA1,SHA256, andNONE. - Set the default value to
MD5.
Step 6: Scripts section
| Platform | Enable | Query Type | Script |
|---|---|---|---|
| Windows | Checked | PowerShell | Windows script below |
| Linux | Checked | UnixShell | Linux script below |
| Mac | Checked | UnixShell | Stub below, returns N/A |
| Solaris | Checked | UnixShell | Stub below, returns N/A |
| AIX | Checked | UnixShell | Stub below, returns N/A |
Copy each script with the copy button on its code block so nothing is changed.
# Running Processes - Paths - Hashes (Windows)
# Pure PowerShell. No Python or Incident Response tools required.
# Output: <executable path>|#<hash> (hash empty when HashType = NONE)
# When running as 32-bit on 64-bit Windows, System32 reads go through Sysnative
# so the real 64-bit file is hashed, not the SysWOW64 copy.
$ErrorActionPreference = 'SilentlyContinue'
$sep = '|#'
$maxBytes = 1GB
# Parameter (Tanium URL-encodes parameter values)
$hashType = [uri]::UnescapeDataString('||HashType||')
if ([string]::IsNullOrWhiteSpace($hashType) -or $hashType -like '*HashType*') { $hashType = 'MD5' }
$hashType = $hashType.Trim().ToUpper()
if (@('MD5','SHA1','SHA256','NONE') -notcontains $hashType) {
Write-Output "Error: Unsupported HashType '$hashType'. Use MD5, SHA1, SHA256, or NONE."
exit
}
# WOW64 redirection handling
$is32on64 = [bool]$env:PROCESSOR_ARCHITEW6432
$sys32 = Join-Path $env:windir 'System32'
$sysnative = Join-Path $env:windir 'Sysnative'
function Get-ReadPath {
param([string]$Path)
if ($is32on64 -and $Path.StartsWith($sys32, [System.StringComparison]::OrdinalIgnoreCase)) {
return $sysnative + $Path.Substring($sys32.Length)
}
return $Path
}
function Get-FileHashSafe {
param([string]$Path, [string]$Algorithm)
$algo = [System.Security.Cryptography.HashAlgorithm]::Create($Algorithm)
$fs = [System.IO.File]::Open($Path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::Read, [System.IO.FileShare]'ReadWrite, Delete')
try {
([System.BitConverter]::ToString($algo.ComputeHash($fs))).Replace('-', '').ToLower()
}
finally {
$fs.Dispose()
$algo.Dispose()
}
}
try {
$procs = Get-CimInstance -ClassName Win32_Process -ErrorAction Stop
}
catch {
try { $procs = Get-WmiObject -Class Win32_Process -ErrorAction Stop }
catch {
Write-Output "Error: Unable to query Win32_Process: $($_.Exception.Message)"
exit
}
}
$paths = $procs |
Where-Object { $_.ExecutablePath } |
Select-Object -ExpandProperty ExecutablePath |
Sort-Object -Unique
foreach ($p in $paths) {
if ($hashType -eq 'NONE') {
Write-Output "$p$sep"
continue
}
try {
$readPath = Get-ReadPath -Path $p
$item = Get-Item -LiteralPath $readPath -ErrorAction Stop
if ($item.Length -gt $maxBytes) {
Write-Output "Error hashing ${p}: file exceeds 1 GB"
continue
}
$h = Get-FileHashSafe -Path $readPath -Algorithm $hashType
Write-Output "$p$sep$h"
}
catch {
Write-Output "Error hashing ${p}: $($_.Exception.Message)"
}
}
#!/bin/sh
# Running Processes - Paths - Hashes (Linux)
# POSIX sh. No Python or Incident Response tools required.
# Output: <executable path>|#<hash> (hash empty when HashType = NONE)
# Hash is computed from /proc/<pid>/exe, so deleted or replaced binaries
# and container processes hash the file actually running.
SEP='|#'
MAX_BYTES=1073741824
TAB=$(printf '\t')
HASH_TYPE='||HashType||'
case "$HASH_TYPE" in
*HashType*|'') HASH_TYPE='MD5' ;;
esac
HASH_TYPE=$(printf '%s' "$HASH_TYPE" | tr '[:lower:]' '[:upper:]' | tr -d ' ')
case "$HASH_TYPE" in
MD5) HASH_CMD='md5sum' ;;
SHA1) HASH_CMD='sha1sum' ;;
SHA256) HASH_CMD='sha256sum' ;;
NONE) HASH_CMD='' ;;
*)
echo "Error: Unsupported HashType '$HASH_TYPE'. Use MD5, SHA1, SHA256, or NONE."
exit 0
;;
esac
if [ -n "$HASH_CMD" ] && ! command -v "$HASH_CMD" >/dev/null 2>&1; then
echo "Error: $HASH_CMD not found on this endpoint."
exit 0
fi
for d in /proc/[0-9]*; do
pid=${d#/proc/}
exe=$(readlink "$d/exe" 2>/dev/null) || continue # kernel threads have no exe
[ -n "$exe" ] || continue
printf '%s\t%s\n' "$exe" "$pid"
done | sort -t "$TAB" -k1,1 -u | while IFS="$TAB" read -r exe pid; do
if [ -z "$HASH_CMD" ]; then
printf '%s%s\n' "$exe" "$SEP"
continue
fi
src="/proc/$pid/exe"
size=$(stat -L -c %s "$src" 2>/dev/null)
if [ -z "$size" ]; then
echo "Error hashing $exe: process exited or file unreadable"
continue
fi
if [ "$size" -gt "$MAX_BYTES" ]; then
echo "Error hashing $exe: file exceeds 1 GB"
continue
fi
h=$($HASH_CMD < "$src" 2>/dev/null | awk '{print $1}')
if [ -n "$h" ]; then
printf '%s%s%s\n' "$exe" "$SEP" "$h"
else
echo "Error hashing $exe: unable to read file"
fi
done
Step 7: Save
Scroll to the bottom of the page and click Save.
Step 8: Test
On the Tanium Console, in Interact:
-
Test one Windows machine with both code paths. Replace
<windows-host>with a real computer name. -
In the MD5 result, check that
C:\Windows\System32\lsass.exeanddwm.exehave hashes.Error hashing ... does not existon System32 files means an older copy of the script without the Sysnative fix was pasted. -
Repeat on one Linux machine:
Ask a question
Is anything running from a specific folder? Example for Java 6:
Get Computer Name and Running Processes - Paths - Hashes[NONE] from all machines with Running Processes - Paths - Hashes[NONE]:Path contains "\jre6\"
Which machines are running a known file?
Get Computer Name and Running Processes - Paths - Hashes[SHA256] from all machines with Running Processes - Paths - Hashes[SHA256]:Hash equals "<sha256>"
What runs from user folders?
Get Computer Name and Running Processes - Paths - Hashes[NONE] from all machines with Running Processes - Paths - Hashes[NONE]:Path contains "\AppData\"
Repeat with \Downloads\ and \Temp\.
How many versions of one program are running across the fleet?
Get Running Processes - Paths - Hashes[SHA256] from all machines with Running Processes - Paths - Hashes[SHA256]:Path contains "\Microsoft\Edge\Application\msedge.exe"
Without Computer Name, each unique path and hash pair is one row, and Count shows how many machines have it.
Which Linux services need a restart after patching?
Get Computer Name and Running Processes - Paths - Hashes[NONE] from all machines with Running Processes - Paths - Hashes[NONE]:Path contains "(deleted)"
Tanium Comply runs its own Java
During a Comply scan, C:\Program Files (x86)\Tanium\Tanium Client\extensions\comply\jre\bin\java.exe appears in the results. It is the private Java runtime Comply uses for its scanner. It is not the system Java and doesn't depend on it, and it goes away when the scan finishes. A filter such as Path contains "jre" will catch it, so filter on the specific folder instead (\jre6\, \jre1.8, \jdk-11). Never include it in a cleanup.
Troubleshooting
| What you see | Likely cause | What to do |
|---|---|---|
Error hashing C:\Windows\System32\...: Cannot find path ... because it does not exist on many rows |
An older copy of the Windows script without the Sysnative fix | Edit the sensor and paste the Windows script from this page again. |
Error hashing on every file with MD5, but SHA256 works |
Windows FIPS policy is enforced | Use SHA256 on those machines. |
Error: Unsupported HashType |
The parameter value was typed instead of picked, or the drop-down list values were changed | Check Step 5. |
Error: Unable to query Win32_Process |
WMI is broken on that machine | Repair WMI on that machine, then ask again. |
Error: <tool> not found on this endpoint. |
Minimal Linux install | Install coreutils, or use NONE. |
Error locating necessary files. Ensure Incident Response Tools are deployed. Error was: No module named 'taniumlib' |
That is the Incident Response sensor, not this one | Use this sensor, and disable the imported one so nobody else hits the same error. |
TSE-Error: Sensor evaluation timed out |
Hashing took too long, usually on a busy server with many large programs | Ask with NONE, or target fewer machines. |
N/A |
macOS, Solaris, or AIX | Not supported on those platforms. |
| A program you expected is missing | It wasn't running when the question was asked, or the result is cached | Ask again after the Max Sensor Age (10 minutes). |
Compared with built-in content
| Running Processes (core) | Running Processes with MD5 Hash (Incident Response) | This sensor | |
|---|---|---|---|
| Full path | No, names only | Yes | Yes |
| Hash | No | MD5, SHA1, SHA256 | MD5, SHA1, SHA256, or none |
| Dependencies | None | Tanium Python and Incident Response tools. Without them it returns Error locating necessary files |
None. PowerShell 5.1, or sh and coreutils |
| Platforms | Windows, Linux, macOS | Windows, Linux, macOS | Windows, Linux |
Limits
- Point in time. A program that runs on a schedule or a few times a month only shows up if it is running when the question is asked.
- No command lines, users, process IDs, or start times. Path and hash only.
- Protected processes are skipped on Windows.
System,Registry, and some security agents return no path to WMI, even forSYSTEM. - Files over 1 GB are listed without a hash.
- No internal time limit. Unlike the other sensors on this site, the script does not stop itself before the sensor timeout. On a machine with hundreds of large programs, hashing can run long. Use
NONEif that happens. - Container processes on Linux show the path as the container sees it, for example
/usr/bin/python3inside the container, not the host path. The hash is still correct. - macOS is not covered. macOS has no
/proc.