Script soll sich nur einmal starten lassen
Hallo Forum.
Ich habe ein Script auf einem Server abgelegt. Dieses Script kann von verschiedenen PCs gestartet werden. Allerdings darf es nicht parallel ausführbar sein. Wie kann man so etwas realisieren?
Es sollte nach Möglichkeit so aufgebaut sein das es auch nach einem Softwareabsturz funktionsfähig ist.
Ich freue mich schon auf neuen Input.
Gruß
Christoph
Ich habe ein Script auf einem Server abgelegt. Dieses Script kann von verschiedenen PCs gestartet werden. Allerdings darf es nicht parallel ausführbar sein. Wie kann man so etwas realisieren?
Es sollte nach Möglichkeit so aufgebaut sein das es auch nach einem Softwareabsturz funktionsfähig ist.
Ich freue mich schon auf neuen Input.
Gruß
Christoph
Please also mark the comments that contributed to the solution of the article
Content-ID: 668397
Url: https://administrator.de/contentid/668397
Printed on: October 15, 2024 at 16:10 o'clock
14 Comments
Latest comment
Klar kannst du da auch Statusinformationen rein schreiben. Softwarefehler sollte man im Skript auch immer mit Try Catch abfangen. Mit Get-Process bzw. via Win32_Process und WMI kannst du laufende Prozesse auch remote abfragen.
Mit Parametern kannst du auch steuern ob man die Status-Datei forciert löscht wenn abgestürzt. Viele Wege führen nach Rom...
Mit Parametern kannst du auch steuern ob man die Status-Datei forciert löscht wenn abgestürzt. Viele Wege führen nach Rom...
Moin,
lasse das Script mit einem Parameter aufrufen:
wird
Wird es weggelassen, wird der Anwender/ Admin vermöbelt, weil er den Parameter nicht mitgegeben hat.
lasse das Script mit einem Parameter aufrufen:
myScript.ps1 -Startmode cleanup
sorgt beim Start des Rechner dafür, dass die Statusdatei gelöscht wirdwird
myScript.ps1
ohne den Parameter aufgerufen (oder mit -Startmode normal
), läuft es normal durch.Wird es weggelassen, wird der Anwender/ Admin vermöbelt, weil er den Parameter nicht mitgegeben hat.
Hi,
lass das Script während des Laufs diese Status-Datei immer wieder aktualisieren.
Beim Start des Scripts prüfts Du, ob diese Datei vorhanden ist. Wenn ja, ob der LastWrite-Zeitstempel aktuell ist (max. Alter musst Du Dir festlegen).
Wenn nicht vorhanden oder Zeitstempel zu alt, dann Script fortsetzen, sonst abbrechen.
E.
lass das Script während des Laufs diese Status-Datei immer wieder aktualisieren.
Beim Start des Scripts prüfts Du, ob diese Datei vorhanden ist. Wenn ja, ob der LastWrite-Zeitstempel aktuell ist (max. Alter musst Du Dir festlegen).
Wenn nicht vorhanden oder Zeitstempel zu alt, dann Script fortsetzen, sonst abbrechen.
E.
Kannst Du hierzu bitte mal ein Beispiel für einstellen? Mit remote habe ich bisher noch nie gearbeitet.
Get-CimInstance Win32_Process -ComputerName XXXXXX -Filter "Name = 'blablub.exe'"
Würde es aber persönlich ohne das Remote-Gedöns so abfackeln
# status file
$statusfile = "\\server.domain.tld\share\status.tok"
# maximum time a process is allowed to run
$maxwaitseconds = 1800
$erroractionpreference = 'Stop'
# check if file exists
if (Test-Path $statusfile -PathType leaf){
# if file last modified older than x seconds, delete file
if ((Get-Item $statusfile).LastWriteTime -lt (get-date).AddSeconds(-$maxwaitseconds)){
Remove-Item $statusfile -force
}else{
# other script still running, exit script
exit
}
}
# set statusfile
"User '$env:USERNAME' running process on machine '$env:COMPUTERNAME'" | set-content $statusfile
try{
# run actions here
$cmd = start-process "D:\Pfad\zum\Programm.exe" -PassThru
# check process continously while running
$start = get-date
while(!$cmd.HasExited){
write-host "Waiting for process to finish ..."
# if process runs longer than x seconds, forcefully end process and throw error
if(((get-date)-$start).TotalSeconds -ge $maxwaitseconds -or !$cmd.Responding){
$cmd | stop-process -Force
throw "Process did not finish in time or did not respond, process killed!"
}
sleep 1
}
write-host "Worker finished."
}catch{
# write error
write-host $_.Exception.Message -F Red
}finally{
# remove status file
Remove-Item $statusfile -force
}
Mit Get-Process bzw. via Win32_Process und WMI kannst du laufende Prozesse auch remote abfragen.
Das macht aber auch nur Sinn, wenn man alle in Frage kommende Computer abfragt und dann auch noch für all diese die entsprechenden Berechtigungen hat. Also wohl eher nicht praktikabel.Wenn man über Freigabe ein Script startet, dann läuft dieses doch nicht auf dem Server sondern auf dem Client, wo man es startet.
Was auch nich eine Variante wäre:
Das Script läuft nur auf genau einem Computer. Und der Anwender löst den Start des Scripts auf diesem Client aus. Das Script kann jetzt lokal die laufenden Prozesse prüfen, und wenn es schon läuft, dann wieder abbrechen.
Auch dafür gäbe es dann auch verschiedene Möglichkeiten der Umsetzung.
Eine wäre z.B. ein Sheduled Task auf diesem einen ausführenden Server. Der Anwender muss dann in der lage sein, diesen Scheduled Task remote auszulösen. Am Task könnte man einstellen, dass dieser nur in einer Instanz laufen darf. Als Trigger für diesen Task könnte z.B. das Erstellen einer definierten Datei sein. Wenn man NTFS überwacht, dann würde das einen Eventlog-Eintrag auf diesem Computer auslösen. Und an diesen Eventlog-Eintrag könnte man den Task anpflanschen.
Viele Wege führen nach Rumänien.
Oder ein Scheduled Task auf diesem einen Computer mit diesem Script. Auslösung jede Minute einmal. Nur eine Instanz zulassen.
Das Script prüft Existenz einer Datei, welche vom Anwender erstellt werden kann. Wenn Datei nicht vorhanden, dann Script beenden. Wenn vorhanden, dann Script fortsetzen. Dabei als erstes diese Datei löschen.
Selbst wenn jetzt während des Laufs jemand anderer diese Datei wieder erstellt, würde das Script doch frühestens dann erneut gestartet werden, wenn es gerade nicht läuft und der Task zum nächsten Intervall wieder gestartet wird.
Das Script prüft Existenz einer Datei, welche vom Anwender erstellt werden kann. Wenn Datei nicht vorhanden, dann Script beenden. Wenn vorhanden, dann Script fortsetzen. Dabei als erstes diese Datei löschen.
Selbst wenn jetzt während des Laufs jemand anderer diese Datei wieder erstellt, würde das Script doch frühestens dann erneut gestartet werden, wenn es gerade nicht läuft und der Task zum nächsten Intervall wieder gestartet wird.
Hallo,
z.B. auch so. Hängt alles, bzw. wird die Lck nciht gelöscht, so wird nach einer gewissen Zeit der Lock übergangen und die Datei gelöscht und neu angelegt.
Die Methode von @em-pie kommt mir noch eleganter vor. Hat auch was
z.B. auch so. Hängt alles, bzw. wird die Lck nciht gelöscht, so wird nach einer gewissen Zeit der Lock übergangen und die Datei gelöscht und neu angelegt.
Die Methode von @em-pie kommt mir noch eleganter vor. Hat auch was
Function CreateLckFile() {
$null = New-Item -ItemType "file" -Path $lckFile;
# Fix NTFS Tunnellig
$(Get-Item -Force $lckFile).CreationTime = $(Get-Item -Force $lckFile).LastWriteTime;
}
Function LckTimeDiff() {
$lckFileCreationTime = $((Get-Item $lckFile).CreationTime)
$Diffobj = $(Get-Date) - $lckFileCreationTime
[int]$Script:DiffInMin = [int]$Diffobj.TotalMinutes
}
Function LckAndStart() {
if (! (Test-path -path $lckFile)) {
CreateLckFile
............
Remove-Item $lckFile -Force
} else {
LckTimeDiff
IF ($DiffInMin -gt 10 ) {
WriteLog "Alte Lck vorhanden"
Remove-Item $lckFile -Force
CreateLckFile
........
}
}
per VBS Script hab ich solche checks schon gemacht, z.B. ob ein MSI Install File gerade noch aktiv ist dann warten im loop
Das kann man natürlich anpassen stat msiexec.exe ne andere exe checken
If Instr.... ist quasi if Like
If Not Instr... ist if not like
hier im beispiel doppel IF abfrage weil eben msiexec auch als dienst läuft mit /V als Parameter und die interessiert hier nicht bei der abfrage. bedeutet bei dir reicht nur ein IF exe am laufen quasi...
und mit
Kann man den Prozess auch killen
'################### Check if MSI is running START###################
Dim ActiveInstall, strComputer, ProcessCommandLine, Answer, WshShell
ActiveInstall = 1
Set WshShell = WScript.CreateObject("WScript.Shell")
do while ActiveInstall = 1
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colProcessList = objWMIService.ExecQuery _
("Select * from Win32_Process")
ActiveInstall = 0
For Each objProcess in colProcessList
'wscript.echo objProcess.CommandLine
ProcessCommandLine = objProcess.CommandLine
If Instr(1, ProcessCommandLine, "msiexec.exe") > 0 Then
If NOT Instr(1, ProcessCommandLine, "/V") > 0 Then
'wscript.echo "Prozess gefunden! " & ProcessCommandLine
ActiveInstall = 1
'Answer = WshShell.Popup("MSIEXEC.exe in use, waiting 10 Secounds before trying to continue....", 10, "Info", 0 + 64)
Wscript.echo (Time) & " MSI Found - waiting 5 Secounds"
Wscript.sleep 5000
End If
End If
Next
loop
'###################### Check if MSI is running END################
Das kann man natürlich anpassen stat msiexec.exe ne andere exe checken
If Instr.... ist quasi if Like
If Not Instr... ist if not like
hier im beispiel doppel IF abfrage weil eben msiexec auch als dienst läuft mit /V als Parameter und die interessiert hier nicht bei der abfrage. bedeutet bei dir reicht nur ein IF exe am laufen quasi...
und mit
If Instr(1, objProcess.CommandLine, "Gesuchte.exe") > 0 Then
wscript.echo "Prozess gefunden! " & objProcess.CommandLine
objProcess.Terminate()
End If
Kann man den Prozess auch killen