如何杀死所有 cmd.exe除了当前从批处理运行的那个



在过去的几天里,我一直在写一个脚本,我认为这很容易,但似乎并非如此,我确实明白为什么。我的问题是如何绕过它。

我需要的批处理脚本解释:

我有一个在cmd中运行的脚本.exe它可以做很多事情,例如将大量文件从一个位置移动到另一个位置。让我们称之为 movefile.cmd .这个脚本有效,但有时会停止(很少 - 让我们不讨论为什么和那个脚本(。此脚本始终运行很重要,因此我的想法是创建一个退出cmd的批处理.exe然后每小时左右重新打开脚本。让我们将此脚本称为restartcmd.bat

听起来非常简单,因为我可以做到这一点:

@echo off
:loop
start c:scriptmovefile.cmd 
Timeout /nobreak /t 3600
Taskkill cmd.exe
goto loop

但显然这不起作用,因为我的新脚本也在 cmd.exe 中运行,所以它也会杀死这个过程。

我尝试过:

所以我做了一个cmd的副本.exe并将其重命名为dontkillthis.exe。我运行 dontkillthis.exe然后从 dontkillthis 打开 restardcmd.bat.exe - 这非常有效!但是我需要能够只是点击我的脚本而不是那样做。为什么?因为它应该尽可能简单,我希望我的 restartcmd.bat 在我的启动文件夹中。

我一直在研究获取cmd的确切进程ID的想法.exe并关闭它,以便我的dontkillthis.exe将保留下来,但我似乎无法确定它。尝试了这里写的所有内容,如何杀死除当前正在运行的文件之外的所有批处理文件,但我无法让它工作。

我不确定我是否感到困惑,或者这样做实际上有点困难。

我真的很感激这里的一些帮助。

此致敬意

首先,您需要当前CMD实例的PID。该主题已在此处讨论。我会给你我的解决方案 - getCmdPID.bat

这是脚本(getCmdPID应该在同一目录中(:

@echo off
call getCmdPID
set "current_pid=%errorlevel%"
for /f "skip=3 tokens=2 delims= " %%a in ('tasklist /fi "imagename eq cmd.exe"') do (
    if "%%a" neq "%current_pid%" (
        TASKKILL /PID %%a /f >nul 2>nul
    )
)

通常使用以下命令,我应该能够找到PID。不幸的是,情况并非如此。

title exclude &tasklist /NH /v /fo csv /FI "WINDOWTITLE ne exclude*" /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running"

因此,为了实现我的目标,我使用了以下命令: FIND /I "exclude" 1>NUL

@echo off
TITLE exclude
(for /f "usebackq  tokens=*" %%a in (`tasklist /NH /v /fo csv /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running"`) do (
  (
    echo %%a | FIND /I "exclude" 1>NUL
  ) || ( 
    for /f "usebackq tokens=2 delims=," %%i in (`echo %%a`) do (
      echo TASKKILL /PID %%~i /f
    )
  )
)
)>_output-taskill.txt
TYPE _output-taskill.txt

在一行中终止所有进程的另一种方法是在命令上使用过滤器taskkill过滤器应如下所示:

TASKKILL /F /FI "PID ne XXXX" /FI "IMAGENAME eq cmd.exe" /IM cmd.exe

均衡器(等于(

ne(不等于(

GT(大于(

LT(小于(

@echo off
TITLE exclude
(for /f "usebackq tokens=2 delims=," %%a in (`tasklist /NH /v /fo csv /FI "IMAGENAME eq cmd.exe" /FI "STATUS eq running" ^| FIND /I "exclude"`) do (
    echo TASKKILL /F /FI "PID ne %%~a" /FI "IMAGENAME eq cmd.exe" /IM cmd.exe
  )
)>_output-taskill.txt
TYPE _output-taskill.txt

我找到了一个解决方案,它利用文本文件来跟踪蝙蝠文件之前的所有PID。它尝试以静默方式杀死它们,然后将当前 PID 添加到列表中。

如果您不希望它杀死旧的,已经存在的进程,只需将带有"taskkill"的行替换为您想要用它执行的任何操作。

(可能需要以管理员身份运行才能获得终止重复进程的权限。 如果不想每次都以管理员身份运行,请参阅下面的权限提升代码了解可选实现。

@echo off
set WorkingDir=%cd% 
if exist MostRecentPID.txt ( del "PIDinfo.txt"  /f /q ) > nul
cd ..............
title mycmd
tasklist /v /fo csv | findstr /i "mycmd" > %WorkingDir%PIDinfo.txt
set /p PIDinfo=<%WorkingDir%PIDinfo.txt
REM below, the 11 means get substring starting a position 11 with length of 5 characters. The tasklist command gives a long and verbose value so this will get just the PID part of the string.
set PID5chars=%PIDinfo:~11,5%
set PID4chars=%PIDinfo:~11,4%
if exist PreviousPIDs.txt (
    for /F "tokens=*" %%A in (PreviousPIDs.txt) do taskkill.exe /F /T /PID %%A > nul 2>&1
    goto CheckIfFourCharPID
)
:CheckIfFourCharPID
if %PID4chars% gtr 8100 (
    for /F "tokens=*" %%A in (PreviousPIDs.txt) do taskkill.exe /F /T /PID %%A > nul 2>&1
    echo %PID4chars% >> "PreviousPIDs.txt"
) else (
    echo %PID5chars% >> "PreviousPIDs.txt"
)

说明:(警告:非常技术性(

-此解决方案获取任务列表命令的子字符串以仅获取PID。cmd 不会有大于 18100 的 PID.exe因此请检查 PID4chars 是否大于 8100,以便我们知道它是 4 位还是 5 位数字

情况 1:像 17504 这样的 5 位 PID 具有 PID5chars 值 17504 和 PID4chars 值 1750,因此我们将 PID5char 添加到 PID 的文本文件中以杀死

情况 2:像 8205 这样的 4 位 PID 的 PID5chars 值为 8205",PID4chars 值为 8205,因此我们将 PID4char 添加到 PID 的文本文件中以杀死

情况 3:像 4352 这样的 4 位 PID 的 PID5chars 值为 4352",PID4chars 值为 4352,因此我们将 PID4char 添加到 PID 的文本文件中以杀死


可选权限提升代码

(将其放在 BAT 文件的顶部,它将以管理员身份自动运行它。

    @echo off
    setlocal DisableDelayedExpansion
    set "batchPath=%~0"
    for %%k in (%0) do set batchName=%%~nk
    cd ................
    if exist %cd%Temp (
    set temp=%cd%Temp
    goto vbsGetPrivileges
    )
    if exist %cd%WindowsTemp (
    set temp=%cd%WindowsTemp
    goto vbsGetPrivileges
    )
    set temp=%cd%
    :vbsGetPrivileges
    set "vbsGetPrivileges=%temp%OEgetPriv_%batchName%.vbs"
    setlocal EnableDelayedExpansion
    :CheckIfRunningAsAdmin
    net session >nul 2>&1
    if %ERRORLEVEL% == 0 ( 
        goto gotPrivileges 
    ) else ( goto ElevatePermissions )
    :ElevatePermissions
    if '%1'=='ELEV' (echo ELEV & shift /1 & goto gotPrivileges)
    ECHO Set UAC = CreateObject^("Shell.Application"^) > "%vbsGetPrivileges%"
    ECHO args = "ELEV " >> "%vbsGetPrivileges%"
    ECHO For Each strArg in WScript.Arguments >> "%vbsGetPrivileges%"
    ECHO args = args ^& strArg ^& " "  >> "%vbsGetPrivileges%"
    ECHO Next >> "%vbsGetPrivileges%"
    ECHO UAC.ShellExecute "!batchPath!", args, "", "runas", 1 >> "%vbsGetPrivileges%"
    "%SystemRoot%System32WScript.exe" "%vbsGetPrivileges%" %*
    exit /B
    :gotPrivileges
    setlocal & pushd .
    cd /d %~dp0
    if '%1'=='ELEV' (del "%vbsGetPrivileges%" 1>nul 2>nul  &  shift /1)
    net session >nul 2>&1
    if %ERRORLEVEL% == 0 (
        goto Continue
    ) else (
        REM unable to elevate permissions so tell user to run file as admin manually
        echo Please re-run this file as administrator. Press any key to exit...
        pause > nul
        goto Exit
     )
    :Continue
    <insert rest of code here>

最好获得movefile.cmd的 PID。如果可以编辑它,请添加一个title MyMoveFileProcess并获取它的 PID

for /f "tokens=2" %%i in ('tasklist /v ^|find "MyMoveFileProcess"') do set PID=%%i

然后你可以用taskkill /pid %pid%杀死它

与其更改movefile.cmd,您还可以以标题开头:

start "MyMoveFileProcess" c:scriptmovefile.cmd 

几行将帮助您实现此目的:

TITLE exclude
taskkill /IM cmd.exe /FI "WINDOWTITLE ne exclude*"

最新更新