Skip to content

Instantly share code, notes, and snippets.

@rampageX
Created July 6, 2026 06:12
Show Gist options
  • Select an option

  • Save rampageX/75093d4b52acbf850be7c4c1aa19d238 to your computer and use it in GitHub Desktop.

Select an option

Save rampageX/75093d4b52acbf850be7c4c1aa19d238 to your computer and use it in GitHub Desktop.
Windows 多服务强制重启监控
@echo off
setlocal enabledelayedexpansion
:: ====================================================================
:: 多服务强制重启监控(增强版)
:: 兼容:Windows Server 2008 中文系统
:: 功能:
:: 1. Stop Pending 超时自动强杀
:: 2. 自动识别服务 EXE
:: 3. SYSTEM 权限 taskkill(需 PsExec)
:: ====================================================================
:: ====== 配置服务名列表 ======
set serviceList=Spooler RapService
:: ====== 参数 ======
set maxRetries=3
set retryDelay=10
set stopTimeout=30
set pendingThreshold=10
:: ====== 日志 ======
for %%F in ("%~nx0") do set scriptName=%%~nF
set log=%~dp0%scriptName%.log
call :log "多服务强制重启监控启动"
:: ====== 主循环 ======
for %%S in (%serviceList%) do (
set svcname=%%S
set tryCount=0
call :log ""
call :log "开始处理服务 [!svcname!]"
:retry_loop_%%S
set /a tryCount+=1
call :log "尝试停止服务 [!svcname!]..."
net stop "!svcname!" >> %log% 2>&1
:: ===== 等待停止(增强版)=====
set waitTime=0
set pendingTime=0
:wait_stop_%%S
set state=
for /f "tokens=3 delims=: " %%a in ('sc query "!svcname!" ^| findstr "STATE"') do set state=%%a
if /i "!state!"=="STOPPED" (
call :log "服务 [!svcname!] 成功停止"
goto start_service_%%S
)
if /i "!state!"=="STOP_PENDING" (
set /a pendingTime+=1
) else (
set pendingTime=0
)
set /a waitTime+=1
if !pendingTime! GEQ %pendingThreshold% (
call :log "服务 [!svcname!] 长时间 STOP_PENDING,强制终止"
goto force_kill_%%S
)
if !waitTime! GEQ %stopTimeout% (
call :log "服务 [!svcname!] 停止超时"
goto force_kill_%%S
)
timeout /t 1 /nobreak >nul
goto wait_stop_%%S
:start_service_%%S
call :log "尝试启动服务 [!svcname!]..."
net start "!svcname!" >> %log% 2>&1
timeout /t %retryDelay% /nobreak >nul
set state=
for /f "tokens=3 delims=: " %%a in ('sc query "!svcname!" ^| findstr "STATE"') do set state=%%a
if /i not "!state!"=="RUNNING" (
call :log "服务 [!svcname!] 第 !tryCount! 次启动失败"
if !tryCount! GEQ %maxRetries% (
call :log "服务 [!svcname!] 重启失败超过 %maxRetries% 次,准备重启服务器"
goto reboot_server
) else (
call :log "等待 %retryDelay% 秒后重试..."
timeout /t %retryDelay% /nobreak >nul
goto retry_loop_%%S
)
) else (
call :log "服务 [!svcname!] 启动成功"
)
call :log "服务 [!svcname!] 处理完成"
)
call :log "多服务强制重启监控结束"
goto end
:: ====== 强制杀进程(增强版)======
:force_kill_%%S
call :get_exe_name "!svcname!"
call :log "检测到服务进程名: !exeName!"
:: 杀 PID
for /f "tokens=2 delims=:" %%a in ('sc queryex "!svcname!" ^| findstr "PID"') do set pid=%%a
set pid=!pid: =!
if not "!pid!"=="" (
call :log "SYSTEM 权限 taskkill PID !pid!"
psexec -accepteula -s -d taskkill /PID !pid! /F >> %log% 2>&1
) else (
call :log "未获取到 PID"
)
:: 按 EXE 名兜底
if not "!exeName!"=="" (
call :log "SYSTEM 权限 taskkill !exeName!"
psexec -accepteula -s -d taskkill /IM "!exeName!" /F >> %log% 2>&1
) else (
call :log "未获取 EXE 名"
)
timeout /t 3 /nobreak >nul
goto retry_loop_%%S
:: ====== 获取 EXE 名 ======
:get_exe_name
setlocal enabledelayedexpansion
set exeName=
set fullpath=
for /f "tokens=2,* delims=:" %%a in ('sc qc "%~1" ^| findstr /i "BINARY_PATH_NAME"') do (
set fullpath=%%b
)
if defined fullpath (
set fullpath=!fullpath:~1!
for %%f in ("!fullpath!") do set exeName=%%~nxf
)
endlocal & set exeName=%exeName%
goto :eof
:: ====== 重启服务器 ======
:reboot_server
call :log "等待 30 秒后重启服务器"
echo 30 秒后重启服务器
@rem timeout /t 30 /nobreak >nul
@rem shutdown /r /f /t 0
goto end
:: ====== 日志函数 ======
:log
setlocal enabledelayedexpansion
for /f "tokens=1-2 delims=." %%a in ("%time%") do set logtime=%%a
echo === [%date% !logtime!] %~1 >> %log%
endlocal & goto :eof
:end
endlocal
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment