OVH Cloud OVH Cloud

Tester l'exécution d'un script

17 réponses
Avatar
SupDePlouf
Bonjour,

Comment tester dans un script batch qu'un auture script batch est en cours
d'exécution ou non ?

Merci
--
SupDePlouf

10 réponses

1 2
Avatar
Gilles LAURENT
"SupDePlouf" a écrit dans le
message de news:
| Bonjour,

Bonjour,

| Comment tester dans un script batch qu'un auture script batch est en
| cours d'exécution ou non ?

Ci-dessous le script VBScript 'isRunning.vbs" permettant de déterminer
si un script batch (*.cmd ou *.bat) est en cours d'exécution.

+++ Usage
>cscript isRunning.vbs <nom_du_script_batch>

+++ Exemple
>cscript isRunning.vbs toto.bat

Note : La variable d'environnement errorlevel est fixée comme suit :
%errorlevel% = 0 si le script batch n'est pas en cours d'exécution
%errorlevel% = 1 si le script batch est en cours d'exécution

Pour tester dans un script batch si le script toto.bat est en cours
d'exécution
cscript //nologo isRunning.vbs toto.bat || echo en cours d'exécution

--- Coupez ici : isRunning.vbs ---

Option Explicit

' déclaration des variables
Dim oWMI, oProc
Dim colProcs
Dim strBatch

' lecture du nom du script batch
strBatch = WScript.Arguments (0)

' initialisation des objets
Set oWMI = GetObject ("winmgmts:.rootcimv2")
Set colProcs = oWMI.ExecQuery ( _
"Select * From Win32_Process " & _
"Where Name='cmd.exe'")

' énumération des processus console actifs
For Each oProc in colProcs
If InStr ( _
LCase (oProc.CommandLine), _
LCase (strBatch)) _
Then
WScript.Quit (1)
End If
Next

--- Coupez ici : isRunning.vbs ---

--
Gilles LAURENT
Me contacter : http://cerbermail.com/?zoTY7ZkLcD
Avatar
Méta-MCI
Bonsoir !


Cela dépend comment a été lancé le batch.

S'il a été lancé interactivement, il n'est pas possible de savoir,
simplement, si le batch est en fonctionnement.

S'il a été lancé comme paramètre d'une ligne de commande (par exemple, avec
un "cmd /ctemp.bat"), là, c'est possible.
Il suffit d'utiliser un batch de ce genre :
wmic process where name="cmd.exe" list full |find "temp.bat"



En l'absence du nom du script dans la ligne de commande, il reste possible
de lister tous les process "cmd.exe" (comme le fait Gilles), avec le
mini-batch suivant :
wmic process where name="cmd.exe" list full |find "CommandLine"
(pour avoir la ligne de commande)

ou
wmic process where name="cmd.exe" list full |find "ProcessId"
(pour avoir le PID)

Mais je doute que cela réponde à ton besoin.



Une autre solution consiste à utiliser un signal, dans le premier batch (par
exemple un fichier-repère), ouvert au début du batch, et supprimé à la fin.
Si le signal existe, c'est que le batch est lancé.
Mais, il faut avoir la possibilité de modifier le batch...



@-salutations

Michel Claveau
Avatar
Jacques Barathon [MS]
Gilles,

Ta solution marche super bien si le script batch a été lancé depuis
l'Explorateur. Si en revanche il a été lancé depuis l'invite de commandes
elle-même, la propriété CommandLine ne contiendra que la référence à
cmd.exe.

On peut quand même tester ce cas particulier en s'appuyant sur le titre de
la fenêtre. Si une commande est lancée depuis l'invite de commandes, le nom
de la commande apparaît dans la barre de titre. Et l'information est
accessible depuis l'objet .Net System.Diagnostics.Process, qui expose
l'information par sa propriété MainWindowTitle. On pourra donc écrire (en
PowerShell pour rester dans un langage qui permet l'accès à WMI et aux
objets .NET dans la plus simple évidence) ;-) :

function test-script ($scriptname="toto.bat")
{
$cmd = get-wmiobject win32_process -filter 'Name="cmd.exe"'
$cmd | where {$_.commandline -match $scriptname -or (get-process -id
$_.Handle).MainWindowTitle -match $scriptname}
}

Exemple:
PS> test-script loop.bat | format-table name,handle,commandline -a

name handle commandline
---- ------ -----------
cmd.exe 3496 "D:Windowssystem32cmd.exe"
cmd.exe 6408 cmd /c ""C:Documents and SettingsjbarathoMy
DocumentsPrivatetestloop.bat" "

Le premier process (id 3496) a cmd.exe en CommandLine. Le script loop.bat a
donc été lancé depuis cmd.exe.
Le second process (id 6408) a "cmd /c ...loop.bat" en CommandLine. Le
script a donc été directement lancé depuis l'Explorateur (ou toute autre
application permettant d'invoquer un autre exécutable).

Jacques

"Gilles LAURENT" a écrit dans le message de news:

"SupDePlouf" a écrit dans le
message de news:
| Bonjour,

Bonjour,

| Comment tester dans un script batch qu'un auture script batch est en
| cours d'exécution ou non ?

Ci-dessous le script VBScript 'isRunning.vbs" permettant de déterminer
si un script batch (*.cmd ou *.bat) est en cours d'exécution.

+++ Usage
>cscript isRunning.vbs <nom_du_script_batch>

+++ Exemple
>cscript isRunning.vbs toto.bat

Note : La variable d'environnement errorlevel est fixée comme suit :
%errorlevel% = 0 si le script batch n'est pas en cours d'exécution
%errorlevel% = 1 si le script batch est en cours d'exécution

Pour tester dans un script batch si le script toto.bat est en cours
d'exécution
cscript //nologo isRunning.vbs toto.bat || echo en cours d'exécution

--- Coupez ici : isRunning.vbs ---

Option Explicit

' déclaration des variables
Dim oWMI, oProc
Dim colProcs
Dim strBatch

' lecture du nom du script batch
strBatch = WScript.Arguments (0)

' initialisation des objets
Set oWMI = GetObject ("winmgmts:.rootcimv2")
Set colProcs = oWMI.ExecQuery ( _
"Select * From Win32_Process " & _
"Where Name='cmd.exe'")

' énumération des processus console actifs
For Each oProc in colProcs
If InStr ( _
LCase (oProc.CommandLine), _
LCase (strBatch)) _
Then
WScript.Quit (1)
End If
Next

--- Coupez ici : isRunning.vbs ---

--
Gilles LAURENT
Me contacter : http://cerbermail.com/?zoTY7ZkLcD




Avatar
Michel Claveau
Bonjour, Jacques !

Normalement, ce sont les vampires qui travaillent de nuit.
A moins que les microsoftiens...

Sinon, l'idée du titre de la fenêtre est intéressante, avec PowerShell,
qui expose cette propriété. Ce qui n'est pas le cas de wmic (ou alors,
je n'ai pas trouvé).

--
@-salutations

Michel Claveau
Avatar
Michel Claveau
Re

à la réflexion, il n'existe aucune méthode fiable, pour savoir si un
batch est en cours.

Pour les raisons suivantes :
- fondamentalement, un batch n'est qu'un pointeur sur un fichier, qui
est ouvert/fermé à chaque appel. On le voit, car le fichier est
modifiable pendant l'exécution.
- un batch peut modifier le titre courant de la fenêtre
(title=XXX...)
- un batch peut être lancé de multiple façons, y compris de manière
invisible (sans fenêtre), et windows ne voit pas toujours la même chose
- lorsqu'un batch appelle une commande externe, cela crée (le plus
souvent) un nouveau process, dont on n'a pas forcément la dépendance.
Et cela vaut pour des batch qui appelent d'autres batch. Résultat : il
y a des situations d'où on ne pourra pas sortir d'informations fiables.

Conclusion : si on veut qu'un batch soit "traçable", il faut prévoir ça
à l'intérieur du batch lui-même.

--
@-salutations

Michel Claveau
Avatar
Jean
Conclusion : si on veut qu'un batch soit "traçable", il faut prévoir ça à
l'intérieur du batch lui-même.


Absolument :-)

Amicalement,

--
Jean - JMST
Belgium

Avatar
Jacques Barathon [MS]
"Michel Claveau" <Enleverles a écrit dans le
message de news:
Bonjour, Jacques !

Normalement, ce sont les vampires qui travaillent de nuit.
A moins que les microsoftiens...


Oh, je ne travaillais pas, juste une petite crise d'insomnie :-(

Sinon, l'idée du titre de la fenêtre est intéressante, avec PowerShell,
qui expose cette propriété. Ce qui n'est pas le cas de wmic (ou alors, je
n'ai pas trouvé).


En l'occurrence PowerShell exploite la propriété MainWindowTitle de la
classe .NET System.Diagnostics.Process. Il se trouve que WMI expose la ligne
de commande mais pas le titre de la fenêtre, et que .NET expose le titre de
la fenêtre mais pas la ligne de commande. Heureusement, PowerShell est
arrivé, qui a accès aux deux mondes! :-)

Sinon, sur le fond tu as entièrement raison à propos de la traçabilité d'un
batch. Avant de voir la réponse de Gilles j'étais d'ailleurs parti pour
répondre avec une solution basée sur ce principe de fichier-repère. Je m'en
suis servi très souvent dans des tâches automatisées sur des serveurs. Ce
mécanisme est très simple et peut permettre à peu près tous les types de
synchronisation souhaités.

Jacques

Avatar
Gilles LAURENT
"Jacques Barathon [MS]" a écrit dans le
message de news:

Bonjour,

[...]

| Sinon, sur le fond tu as entièrement raison à propos de la
| traçabilité d'un batch. Avant de voir la réponse de Gilles j'étais
| d'ailleurs parti pour répondre avec une solution basée sur ce
| principe de fichier-repère. Je m'en suis servi très souvent dans des
| tâches automatisées sur des serveurs. Ce mécanisme est très simple et
| peut permettre à peu près tous les types de synchronisation souhaités.

C'est vrai que s'appuyer sur les arguments de la ligne de commande du
processus cmd.exe pour tester l'exécution d'un script batch n'est pas
fiable à 100%. Néanmoins, je pense que dans la majorité des scénarii
cette technique peut être adoptée. Toutefois, une solution plus robuste
serait de démarrer le batch à surveiller dans un job. De ce fait, quoi
que fasse le script batch (commandes externes, appels à d'autres scripts
batch etc ...) l'environnement d'exécution serait limité au job. Pour
tester l'éxécution du script batch et/ou de ses dépendances il suffirait
simplement de vérifier la présence du job car le job n'existerait que
pendant le temps d'exécution du batch et de ses dépendances. A vrai dire
j'ai maquetté avec succès et cela donne le résultat suivant :

+++ Usage

Pour exécuter un script batch ou un processus dans un job
Si le job n'existe pas il est créé
>job3_14.exe -run <commande> -jobname <nom_du_job>

Pour vérifier la présence du job
>job3_14.exe -status -jobname <nom_du_job>

Pour lister les processus en cours d'exécution dans le job
Affichage du pid et du nom du processus
>job3_14.exe -query -jobname <nom_du_job>

Pour attendre jusqu'à la fin du job
>job3_14.exe -wait -jobname <nom_du_job>

Pour terminer le job donc arrêter tous les processus membres
>job3_14.exe -kill -jobname <nom_du_job>

J'ai écrit le binaire CUI job3_14.exe en C. Il serait tout à fait
envisageable de l'implémenter sous forme d'un ActiveX ou serveur COM ;-)
dans le but d'utiliser ces méthodes et propriétés à partir de VBScript
ou tout autre langage supportant automation. Cela pourrait donner cela :

--- script1.vbs : démarrage des batch ---

Option Explicit

' déclaration des variables
Dim oJob

' initialisation des objets
Set oJob = CreateObject ("IJob3_14.job")

' définition du nom du job
oJob.Name = "monJob"

' création du job et exécution des processus
oJob.Run "test1.bat" ' création du job puis démarrage du processus
oJob.Run "test2.bat" ' démarrage du processus dans le job

' attente de la fin du traitement
oJob.Wait

--- script1.vbs : démarrage des batch ---

--- script2.vbs : contrôle du job ---

Option Explicit

' déclaration des variables
Dim oJob, oProc
Dim colProc

' initialisation des objets
Set oJob = CreateObject ("IJob.job")

' définition du nom du job à contrôler
oJob.Name = "monJob"

' attente de la fin du job
Do Until oJob.Status = 0

' lecture des processus présents dans le job
Set colProc = oJob.Query
For Each oProc In colProc
WScript.Echo oProc.ProcessId
WScript.Echo oProc.ProcessName
Next

' pause
WScript.Sleep (1000)
Loop

' job terminé
WScript.Echo "Done..."

--- script2.vbs : contrôle du job ---

--
Gilles LAURENT
Me contacter : http://cerbermail.com/?zoTY7ZkLcD
Avatar
MC
Bonjour !

Mais, si le batch en appelle un autre (directement, ou par CALL), ça ne
suivra pas.

--
@-salutations

Michel Claveau
Avatar
Gilles LAURENT
"MC" a écrit dans le message de
news:
| Bonjour !

Bonjour,

| Mais, si le batch en appelle un autre (directement, ou par CALL), ça
| ne suivra pas.

Oui ça "suivra". C'est justement là tout l'intérêt du job. Le premier
processus est "injecté" dans le job (une enveloppe en quelque sorte) et
les descendants tournent dans ce même job. Le job est détruit de manière
implicite lorsque tous les processus membres du job sont terminés ou
alors de manière explicite en forçant sa fermeture. Dans ce dernier cas,
tous les processus en cours d'exécution seront également détruits.

Par exemple, soit le batch root.cmd

--- root.cmd ---

:: démarrage du batch root.cmd
:: cmd.exe dans le job
@echo off

:: démarrage d'un processus
:: cmd.exe et notepad.exe dans le job
start notepad.exe

:: appel d'un batch par call (test1.cmd rend la main)
:: pas de création de nouveau processus
:: cmd.exe et notepad.exe dans le job
call test1.cmd

:: démarrage d'un processus
:: cmd.exe, notepad.exe et calc.exe dans le job
start calc.exe

:: démarrage d'un processus
:: 2 cmd.exe, notepad.exe et calc.exe dans le job
start test2.cmd

:: enchaînement sur test3.cmd
:: pas de création de nouveau processus
:: 2 cmd.exe, notepad.exe et calc.exe dans le job
test3.cmd

:: lorsque le batch test3.cmd sera terminé
:: 1 cmd.exe, notepad.exe et calc.exe dans le job

--- root.cmd ---

Le job sera détruit implicitement lorsque les processus ...

cmd.exe (test2.cmd)
notepad.exe
calc.exe

... seront terminés

--
Gilles LAURENT
Me contacter : http://cerbermail.com/?zoTY7ZkLcD
1 2