How to Get the Process ID (PID) of a Service in a Batch Script
A Windows service runs in the background, but it is always hosted inside a standard Windows process (like svchost.exe or a custom application executable). For advanced troubleshooting and performance monitoring, you often need to link a specific service to its host process by finding its Process ID (PID). With the PID, you can then check the process's memory or CPU usage, or forcefully terminate it if it's unresponsive.
This guide will teach you how to get the PID of a running service using the definitive command-line tool for this task: sc.exe (Service Control). You will learn the correct command to query a service's extended information and how to parse the output to capture the PID into a variable for use in your automation scripts.
The Challenge: Linking a Service to a Process
While the services.msc GUI can show you the PID, a script needs a command-line method. The standard tasklist command can show services hosted in svchost.exe (tasklist /svc), but it can be difficult to parse and doesn't work for services running in their own executables. A more direct query is needed.
The Core Command: sc queryex
The sc.exe (Service Control) utility is the primary tool for managing services. The queryex (Query Extended) subcommand provides detailed, real-time information about a service, including its current state and, if it's running, its PID.
Syntax: sc queryex "ServiceName"
"ServiceName": This must be the internal service name, not the longer, user-friendly "Display Name."
Basic Example: Getting the PID for the Windows Update Service
First, we need the internal service name for "Windows Update," which is wuauserv.
C:\> sc queryex wuauserv
The command returns a detailed block of information. The line we care about is the one that starts with PID.
SERVICE_NAME: wuauserv
DISPLAY_NAME: Windows Update
TYPE : 20 WIN32_SHARE_PROCESS
STATE : 4 RUNNING
(STOPPABLE, NOT_PAUSABLE, ACCEPTS_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
PID : 10812
FLAGS :
From this, we can see the PID is 10812.
Parsing the Output with FOR /F to Get the PID
To use this PID in a script, we need to extract that number from the output. We can do this by filtering the output for the "PID" line and then parsing that line.
@ECHO OFF
SET "ServiceName=wuauserv"
SET "ServicePID="
ECHO --- Getting PID for service: %ServiceName% ---
ECHO.
REM 'findstr "PID"' filters the output to only the line containing "PID".
REM 'tokens=2 delims=:' splits that line by the colon. %%P gets the value.
FOR /F "tokens=2 delims=:" %%P IN ('sc queryex %ServiceName% ^| findstr "PID"') DO (
SET "ServicePID=%%P"
)
REM The value from sc has a leading space. This second FOR is a trick to trim it.
FOR /F "tokens=*" %%N IN ("%ServicePID%") DO (
SET "ServicePID=%%N"
)
ECHO The PID for %ServiceName% is: %ServicePID%
An Alternative Method: Using WMIC
The WMIC utility can also get this information, often in a more direct, single-line query.
Command: WMIC SERVICE WHERE "Name='wuauserv'" GET ProcessId
This is an excellent alternative, as it returns only the header and the PID, which can be easier to parse.
Common Pitfalls and How to Solve Them
CRITICAL: Service Name vs. Display Name
This is the number one reason sc commands fail. You must use the short, internal Service Name.
- Display Name: "Print Spooler" (will fail)
- Service Name:
Spooler(will succeed)
Solution: Before running the command, find the correct service name with sc queryex.
sc queryex type=service state=all | findstr /I "Print Spooler"
The Service is Not Running
If the service is stopped, it does not have a Process ID. In this case, the PID field in the sc queryex output will be 0.
Solution: Your script should check for this. An IF statement can test if the captured PID is 0 and report that the service is stopped.
IF "%ServicePID%"=="0" (
ECHO Service is stopped.
) ELSE (
ECHO Service is running with PID: %ServicePID%
)
Practical Example: A "Service Investigator" Script
This script takes a service's display name, finds its PID, and if the service is running, it then uses tasklist to find out how much memory that specific PID is using.
@ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "DisplayName=Windows Update"
SET "ServiceName="
SET "ServicePID="
ECHO --- Service Investigator ---
ECHO Finding details for "%DisplayName%"...
ECHO.
REM --- Step 1: Find the internal Service Name ---
FOR /F "tokens=2 delims=:" %%S IN ('sc queryex type=service state=all ^| findstr /I /C:"DISPLAY_NAME: %DisplayName%"') DO (
FOR /F "tokens=*" %%N IN ("%%S") DO SET "ServiceName=%%N"
)
IF NOT DEFINED ServiceName (ECHO [ERROR] Service not found. & GOTO :End)
ECHO Service Name: !ServiceName!
REM --- Step 2: Get the PID for that service ---
FOR /F "tokens=2 delims=:" %%P IN ('sc queryex !ServiceName! ^| findstr "PID"') DO SET "ServicePID=%%P"
FOR /F "tokens=*" %%N IN ("!ServicePID!") DO SET "ServicePID=%%N"
ECHO PID: !ServicePID!
REM --- Step 3: If PID is not 0, get memory usage ---
IF "!ServicePID!"=="0" (
ECHO Status: The service is stopped.
) ELSE (
ECHO Status: The service is RUNNING.
FOR /F "tokens=4" %%M IN ('tasklist /FI "PID eq !ServicePID!" /NH') DO (
ECHO Memory Usage: %%M K
)
)
:End
ENDLOCAL
Conclusion
The sc queryex command is the standard and most detailed built-in tool for getting the Process ID of a Windows service.
For reliable scripting:
- Always run your script as an Administrator.
- You must use the internal Service Name, not the Display Name. Use
sc queryexto find the correct name first. - Pipe the output to
findstr "PID"to isolate the correct line. - Use a
FOR /Floop to parse the line and capture the PID into a variable. - Remember to handle the case where the PID is
0, which means the service is stopped.