Skip to content

Instantly share code, notes, and snippets.

@redneck-f25
Last active June 27, 2019 22:45
Show Gist options
  • Save redneck-f25/5eaaa3c1e175102ddc984c753cdf0311 to your computer and use it in GitHub Desktop.
Save redneck-f25/5eaaa3c1e175102ddc984c753cdf0311 to your computer and use it in GitHub Desktop.
Respawn Windows Console Processes and collect std{out,err} (i.e. for startup-tasks)
@echo off & setlocal enableextensions enabledelayedexpansion
if "%~1" == "" (
set "conf_file=%~dpn0.conf.cmd"
) else (
set "conf_file=%~dp0%~1.conf.cmd"
)
call "%conf_file%" || ( pause & exit 1 )
goto __main__
:log
echo [%DATE% %TIME: =0% %pid%]: %*
goto :eof
:__main__
rem get pid
rem @see https://serverfault.com/questions/126502/how-to-get-own-process-pid-from-the-command-prompt-in-windows/654029#654029
set "uniq=%~f0:%DATE%-%TIME: =0%-%RANDOM%-%RANDOM%" & set "uniq=!uniq:#=#0!" & set "uniq=!uniq::=#1!" & set "uniq=!uniq:,=#2!" & set "uniq=!uniq:/=#3!" & set "uniq=!uniq:\=#4!" & set "uniq=!uniq:`=#5!"
set "lock=%TEMP%\%uniq%.lock"
2>nul ( 4>"%lock%" (
for /f "usebackq skip=1 tokens=1,2" %%a in (
`wmic process where ^( Name^="cmd.exe" and CommandLine like "%%<%uniq%>%%" ^) get ParentProcessId`
) do for %%b in (%%a) do set pid=%%b
)) || goto __main__
del "%lock%" 2>nul
>>"%LOGFILE%.%pid%.tmp" call :log +++ start %~f0 %conf_file%
rem try to terminate other instance of this respawn script and the target program
for /f "usebackq tokens=1" %%a in ( `type "%PIDFILE%" 2^>nul` ) do (
set /a "pcmdpid=%%a+0"
if "!pcmdpid!" neq "0" (
for /f "usebackq skip=1 tokens=1" %%b in ( `wmic process where ^( Name^="cmd.exe" and ParentProcessId^="%%a" ^) get ProcessId 2^>nul` ) do (
set /a "cmdpid=%%b+0"
if "!cmdpid!" neq "0" (
for /f "usebackq skip=1 tokens=1" %%c in ( `wmic process where ^( ExecutablePath^="%PROGRAM:\=\\%" and ParentProcessId^="%%b" ^) get ProcessId 2^>nul` ) do (
set /a "programpid=%%c+0"
if "!programpid!" neq "0" (
>>"%LOGFILE%.%pid%.tmp" call :log Terminate running instance (!pcmdpid!,!programpid!)
rem delete the run-file as signal for the respawn-loop below
del "%RUNFILE%" 2>nul
>>"%LOGFILE%.%pid%.tmp" 2>&1 wmic process where ^( ExecutablePath="%PROGRAM:\=\\%" and ProcessId="!programpid!" ^) call terminate
rem give some time to release the logfile
timeout /t 1 /nobreak >nul
)
)
)
)
)
)
rem terminate other target programs inclusive two cmd-parents (missing pidfile)
for /f "usebackq skip=1 tokens=1,2" %%a in ( `wmic process where ExecutablePath^="%PROGRAM:\=\\%" get ParentProcessId^,ProcessId 2^>nul` ) do (
set /a "otherprogrampid=%%b+0"
if "!otherprogrampid!" neq "0" (
set "cond=ProcessID="!otherprogrampid!""
for /f "usebackq skip=1 tokens=1,2" %%c in ( `wmic process where ^( ProcessId^="%%a" and Name^="cmd.exe" ^) get ParentProcessId^,ProcessId 2^>nul` ) do (
set /a "othercmdpid=%%d+0"
if "!othercmdpid!" neq "0" (
set "cond=!cond! or ProcessID="!othercmdpid!""
for /f "usebackq skip=1 tokens=1" %%e in ( `wmic process where ^( ProcessId^="%%c" and Name^="cmd.exe" ^) get ProcessId 2^>nul` ) do (
set /a "otherpcmdpid=%%e+0"
if "!otherpcmdpid!" neq "0" (
set "cond=!cond! or ProcessID="!otherpcmdpid!""
)
)
)
)
>>"%LOGFILE%.%pid%.tmp" call :log Terminate running instances (!otherpcmdpid!,!otherprogrampid!)
>>"%LOGFILE%.%pid%.tmp" 2>&1 wmic process where ^( !cond! ^) call terminate
)
)
>"%RUNFILE%" <nul set /p "_="
rem fails if log-file is still open (other user context, missing permissins)
type "%LOGFILE%.%pid%.tmp" >>"%LOGFILE%" || ( pause & exit 1 )
del "%LOGFILE%.%pid%.tmp"
>"%PIDFILE%" echo\%pid%
:loop
>>"%LOGFILE%" call :log spawn "%PROGRAM%" %ARGS%
start "" /wait cmd /c ""%PROGRAM%" %ARGS% >>"%LOGFILE%" 2>&1"
>>"%LOGFILE%" call :log terminated with exitcode %ERRORLEVEL%
rem if pid-file exists and still contains current pid, respawn after timeout
if exist "%RUNFILE%" (
for /f "usebackq" %%a in ( `type "%PIDFILE%" 2^>nul` ) do (
if "%%a" == "%pid%" (
timeout /t %RESPAWN_DELAY% /nobreak >nul
goto loop
)
)
)
del "%PIDFILE%" 2>nul
>>"%LOGFILE%" call :log === exit %~f0 %conf_file%
@echo off & setlocal enableextensions enabledelayedexpansion
if "%~1" == "" (
set "conf_file=%~dp0respawn.conf.cmd"
) else (
set "conf_file=%~dp0respawn-%~1.conf.cmd"
)
call "%conf_file%" || ( pause & exit 1 )
for /f "usebackq tokens=1" %%a in ( `type "%PIDFILE%" 2^>nul` ) do (
set /a "pcmdpid=%%a+0"
if "!pcmdpid!" neq "0" (
for /f "usebackq skip=1 tokens=1" %%b in ( `wmic process where ^( Name^="cmd.exe" and ParentProcessId^="%%a" ^) get ProcessId` ) do (
set /a "cmdpid=%%b+0"
if "!cmdpid!" neq "0" (
for /f "usebackq skip=1 tokens=1" %%c in ( `wmic process where ^( ExecutablePath^="%PROGRAM:\=\\%" and ParentProcessId^="%%b" ^) get ProcessId` ) do (
set /a "programpid=%%c+0"
if "!programpid!" neq "0" (
del "%RUNFILE%"
wmic process where ^( ExecutablePath="%PROGRAM:\=\\%" and ProcessId="!programpid!" ^) call terminate
)
)
)
)
)
)
@"%~dp0_respawn.cmd" "%~n0"
set "PROGRAM=C:\Windows\system32\PING.EXE"
set "ARGS=-t localhost"
set "LOGFILE=%~dp0respawn-ping.log"
set "PIDFILE=%~dp0respawn-ping.pid"
set "RUNFILE=%~dp0respawn-ping.run"
set "RESPAWN_DELAY=5"
@"%~dp0_terminate.cmd" "ping"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment