Comment vérifier si un processus s'exécute via un script batch

260

Comment puis-je vérifier si une application s'exécute à partir d'un fichier batch (bien cmd)?

Je n'ai pas besoin de lancer une autre instance si un programme est déjà en cours d'exécution. (Je ne peux pas changer l'application pour en faire une seule instance.)

L'application peut également être exécutée en tant que n'importe quel utilisateur.

Matt Lacey
la source
Copie
12
double d'une question posée cinq ans plus tard?
Matt Lacey
@ LưuVĩnhPhúc ils ne sont même pas relativement proches.
Cardinal - Rétablir Monica du
@JackKirby qui a dit que ce n'était pas lié?
phuclv
3
@oopsdazie ouais je peux me tromper dans ce cas mais la règle générale est de garder la question avec la meilleure collection de réponses, et de fermer l'autre en double , quelle que soit l'heure
phuclv

Réponses:

330

Une autre possibilité que j'ai trouvée, inspirée de l'utilisation de grep , est:

tasklist /FI "IMAGENAME eq myapp.exe" 2>NUL | find /I /N "myapp.exe">NUL
if "%ERRORLEVEL%"=="0" echo Program is running

Il n'a pas besoin d'enregistrer un fichier supplémentaire, je préfère donc cette méthode.

pkamb
la source
7
cela a bien fonctionné pour moi (Windows XP SP3). À
mon humble avis,
2
J'ai eu un problème de syntaxe avec cette ligne de commande. Je l'ai changé en tasklist /FI "IMAGENAME eq winword.exe" 2>NUL | find /I /N "winword.exe">NUL/ if %ERRORLEVEL%==1 goto wordnotrunningafin de le faire fonctionner (soupçonnant la citation autour des parties if
Steve B
4
N'oubliez pas que dans les autres versions linguistiques de XP, les noms des filtres ont été traduits en code mais pas mais en /?écran d' aide . Ainsi, par exemple, IMAGENAMEdans la version polonaise est NAZWA_OBRAZU.
rsk82
3
Sous Win7, j'ai dû le changer en tasklist /FI "IMAGENAME eq myapp.exe" /NH | find /I /N "myapp.exe" >NUL Le premier NUL semble inutile, je ne sais pas à quoi sert le '2', le / NH est facultatif.
Jan Doggen
12
tasklist quitte toujours avec le statut 0, qu'il trouve ou non des tâches correspondantes, c'est pourquoi il est inutile en soi. Puisque vous devez utiliser find (ou findstr) pour vérifier sa sortie de toute façon, il est inutile d'utiliser les filtres de la liste des tâches. Faites simplement la liste des tâches | trouver "myprog.exe"> nul: && goto foundit ou somesuch. Vous pourriez avoir besoin de l'option / v (verbose) pour lister les tâches.
Denis Howe
61

Voici comment je l'ai résolu:

tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log

FOR /F %%A IN (search.log) DO IF %%~zA EQU 0 GOTO end

start notepad.exe

:end

del search.log

Ce qui précède ouvrira le Bloc - notes s'il n'est pas déjà en cours d'exécution.

Modifier: notez que cela ne trouvera pas d'applications cachées dans la liste des tâches. Cela inclura toutes les tâches planifiées exécutées en tant qu'utilisateur différent, car elles sont automatiquement masquées.

Matt Lacey
la source
2
Changer le format de la liste des tâches en CSV ou autre chose que la table est important car il la disposition par défaut de la liste des tâches (table) tronque les noms d'images longs, ce qui rompt la logique.
Scott White
4
Cette solution ne fonctionnera pas sur Vista car TASKLIST produit une sortie même si le processus n'est pas trouvé. Je suppose que la même chose est vraie pour Windows 7.
dbenham
ne fonctionne pas dans Windows 10. search.log contient "INFO: aucune tâche en cours d'exécution qui correspond aux critères spécifiés." et aucun bloc-notes n'est démarré
Sergey
46

J'aime la solution de Chaosmaster! Mais j'ai cherché une solution qui ne démarre pas un autre programme externe (comme find.exe ou findstr.exe ). J'ai donc ajouté l'idée de la solution de Matt Lacey, qui crée un fichier temporaire également évitable. A la fin j'ai pu trouver une solution assez simple, donc je la partage ...

SETLOCAL EnableExtensions
set EXE=myprog.exe
FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% goto FOUND
echo Not running
goto FIN
:FOUND
echo Running
:FIN

Cela fonctionne bien pour moi ...

TrueY
la source
Cette solution fonctionne bien - testée dans Windows 8.1. J'ai remarqué qu'il est sensible à la casse.
oliver-clare
@LordScree Comme je travaille sur les systèmes un * x, la sensibilité à la casse est bonne pour moi! J'ai même défini le système de fichiers pour activer les noms de fichiers sensibles à la casse. ;)
TrueY
Fonctionne bien pour moi - testé sous Windows 7 X64
M. Rubix
Cela ne fonctionne pas si l'application a un espace dans le nom car% x finit par faire partie du nom de l'application jusqu'au premier espace.
Chris
Une solution possible serait de vérifier si l'application n'est pas trouvée à la place en vérifiant si% x == INFO: mais je ne sais pas sur quelles versions de Windows cela fonctionnerait ou s'il existe une meilleure solution.
Chris
21

La suggestion de npocmaka d'utiliser QPROCESS au lieu de TASKLIST est excellente mais, sa réponse est si grande et complexe que je me sens obligé d'en publier une version assez simplifiée qui, je suppose, résoudra le problème de la plupart des utilisateurs non avancés:

QPROCESS "myprocess.exe">NUL
IF %ERRORLEVEL% EQU 0 ECHO "Process running"

Le code ci-dessus a été testé dans Windows 7, avec un utilisateur avec des droits d'administrateur.

aldemarcalazans
la source
J'ai juste utilisé cette idée pour arrêter un tir automatisé deux fois et cela a fonctionné comme un charme!
Davy C
Je dois dire que contrairement à cette commande, les solutions de liste de tâches non seulement semblent trop compliquées pour une requête aussi simple, mais elles exécutent également une seconde environ et utilisent des tonnes de CPU! C'est beaucoup mieux, a également fonctionné sans autorisations d'administrateur (Windows Server 2012).
Eugene Marin
Cela semble être la solution la plus simple et la meilleure (au moins pour moi) car elle fonctionne telle quelle lorsque l'application a des espaces dans le nom. Je suis curieux de savoir quelles sont les limites de cette solution et pourquoi elle n'a pas plus de votes.
Chris
20

Sous Windows, vous pouvez utiliser Windows Management Instrumentation (WMI) pour vous assurer qu'aucune application avec la ligne de commande spécifiée n'est lancée, par exemple:

wmic process where (name="nmake.exe") get commandline | findstr /i /c:"/f load.mak" /c:"/f build.mak" > NUL && (echo THE BUILD HAS BEEN STARTED ALREADY! > %ALREADY_STARTED% & exit /b 1)

vtrz
la source
Notez que WMIC nécessite des privilèges administratifs; si vous ne l'avez pas, Only the administrator group members can use WMIC.EXE.suivi deReason:Win32 Error: Access is denied.
Jeroen Wiert Pluimers
Je pense que c'est la meilleure solution, car wmic vous donne une ligne de commande complète lancée et des millions d'autres informations ...
Glavić
14
TASKLIST | FINDSTR ProgramName || START "" "Path\ProgramName.exe"
Riccardo La Marca
la source
3
Cela fonctionne vraiment bien. Facile! Sachez qu'il est sensible à la casse, sauf si vous ajoutez /i.
Jason
8

J'utilise PV.exe de http://www.teamcti.com/pview/prcview.htm installé dans Program Files \ PV avec un fichier de commandes comme celui-ci:

@echo off
PATH=%PATH%;%PROGRAMFILES%\PV;%PROGRAMFILES%\YourProgram
PV.EXE YourProgram.exe >nul
if ERRORLEVEL 1 goto Process_NotFound
:Process_Found
echo YourProgram is running
goto END
:Process_NotFound
echo YourProgram is not running
YourProgram.exe
goto END
:END

la source
1
cela fonctionne pour moi sur Windows 7. La deuxième ligne est le répertoire qui contient le programme, pas le programme lui-même.
Fabio Cionini
8

La réponse de TrueY a semblé la solution la plus élégante, cependant, j'ai dû faire quelques farces parce que je ne comprenais pas exactement ce qui se passait. Permettez-moi de clarifier les choses pour, espérons-le, gagner du temps pour la prochaine personne.

Réponse modifiée de TrueY:

::Change the name of notepad.exe to the process .exe that you're trying to track
::Process names are CASE SENSITIVE, so notepad.exe works but Notepad.exe does NOT
::Do not change IMAGENAME
::You can Copy and Paste this into an empty batch file and change the name of
::notepad.exe to the process you'd like to track
::Also, some large programs take a while to no longer show as not running, so
::give this batch a few seconds timer to avoid a false result!!

@echo off
SETLOCAL EnableExtensions

set EXE=notepad.exe

FOR /F %%x IN ('tasklist /NH /FI "IMAGENAME eq %EXE%"') DO IF %%x == %EXE% goto ProcessFound

goto ProcessNotFound

:ProcessFound

echo %EXE% is running
goto END
:ProcessNotFound
echo %EXE% is not running
goto END
:END
echo Finished!

Quoi qu'il en soit, j'espère que cela aide. Je sais que parfois lire un batch / une ligne de commande peut être un peu déroutant parfois si vous êtes un peu novice, comme moi.

kayleeFrye_onDeck
la source
6

La réponse fournie par Matt Lacey fonctionne pour Windows XP. Cependant, dans Windows Server 2003, la ligne

 tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log

Retour

INFO: aucune tâche en cours d'exécution qui correspond aux critères spécifiés.

qui est ensuite lu pendant l'exécution du processus.

Je n'ai pas beaucoup d'expérience dans les scripts de traitement par lots, donc mon âme est de rechercher le nom du processus dans le search.logfichier et de pomper les résultats dans un autre fichier et de le rechercher pour n'importe quelle sortie.

tasklist /FI "IMAGENAME eq notepad.exe" /FO CSV > search.log

FINDSTR notepad.exe search.log > found.log

FOR /F %%A IN (found.log) DO IF %%~zA EQU 0 GOTO end

start notepad.exe

:end

del search.log
del found.log

J'espère que ça aidera quelqu'un d'autre.

benmod
la source
Cela fonctionne pour Win 2008. +1 pour Aucune tâche en cours d'exécution qui correspond aux critères spécifiés.
Mangesh Pimpalkar
5

J'aime les outils WMICet TASKLIST, mais ils ne sont pas disponibles dans les éditions home / basic de windows.Une autre façon est d'utiliser la QPROCESScommande disponible sur presque toutes les machines Windows (pour celles qui ont des services terminaux - je pense que gagner XP sans SP2, donc pratiquement tous les machine Windows):

@echo off
:check_process
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1
:: QPROCESS can display only the first 12 symbols of the running process
:: If other tool is used the line bellow could be deleted
set process_to_check=%process_to_check:~0,12%

QPROCESS * | find /i "%process_to_check%" >nul 2>&1 && (
    echo process %process_to_check%  is running
) || (
    echo process %process_to_check%  is not running
)
endlocal

QPROCESSLa commande n'est pas aussi puissante TASKLISTet est limitée à ne montrer que 12 symboles du nom du processus mais doit être prise en compte si elle TASKLISTn'est pas disponible.

Utilisation plus simple où il utilise le nom si le processus comme argument (le .exesuffixe est obligatoire dans ce cas où vous passez le nom de l'exécutable):

@echo off
:check_process
setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
:: .exe suffix is mandatory
set "process_to_check=%~1"


QPROCESS "%process_to_check%" >nul 2>&1 && (
    echo process %process_to_check%  is running
) || (
    echo process %process_to_check%  is not running
)
endlocal

La différence entre deux modes d' QPROCESSutilisation est que le QPROCESS *listera tous les processus alors qu'il QPROCESS some.exene filtrera que les processus pour l'utilisateur actuel.

Il est également possible d'utiliser des WMIobjets via Windows Script Host WMICExe au lieu de.Il devrait également être exécuté sur toutes les machines Windows (à l'exception de celles où le WSH est désactivé, mais c'est un cas rare). et peut être utilisé à la place du QPROCESSscript ci-dessus (il s'agit d'un hybride jscript / bat et doit être enregistré sous .bat):

@if (@X)==(@Y) @end /* JSCRIPT COMMENT **


@echo off
cscript //E:JScript //nologo "%~f0"
exit /b

************** end of JSCRIPT COMMENT **/


var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes =  new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
    var process=processes.item();
    WScript.Echo( process.processID + "   " + process.Name );
}

Et une modification qui vérifiera si un processus est en cours d'exécution:

@if (@X)==(@Y) @end /* JSCRIPT COMMENT **


@echo off
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running
set process_to_check=%~1

cscript //E:JScript //nologo "%~f0" | find /i "%process_to_check%" >nul 2>&1 && (
    echo process %process_to_check%  is running
) || (
    echo process %process_to_check%  is not running
)

exit /b

************** end of JSCRIPT COMMENT **/


var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
var processes =  new Enumerator(colProcess);
for (;!processes.atEnd();processes.moveNext()) {
    var process=processes.item();
    WScript.Echo( process.processID + "   " + process.Name );
}

Les deux options pourraient être utilisées sur des machines qui n'en ont pas TASKLIST.

La technique ultime utilise MSHTA. Cela s'exécutera sur toutes les machines Windows à partir de XP et au-dessus et ne dépend pas des paramètres d'hôte du script Windows. l'appel de MSHTApourrait cependant réduire un peu les performances (encore une fois, il devrait être enregistré en tant que batte):

@if (@X)==(@Y) @end /* JSCRIPT COMMENT **
@echo off

setlocal
if "%~1" equ "" echo pass the process name as forst argument && exit /b 1
:: first argument is the process you want to check if running

set process_to_check=%~1


mshta "about:<script language='javascript' src='file://%~dpnxf0'></script>" | find /i "%process_to_check%" >nul 2>&1 && (
    echo process %process_to_check%  is running
) || (
    echo process %process_to_check%  is not running
)
endlocal
exit /b
************** end of JSCRIPT COMMENT **/


   var fso= new ActiveXObject('Scripting.FileSystemObject').GetStandardStream(1);


   var winmgmts = GetObject("winmgmts:\\\\.\\root\\cimv2");
   var colProcess = winmgmts.ExecQuery("Select * from Win32_Process");
   var processes =  new Enumerator(colProcess);
   for (;!processes.atEnd();processes.moveNext()) {
    var process=processes.item();
    fso.Write( process.processID + "   " + process.Name + "\n");
   }
   close();
npocmaka
la source
2

Je ne sais pas comment le faire avec CMD intégré mais si vous avez grep, vous pouvez essayer ce qui suit:

tasklist /FI "IMAGENAME eq myApp.exe" | grep myApp.exe
if ERRORLEVEL 1 echo "myApp is not running"
Motti
la source
2

Il suffit de mentionner que si le nom de votre tâche est vraiment long, il n'apparaîtra pas dans son intégralité dans le tasklistrésultat, il peut donc être plus sûr (autre que la localisation) de vérifier le contraire.

Variation de cette réponse :

:: in case your task name is really long, check for the 'opposite' and find  the message when it's not there
tasklist /fi "imagename eq yourreallylongtasknamethatwontfitinthelist.exe" 2>NUL | find /I /N "no tasks are running">NUL
if "%errorlevel%"=="0" (
    echo Task Found
) else (
    echo Not Found Task
)
drzaus
la source
0

Je suppose que des fenêtres ici. Vous devrez donc utiliser WMI pour obtenir ces informations. Consultez les archives de The Scripting Guy pour de nombreux exemples sur la façon d'utiliser WMI à partir d'un script.

Pas moi
la source
0

J'ai utilisé le script fourni par Matt (2008-10-02). La seule chose avec laquelle j'ai eu du mal, c'est qu'il ne supprimait pas le search.logfichier. J'attends parce que je devais aller cdà un autre endroit pour commencer mon programme. Je cdreviens à l'endroit où se trouvent le fichier BAT search.log, mais il ne serait toujours pas supprimé. J'ai donc résolu cela en supprimant le search.logfichier d'abord au lieu du dernier.

del search.log

tasklist /FI "IMAGENAME eq myprog.exe" /FO CSV > search.log

FOR /F %%A IN (search.log) DO IF %%-zA EQU 0 GOTO end

cd "C:\Program Files\MyLoc\bin"

myprog.exe myuser mypwd

:end
Nin
la source
1
@Sebastian: Il y a un peu d'informations supplémentaires ajoutées ici, donc je suis enclin à le laisser comme réponse.
Bill the Lizard
0

Vous devez vérifier le nom du processus parent, voir l'article The Code Project sur une solution basée sur .NET ** .

Une façon non programmatique de vérifier:

  1. Lancer Cmd.exe
  2. Lancer une application (par exemple, c:\windows\notepad.exe)
  3. Vérifiez les propriétés du processus Notepad.exe dans Process Explorer
  4. Vérifier le processus parent (cela montre cmd.exe)

La même chose peut être vérifiée en obtenant le nom du processus parent.

prakash
la source
0

S'appuyant sur la réponse de vtrz et la réponse de Samuel Renkert sur un autre sujet , je suis venu avec le script suivant qui ne fonctionne que %EXEC_CMD%si elle est pas déjà en cours d' exécution:

@echo off
set EXEC_CMD="rsync.exe"
wmic process where (name=%EXEC_CMD%) get commandline | findstr /i %EXEC_CMD%> NUL
if errorlevel 1 (
    %EXEC_CMD% ...
) else (
    @echo not starting %EXEC_CMD%: already running.
)

Comme cela a été dit précédemment, cela nécessite des privilèges administratifs.

Calimo
la source
n'a pas fonctionné pour moi, et j'utilise un compte administrateur. Une boîte DOS apparaît avecNode - (computer name) ERROR: Description = Invalid query
khaverim
1
Fonctionne très bien pour moi.
Mark Duncan
1
Fonctionne très bien pour Windows 7 ici. Pas d'issues.
galacticninja
0

J'avais besoin d'une solution avec une nouvelle tentative. Ce code s'exécutera jusqu'à ce que le processus soit trouvé, puis le tuera. Vous pouvez définir un délai d'expiration ou quoi que ce soit si vous le souhaitez.

Remarques:

  • Le ".exe" est obligatoire
  • Vous pouvez créer un fichier exécutable avec des paramètres, version ci-dessous
    :: Set programm you want to kill
    :: Fileextension is mandatory
    SET KillProg=explorer.exe

    :: Set waiting time between 2 requests in seconds
    SET /A "_wait=3"

    :ProcessNotFound
        tasklist /NH /FI "IMAGENAME eq %KillProg%" | FIND /I "%KillProg%"
        IF "%ERRORLEVEL%"=="0" (
            TASKKILL.EXE /F /T /IM %KillProg%
        ) ELSE (
            timeout /t %_wait%
            GOTO :ProcessNotFound
        )

taskkill.bat:

    :: Get program name from argumentlist
    IF NOT "%~1"=="" (
        SET "KillProg=%~1"
    ) ELSE (
        ECHO Usage: "%~nx0" ProgramToKill.exe & EXIT /B
    )

    :: Set waiting time between 2 requests in seconds
    SET /A "_wait=3"

    :ProcessNotFound
        tasklist /NH /FI "IMAGENAME eq %KillProg%" | FIND /I "%KillProg%"
        IF "%ERRORLEVEL%"=="0" (
            TASKKILL.EXE /F /T /IM %KillProg%
        ) ELSE (
            timeout /t %_wait%
            GOTO :ProcessNotFound
        )

Courir avec .\taskkill.bat ProgramToKill.exe

Patrick
la source
-2

J'exécute généralement la commande suivante dans l'invite cmd pour vérifier si mon programme.exe est en cours d'exécution ou non:

tasklist | grep program
Rajeev Jayaswal
la source