jan-markus
Goto Top

Poweshell-Skript soll nur einmal gleichzeitig laufen dürfen?

Hi,

Ich habe ein Powershell-Skript, welches zyklisch Eingaben aus einer Datei einliest (solange es aktiv ist).

Wie verhindere ich das es aus versehen ein 2. Mal gestartet wird während das erste schon/noch läuft?

Ich müsste ja irgendwie prüfen, ob ein Prozess mit einem bestimmten Namen schon existiert, dann könnte ich beim Start des Skriptes darauf prüfen.

Vielen Dank für jegliche Denkanstöße oder Richtungsstupser face-smile

Jan

Content-ID: 566186

Url: https://administrator.de/contentid/566186

Ausgedruckt am: 22.11.2024 um 05:11 Uhr

SlainteMhath
Lösung SlainteMhath 20.04.2020 um 14:55:18 Uhr
Goto Top
Moin,

0. Bei vorhandenden Flag-Datei Ausführung abbrechen
1. Beim Start Flag Datei in festgelegtem Verzeichniss erstellen
2. Flagdatei Beim Beenden löschen

Geht sicher auch mit Prozessabfräge o.Ä. ab die Datei tut's auch.

lg,
Slainte
jan-markus
jan-markus 20.04.2020 um 15:45:58 Uhr
Goto Top
Klasse! Genau die Art Stupser brauchte ich! Klar, ein lockfile!
Vielen Dank! face-smile
manuel-r
Lösung manuel-r 20.04.2020 um 16:27:34 Uhr
Goto Top
Klar, ein lockfile!

Die Methode hat einen entscheidenden Nachteil: Sollte dein Script unerwartet abbrechen/beendet werden wird die Datei nicht gelöscht und dein Script startet nie wieder. Zumindest so lange nicht bis jemand manuell die Datei löscht.
Deswegen würde ich das etwa so lösen:
If (Get-WmiObject win32_process | Where -Property CommandLine -Match "meinscript.ps1") {  
  machwas
} Else {
  machwasanderes
}

Manuel
jan-markus
jan-markus 20.04.2020 um 18:35:25 Uhr
Goto Top
Danke Manuel,

das ist super! So kann ich direkt prüfen, ob "meinscript.ps1" bereits läuft. Das probiere ich aus!

Vielen Dank!
jan-markus
jan-markus 20.04.2020 um 21:13:10 Uhr
Goto Top
In die Richtung komme ich leider nicht weiter. In der Property "CommandLine" steht nur Powershell.exe - leider nicht das Skript, welches dort ausgeführt wird.
manuel-r
Lösung manuel-r 20.04.2020 aktualisiert um 21:42:07 Uhr
Goto Top
In die Richtung komme ich leider nicht weiter. In der Property "CommandLine" steht nur Powershell.exe - leider nicht das Skript, welches dort ausgeführt wird.

Doch, das steht da ganz sicher drin. Aber natürlich nur, wenn auch ein Script läuft. Genauer gesagt muss das Script auch über die Kommandzeile gestartet worden sein. Eine Powershell starten und dann darin das Script aufrufen führt nicht zum gewünschten Ergebnis. Aber das hast du normalerweise ja eher nicht. Entweder startet ein Benutzer das Script ja vermutlich über rechte Maustaste > mit Powershell ausführen oder es gibt eine Verknüpfung zum Script oder einen geplanten Task.
Das sagt ja auch die Property CommandLine. Wenn der Scriptname nicht in der aufrufenden Befehlzeile drin steht, dann ist die Bedingung naturlich nicht erfüllt.

Als Beispiel habe ich hier mal ein Script laufen lassen, das einfach nur eine Loop macht damit es ewig läuft. Als Ausgabe von
Get-WmiObject win32_process | Where -Property CommandLine -Match "testloop.ps1"  
erhalte ich dann während das andere Script läuft
CommandLine:
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" "-Command" "if((Get-ExecutionPolicy ) -ne 'AllSigned') { Set-ExecutionPolicy -Scope Process Bypass }; & 'C:\Users\<meinuser>\Desktop\testloop.ps1'"  
Und damit ist die If-Bedingung Wahr/True

Manuel
filippg
Lösung filippg 20.04.2020 um 23:39:04 Uhr
Goto Top
Hallo,

dafür gibt es Mutexe.
Siehe etwa https://www.msxfaq.de/code/powershell/ps-mutex.htm
Am Anfang des Skriptes versuchen, den Mutex zu erhalten, bei Fehler Skript abbrechen. Am Ende des Skriptes idealerweise den Mutex wieder freigeben. Selbst wenn das nicht erfolgt, wird er bei Beendendes Prozesses freigegeben, es wird dann nur bei der nächsten Abfrage eine Exception geworfen.
-> Saubere Zustandssynchronisierung über mehrere Prozesse, ohne Dateien, ohne darauf angewiesen zu sein, dass der Skriptname immer gleich ist, ohne Deadlock, wenn das Skript abstürtzt, ohne...

Grüße

Filipp
TK1987
Lösung TK1987 21.04.2020 aktualisiert um 09:46:17 Uhr
Goto Top
Moin,

du kannst dem Skript auch einfach einen eigenen Fenstertitel verpassen, nach diesem kannst du dann ganz leicht filtern
$Host.UI.RawUI.WindowTitle='Mein Skript'  

if ((Get-Process Powershell| ?{$_.MainWindowTitle -match $Host.UI.RawUI.WindowTitle}).Count -gt 1) {Return}
# Ab hier läuft das Skript nur noch ein mal...

Gruß Thomas
jan-markus
jan-markus 21.04.2020 um 12:15:25 Uhr
Goto Top
Ein wirklich dickes DANKE! nochmal an ALLE für die zahlreichen, auch unterschiedlichen Ansätze, zur Lösung!
jan-markus
jan-markus 21.04.2020, aktualisiert am 22.04.2020 um 07:31:22 Uhr
Goto Top
Hab das jetzt einmal als Test so umgesetzt. Weiß nicht, ob ich damit alle Fälle abdecke, aber die Tests sehen soweit gut aus.

$ProcessName = 'TEST'  
$Host.UI.RawUI.WindowTitle = $ProcessName

if ((Get-Process | ?{$_.MainWindowTitle -match $Host.UI.RawUI.WindowTitle}).Count -gt 1) {
        Write-Host "Nein. Da ist noch ein anderer $ProcessName!"  
        Start-Sleep 5
        Return
    }

while ($true) {
    Write-Host "Hallo? Bin ich allein?"  
    Start-Sleep 5
}

  • "Start-Sleep 5" hinzugefügt nach Hinweis.
TK1987
TK1987 21.04.2020 aktualisiert um 14:18:41 Uhr
Goto Top
Zitat von @jan-markus:
Hab das jetzt einmal als Test so umgesetzt.
 if ((Get-Process | ?{$_.MainWindowTitle -match $Host.UI.RawUI.WindowTitle}).Count -gt 1) {
        Write-Host "Nein. Da ist noch ein anderer $ProcessName!"  
        Return
    } 
Wenn du willst, dass dem Benutzer hier etwas angezeigt wird, musst du vor dem Return natürlich auch noch einen sleep oder ähnliches einbauen, sonst ist das Skript ja beendet, bevor du den write-host Befehl lesen kannst
while ($true) {
    Write-Host "Hallo? Bin ich allein?"  
    Start-Sleep 5
}
Ist die Endlosschleife absicht?
Weiß nicht, ob ich damit alle Fälle abdecke...
Was meinst du mit "alle Fälle"?! Es gibt doch nur 2 Fälle, entweder läuft bereits eine Instanz des Skripts - oder eben nicht.
jan-markus
jan-markus 22.04.2020 um 07:30:19 Uhr
Goto Top
Danke, klar, ein "Sleep" müsste da noch hin.
Die Endlosschleife ist an der Stelle für den Test: Ein Skript läuft und ich starte das 2. zum Test.
Stimmt, beide Fälle sind abgedeckt face-smile
NordicMike
NordicMike 22.04.2020 um 09:56:05 Uhr
Goto Top
So nebenbei, weil eine Lösung wurde mit Mutex schon genannt: Wie verhindert man, dass sich das Script selbst findet? Man müsste abfragen, ob zwei Prozesse mit dem Titel laufen...?!?
TK1987
TK1987 22.04.2020 aktualisiert um 10:49:51 Uhr
Goto Top
Moin,

Zitat von @NordicMike:
So nebenbei, weil eine Lösung wurde mit Mutex schon genannt: Wie verhindert man, dass sich das Script selbst findet?
Guck dir das If-Statement mal genau an... wie man verhindert das sich das Script selbst findet - gar nicht face-wink

Es wird nach Prozessen mit dem Titel gesucht und wenn von dem Output .Count größer 1 ist, also mehr als eine Instanz gefunden wurde, erfolgt der Return.

Gruß Thomas
NordicMike
NordicMike 22.04.2020 aktualisiert um 10:16:25 Uhr
Goto Top
Stimmt, der .count ist mir im Code gar nicht aufgefallen :c)