web-dev-qa-db-ja.com

バッチファイルが実行中かどうかを確認するにはどうすればよいですか?

ATコマンドから実行されるバッチスクリプトがあり、複数回実行される可能性があります。開始時に、既に実行されているかどうかを検出する必要があります。実行されている場合は、終了します( 2つ目)すぐに。

  1. これは堅牢で、スクリプトが予期せず終了した場合に処理する必要があります(つまり、開始時にフラグを設定して終了時にフラグをクリアすることはできません)。
  2. リモートデスクトップセッションで実行する必要があります
  3. Powershell v2でXP=で立ち往生していますが、バッチ/ powershellまたはvbsで実行できない場合は、少しexeを書いても構いません。
  4. スクリプトは最小化して実行する必要があるため、Start "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を含むスクリプトは最小化されていません

何か案は?

8
FrinkTheBrave

ロックファイルは、最も簡単で信頼性の高いソリューションだと思います。コツは、実行中のバッチプロセスが終了するまでファイルへの排他書き込みロックを維持することです。このシステムの優れた点は、バッチが終了した理由に関係なく、Windowsがロックを解放することです。

ロックファイルを取得したら、ファイルが現在ロックされているかどうかを検出する方法が必要です。私はこれを行う方法を 特定のファイルまたはディレクトリがロックされている(任意のプロセスで使用されている)かどうかをコマンドラインで確認する方法)で説明しています

この原始的でありながら効果的な手法を使用して、Windowsバッチでかなり高度なタスクをいくつか実行しました。

リモートマシンまたはローカルマシンのバッチファイルがどこにあるか、または複数のマシンで同時にスクリプトを実行しているかもしれませんが、マシンごとにアクティブなプロセスは1つだけです。

バッチスクリプトがリモートマシンにあり、プロセスにスクリプトへの書き込みアクセス権がある場合、バッチファイル自体をロックファイルとして使用できます。追加モードを使用して、未使用のファイルハンドルをバッチスクリプトにリダイレクトするときに、単に:subroutineを呼び出す必要があります。別のプロセスがすでにロックしている場合、CALLは失敗します。ロックは、スクリプトの終了時に自動的に解放されます(スクリプトが終了する方法に関係なく)。

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

スクリプトがプロセスとは異なるマシン上にあるが、一度に1つのマシン上でのみプロセスを実行している場合、上記は引き続き機能すると思います。

おそらく、より良い代替策は、バッチスクリプトとは別に、各リモートマシンに専用のロックファイルを確立することです。その後、必要な数のリモートマシンでプロセスを実行できます。

7
dbenham

助けてくれてありがとう。私は以下を実装しました:

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. TASKLISTはWMIを使用するため、実行中のプロセスを一覧表示するには、POWERSHELL Get-Processを使用します。
  2. 開始されたスクリプトのPIDを確認するには、現在のすべてのcmd PIDを一覧表示し、スクリプトを開始してから、すべてのcmd PIDを一覧表示して、前に存在しなかったものを探します。
2
FrinkTheBrave