Como posso saber se meu arquivo de lote está sendo executado?

6

Eu tenho um script em lote que é executado a partir de um comando AT e pode ser executado mais de uma vez. Quando começar, preciso detectar se já está em execução e, em caso afirmativo, sair (o segundo) imediatamente.

  1. Deve ser robusto e manipular se os scripts saírem inesperadamente (ou seja, não posso definir um sinalizador na entrada e desmarcá-lo na saída)
  2. Ele deve ser executado em uma sessão de área de trabalho remota
  3. Estou preso no XP com o Powershell v2, mas não me importo de escrever um exe se não puder fazê-lo em lote / powershell ou vbs
  4. O script deve ser executado minimizado, então eu inicio com Iniciar "NAME" / MIN% COMSPEC% / C "MyScript.bat"
  5. Outras janelas do cmd podem estar abertas, por isso preciso verificar o script em execução
  6. O script em lote é executado como usuário SYSTEM, mas não consigo usar nenhum WMI

Eu estava usando o PowerShell Get-Process para ver o MainWindowTitle, mas isso não funcionava quando eu me conectava remotamente ao computador, pois o script pode estar em execução, mas não exibido nessa instância de conexão remota. Neste caso, o processo do cmd é visto pelo Get-Process, mas o MainWindowTitle está em branco.

Eu tentei o Get-Process e examinei a propriedade StartInfo.EnvironmentVariables expandida, mas não consigo ver como criar um env var para que ele apareça na propriedade.

Eu pensei em usar / WAIT no comando start, então o AT permanecerá aberto até que termine, mas o script contendo o AT não é minimizado

Alguma idéia?

    
por FrinkTheBrave 03.02.2016 / 11:33

3 respostas

3

Eu acredito que um arquivo de bloqueio é a solução confiável mais simples. O truque é garantir que o processo em lote em execução mantenha um bloqueio de gravação exclusivo no arquivo até que seja finalizado. A beleza deste sistema é que o Windows irá liberar o bloqueio, não importando o motivo pelo qual o lote termine.

Depois de ter um arquivo de bloqueio, você precisa de uma maneira de detectar se o arquivo está bloqueado no momento. Eu descrevo como fazer isso em Como verificar na linha de comando se um determinado arquivo ou diretório está bloqueado (usado por qualquer processo)?

Eu usei essa técnica primitiva, mas eficaz, para realizar algumas tarefas bastante sofisticadas com o lote do Windows:

Você não sabe onde o arquivo de lote reside - na máquina remota ou na máquina local, ou se você pode estar executando o script em várias máquinas simultaneamente, mas apenas um processo ativo por máquina.

Se o script em lote estiver na máquina remota e seu processo tiver acesso de gravação ao script, você poderá usar o próprio arquivo em lote como o arquivo de bloqueio! Você só precisa chamar uma sub-rotina ao redirecionar um identificador de arquivo não usado para o script em lote usando o modo de anexação. A CHAMADA falhará se outro processo já tiver um bloqueio. O bloqueio será liberado automaticamente quando o script terminar (independentemente de como ele termina).

myscript.bat

@echo off
:: Note - this extra call is to avoid a bug with %~f0 when the script
::        is executed with quotes around the script name.
call :getLock
exit /b

:getLock
:: The CALL will fail if another process already has a write lock on the script
call :main 9>>"%~f0"
exit /b

:main
:: Body of your script goes here. Only one process can ever get here
:: at a time. The lock will be released upon return from this routine,
:: or when the script terminates for any reason
exit /b

Se o seu script estiver em uma máquina diferente do processo, mas você só tiver o processo em execução em uma máquina por vez, acho que o processo acima ainda funcionará.

Talvez uma alternativa melhor seja estabelecer um arquivo de bloqueio dedicado em cada máquina remota, separado do script em lote. Então você pode executar o processo em quantas máquinas remotas quiser.

    
por 04.02.2016 / 04:15
2

Obrigado pela ajuda. Eu implementei o seguinte:

Before starting my script (in a wrapper script), check whether the lockfile exists:
  If it does, read the PID out of it.
    If the PID is still a running cmd process, exit my script as another version of it is already running.
    If the PID is not still a running cmd process, delete the lockfile
  Start the script, and create a new lockfile, containing the PID of the started script

When exiting my script, delete the lockfile

Isso parece funcionar bem, mais testes dirão.

  1. Para listar processos em execução, uso o POWERSHELL Get-Process, pois o TASKLIST usa o WMI, que, como afirmei anteriormente, não está disponível para mim.
  2. Para determinar o PID do script iniciado, listo todos os cmd PIDs atuais, inicio o script e, em seguida, listo todos os cmd PIDs, procurando aquele que não estava lá antes.
por 04.02.2016 / 14:47
-2

Eu criei um plug-in automatizado chamado CMDS que você pode usar aqui: Como eu veria se um determinado arquivo de lote está sendo executado? e obter o PID No entanto, não tenho certeza se isso funcionará com o XP.

Ele também possui um modo gui para ser usado sozinho.

    
por 15.12.2017 / 15:15