Search code examples
windowsbatch-filebackgroundpid

Is there a way to get the process ID of a console program I've just started in the background?


Suppose I just started the following programs in the background:

START /B CMD /C tomcat.exe
START /B CMD /C tomcat.exe
START /B CMD /C tomcat.exe

and I want to kill the second one. Because they have the same image name, I can't use taskkill to kill them using tomcat.exe or I'll kill more than I want.

What I want is to get the process ID of each when they're kicked off.

My question is: Is there a way to get the process ID of a console program I've just started in the background?


Solution

  • Here's a utility batch function that'll let you spawn a process and have its PID set to a variable. Copypaste this into the bottom of your script, after the final exit /b or goto :EOF so it can only be executed by call. It looks complicated (and truth be told it is perhaps a little more complicated than the current situation requires), but it ought to handle backslashes and quoted arguments if you should ever need to recycle it for future projects.

    :spawn command args
    :: sets %PID% on completion
    setlocal
    set "PID="
    set "return="
    set "args=%*"
    set "args=%args:\=\\%"
    
    for /f "tokens=2 delims==;" %%I in (
        'wmic process call create "%args:"=\"%" ^| find "ProcessId"'
    ) do set "return=%%I"
    
    endlocal & set "PID=%return: =%"
    goto :EOF
    

    If you wmic process call create "ping localhost" from a console, you'll see how this works. Unlike start /b, using wmic process call create to run a new asynchronous process will output the PID of the process as it's started.

    Call the function above like this:

    call :spawn tomcat.exe
    set "instance1=%PID%"
    
    call :spawn tomcat.exe
    set "instance2=%PID%"
    
    call :spawn tomcat.exe
    set "instance3=%PID%"
    
    :: kill the 2nd one:
    taskkill /PID "%instance2%"