
Ich habe ein Batch-Skript, das von einem AT-Befehl ausgeführt wird und möglicherweise mehr als einmal ausgeführt wird. Beim Start muss es erkennen, ob es bereits ausgeführt wird, und wenn ja, (das zweite) sofort beenden.
- Es muss robust sein und mit unerwarteten Beendigungen des Skripts umgehen können (d. h. ich kann beim Eintritt kein Flag setzen und es beim Austritt löschen).
- Es muss in einer Remotedesktopsitzung ausgeführt werden
- Ich hänge bei XP mit Powershell v2 fest, aber ich habe nichts dagegen, eine kleine EXE zu schreiben, wenn ich es nicht in Batch/Powershell oder VBS machen kann
- Das Skript muss minimiert ausgeführt werden, daher starte ich es mit Start "NAME" /MIN %COMSPEC% /C "MyScript.bat"
- Möglicherweise sind andere Cmd-Fenster geöffnet, daher muss ich das laufende Skript überprüfen
- Das Batch-Skript wird als SYSTEM-Benutzer ausgeführt, aber ich kann kein WMI verwenden
Ich habe PowerShell Get-Process verwendet, um mir MainWindowTitle anzusehen, aber das hat bei der Remote-Verbindung mit dem Computer nicht funktioniert, da das Skript zwar ausgeführt werden kann, aber in dieser Remote-Verbindungsinstanz nicht angezeigt wird. In diesem Fall wird der cmd-Prozess von Get-Process gesehen, aber der MainWindowTitle ist leer.
Ich habe Get-Process ausprobiert und mir die erweiterte Eigenschaft StartInfo.EnvironmentVariables angesehen, kann aber nicht erkennen, wie eine Umgebungsvariable erstellt wird, sodass sie in der Eigenschaft angezeigt wird.
Ich habe überlegt, /WAIT im Startbefehl zu verwenden, dann bleibt der AT geöffnet, bis er beendet ist, aber das Skript, das den AT enthält, wird nicht minimiert
Irgendwelche Ideen?
Antwort1
Ich glaube, dass eine Sperrdatei die einfachste und zuverlässigste Lösung ist. Der Trick besteht darin, sicherzustellen, dass Ihr laufender Batch-Prozess eine exklusive Schreibsperre für die Datei aufrechterhält, bis er beendet wird. Das Schöne an diesem System ist, dass Windows die Sperre aufhebt, egal aus welchem Grund der Batch beendet wird.
Sobald Sie eine Sperrdatei haben, müssen Sie feststellen können, ob die Datei derzeit gesperrt ist. Wie das geht, erkläre ich unterWie kann ich in der Befehlszeile überprüfen, ob eine bestimmte Datei oder ein bestimmtes Verzeichnis gesperrt ist (von einem Prozess verwendet wird)?
Ich habe diese primitive, aber effektive Technik verwendet, um einige ziemlich anspruchsvolle Aufgaben mit der Windows-Batchverarbeitung durchzuführen:
- Parallele Ausführung einer Liste von Aufgaben, wodurch die Gesamtzahl gleichzeitiger Prozesse begrenzt wird
- Wie können Sie unter Windows Protokolldateien gemeinsam nutzen?
- Serialisieren Sie die Ausführung des Symstore über Powershell oder BATCH
Ihnen ist nicht klar, wo sich die Batchdatei befindet – auf dem Remotecomputer oder dem lokalen Computer – oder ob Sie das Skript möglicherweise auf mehreren Computern gleichzeitig ausführen, aber nur einen aktiven Prozess pro Computer.
Wenn sich das Batch-Skript auf dem Remote-Computer befindet und Ihr Prozess Schreibzugriff auf das Skript hat, können Sie die Batch-Datei selbst als Sperrdatei verwenden! Sie müssen lediglich eine :subroutine aufrufen und dabei einen nicht verwendeten Datei-Handle im Anfügemodus an das Batch-Skript umleiten. Der Aufruf schlägt fehl, wenn ein anderer Prozess bereits eine Sperre hat. Die Sperre wird automatisch aufgehoben, wenn das Skript beendet wird (unabhängig davon, wie es beendet wird).
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
Wenn sich Ihr Skript auf einer anderen Maschine als der Prozess befindet, Sie den Prozess aber immer nur auf einer Maschine gleichzeitig ausführen, funktioniert das oben genannte meiner Ansicht nach trotzdem.
Eine bessere Alternative besteht vielleicht darin, auf jedem Remotecomputer eine dedizierte Sperrdatei zu erstellen, getrennt vom Batch-Skript. Dann können Sie den Prozess auf so vielen Remotecomputern ausführen, wie Sie möchten.
Antwort2
Danke für die Hilfe. Ich habe folgendes umgesetzt:
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
Das scheint gut zu funktionieren, weitere Tests werden es zeigen.
- Zum Auflisten laufender Prozesse verwende ich POWERSHELL Get-Process, da TASKLIST WMI verwendet, das mir, wie bereits erwähnt, nicht zur Verfügung steht.
- Um die PID des gestarteten Skripts zu bestimmen, liste ich alle aktuellen cmd-PIDs auf, starte das Skript und liste dann alle cmd-PIDs auf, um nach der einen zu suchen, die vorher nicht da war.
Antwort3
Ich habe ein automatisiertes Plugin namens CMDS erstellt, das Sie hier verwenden können:Wie kann ich erkennen, ob eine bestimmte Batchdatei ausgeführt wird und die PID abrufen?Ich bin jedoch nicht sicher, ob dies mit XP funktioniert.
Beispielbefehl:CMDS /TS "Your Batch File Title"
Es verfügt auch über einen GUI-Modus für die eigenständige Verwendung.
Hier ist die Hilfedatei: