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-Key: 566186

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

Printed on: April 19, 2024 at 23:04 o'clock

Member: SlainteMhath
Solution SlainteMhath Apr 20, 2020 at 12:55:18 (UTC)
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
Member: jan-markus
jan-markus Apr 20, 2020 at 13:45:58 (UTC)
Goto Top
Klasse! Genau die Art Stupser brauchte ich! Klar, ein lockfile!
Vielen Dank! face-smile
Member: manuel-r
Solution manuel-r Apr 20, 2020 at 14:27:34 (UTC)
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
Member: jan-markus
jan-markus Apr 20, 2020 at 16:35:25 (UTC)
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!
Member: jan-markus
jan-markus Apr 20, 2020 at 19:13:10 (UTC)
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.
Member: manuel-r
Solution manuel-r Apr 20, 2020 updated at 19:42:07 (UTC)
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
Member: filippg
Solution filippg Apr 20, 2020 at 21:39:04 (UTC)
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
Member: TK1987
Solution TK1987 Apr 21, 2020 updated at 07:46:17 (UTC)
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
Member: jan-markus
jan-markus Apr 21, 2020 at 10:15:25 (UTC)
Goto Top
Ein wirklich dickes DANKE! nochmal an ALLE für die zahlreichen, auch unterschiedlichen Ansätze, zur Lösung!
Member: jan-markus
jan-markus Apr 21, 2020, updated at Apr 22, 2020 at 05:31:22 (UTC)
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.
Member: TK1987
TK1987 Apr 21, 2020 updated at 12:18:41 (UTC)
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.
Member: jan-markus
jan-markus Apr 22, 2020 at 05:30:19 (UTC)
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
Member: NordicMike
NordicMike Apr 22, 2020 at 07:56:05 (UTC)
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...?!?
Member: TK1987
TK1987 Apr 22, 2020 updated at 08:49:51 (UTC)
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
Member: NordicMike
NordicMike Apr 22, 2020 updated at 08:16:25 (UTC)
Goto Top
Stimmt, der .count ist mir im Code gar nicht aufgefallen :c)