7

У меня есть пакетный скрипт, который запускается из команды AT, и может быть запущен более одного раза. Когда он запускается, мне нужно определить, запущен ли он, и если да, немедленно выйти (второй).

  1. Он должен быть надежным и обрабатывать, если сценарии неожиданно завершаются (т.е. я не могу установить флаг при входе и очистить его при выходе)
  2. Он должен работать в сеансе удаленного рабочего стола
  3. Я застрял на XP с Powershell v2, но не против написать небольшой exe, если я не могу сделать это в batch/powershell или vbs
  4. Сценарий должен быть свернут, поэтому я запускаю его с помощью команды "Пуск" NAME /MIN% COMSPEC% /C «MyScript.bat»
  5. Другие окна cmd могут быть открыты, поэтому мне нужно проверить работающий скрипт
  6. Пакетный скрипт запускается от имени пользователя SYSTEM, но я не могу использовать WMI

Я использовал PowerShell Get-Process для просмотра MainWindowTitle, но это не сработало при удаленном подключении к компьютеру, так как сценарий может быть запущен, но не отображается в этом экземпляре удаленного подключения. В этом случае процесс cmd виден Get-Process, но MainWindowTitle пуст.

Я попробовал Get-Process и посмотрел на расширенное свойство StartInfo.EnvironmentVariables, но не вижу, как создать env var, чтобы он отображался в свойстве.

Я думал об использовании /WAIT в команде запуска, тогда AT будет оставаться открытым, пока не завершится, но сценарий, содержащий AT, не свернут

Есть идеи?

3 ответа3

5

Я считаю, что файл блокировки - самое простое и надежное решение. Хитрость заключается в том, чтобы убедиться, что ваш запущенный пакетный процесс поддерживает эксклюзивную блокировку записи в файл до его завершения. Прелесть этой системы в том, что Windows снимает блокировку независимо от причины, по которой пакет завершается.

Если у вас есть файл блокировки, вам нужен способ определить, заблокирован ли файл в данный момент. Я описываю, как это сделать, в разделе Как проверить в командной строке, заблокирован ли данный файл или каталог (используется каким-либо процессом)?

Я использовал этот примитивный, но эффективный метод для решения некоторых довольно сложных задач с помощью пакета Windows:

Вам неясно, где находится пакетный файл - на удаленном компьютере или на локальном компьютере, или если вы могли запускать сценарий одновременно на нескольких машинах, но только один активный процесс на машину.

Если пакетный сценарий находится на удаленной машине, и ваш процесс имеет доступ для записи в сценарий, то вы можете использовать сам пакетный файл в качестве файла блокировки! Вам просто нужно вызвать подпрограмму: при перенаправлении неиспользуемого дескриптора файла в пакетный скрипт в режиме добавления. ВЫЗОВ не будет выполнен, если другой процесс уже имеет блокировку. Блокировка будет снята автоматически, когда скрипт завершится (независимо от того, как он завершится).

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

Если ваш сценарий находится на другой машине, чем процесс, но вы одновременно запускаете процесс только на одной машине, то я думаю, что вышеописанное все равно будет работать.

Возможно, лучшая альтернатива - установить отдельный файл блокировки на каждом удаленном компьютере отдельно от пакетного сценария. Затем вы можете запустить процесс на любом количестве удаленных компьютеров.

2

Спасибо за помощь. Я реализовал следующее:

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

Это, кажется, работает хорошо, дальнейшее тестирование покажет.

  1. Для отображения запущенных процессов я использую POWERSHELL Get-Process, так как TASKLIST использует WMI, который, как я уже говорил ранее, мне недоступен.
  2. Чтобы определить PID запущенного сценария, я перечисляю все текущие идентификаторы cmd, запускаю сценарий, а затем перечисляю все идентификаторы cmd, ища тот, которого не было раньше.
-2

Я создал автоматический плагин под названием CMDS, который вы можете использовать здесь: Как я могу увидеть, работает ли определенный пакетный файл и получает ли PID? Однако я не уверен, будет ли это работать с XP.

Пример команды: CMDS /TS "Your Batch File Title" командного файла"

Он также имеет графический интерфейс для использования сам по себе.

Вот файл справки:

Справка MSG

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .