Kleines Entpack-Script
Hallo zusammen,
ich bin auf der Suche nach einem einfachen kleinen Script.
Soll: Einen lokalen Ordner überwachen, warten, bis eine ZIP-Datei erstellt wird (mit beliebigem Namen) und diese soll dann ins gleiche Verzeichnis entpackt werden und die ZIP soll im Anschluss automatisch gelöscht werden.
Ich habe folgendes versucht, basierend darauf: https://it-learner.de/mithilfe-der-windows-powershell-einen-ordner-bzw-e ...
Das funktioniert manchmal. Dann aber auch wiederum nicht. Ein anderes Mal konnte ich 10 mal die ZIP Datei kopieren, entpacken und wieder löschen lassen, beim 11. Mal ging es dann plötzlich nicht mehr.
Was mache ich falsch? Gibt es einen einfacheren Weg? Die Ausgaben sind nice-to-have, wichtiger wäre die Grundfunktion des Scripts.
Kann mir jemand helfen? I
Danke!
MfG
ich bin auf der Suche nach einem einfachen kleinen Script.
Soll: Einen lokalen Ordner überwachen, warten, bis eine ZIP-Datei erstellt wird (mit beliebigem Namen) und diese soll dann ins gleiche Verzeichnis entpackt werden und die ZIP soll im Anschluss automatisch gelöscht werden.
Ich habe folgendes versucht, basierend darauf: https://it-learner.de/mithilfe-der-windows-powershell-einen-ordner-bzw-e ...
# Variablen definieren
$ordner = 'D:\Pfad\zum\Ordner'
$timeout = 10
$DateiFilter = '*.zip'
Write-Host $ordner
$zipwatcher = New-Object System.IO.FileSystemWatcher $ordner, $DateiFilter
# Manueller Abbruch der Schleife
Write-Host „Mit CTRL+C kann das Monitoring abgebrochen werden.“
Remove-Item -Path $ordner'\*.zip' #für den Fall, dass schon eine ZIP existiert
while ($true) {
$result = $zipwatcher.WaitForChanged(‚all‘, $timeout)
if ($result.TimedOut -eq $false)
{
Write-Host ('ZIP {0}: {1}‘ -f $result.ChangeType, $result.name) #veränderte ZIP-Datei anzeigen
Expand-Archive -Path $ordner'\*.zip' -DestinationPath $ordner -Force #ZIP entpacken
Write-Host $result.name ' entpackt'
Start-Sleep -Seconds 5
Remove-Item -Path $ordner'\*.zip' # ZIP löschen
Write-Host $result.name ' gelöscht'
} #end if
} #end while
Write-Host „Monitoring abgebrochen.“
Was mache ich falsch? Gibt es einen einfacheren Weg? Die Ausgaben sind nice-to-have, wichtiger wäre die Grundfunktion des Scripts.
Kann mir jemand helfen? I
Danke!
MfG
Bitte markiere auch die Kommentare, die zur Lösung des Beitrags beigetragen haben
Content-ID: 6543517771
Url: https://administrator.de/contentid/6543517771
Ausgedruckt am: 21.11.2024 um 22:11 Uhr
8 Kommentare
Neuester Kommentar
Moin,
da steht alles beschrieben: https://powershell.one/tricks/filesystem/filesystemwatcher
Es wird daran liegen, das der Watcher die Änderung schlicht "übersieht". Das Start-Sleep wird das Problem sogar noch verschlimmern.
da steht alles beschrieben: https://powershell.one/tricks/filesystem/filesystemwatcher
Es wird daran liegen, das der Watcher die Änderung schlicht "übersieht". Das Start-Sleep wird das Problem sogar noch verschlimmern.
https://powershell.one/tricks/filesystem/filesystemwatcher
Der hat sich viele Gedanken zum Watcher gemacht.
Alternativ kannst du auch so ZIP prüfen und entpacken. Entweder Lock prüfen - ob die noch geschrieben wird - oder Sagen es soll nur Dateien nehmen die mindestens 5 min. alt sind. Dann sollten die - je nach Größe - vollständig geschrieben sein und keinen Lock aufweisen. Ab da dann wieder normal weiter.
Schleife oder Task der alle 5 min. prüft. Je nachdem, wie Zeitkritisch es sein soll.
Für Backup hab ich immer selber eine Lock File erstellt. Um zu verhindern das Task erneut ausgeführt wird, wenn der alten noch laufen/ hängen sollte. Wurde eine gewisse Zeit überschritten, wurden die Altlasten entsorgt und Lock gelöscht. Dann war wieder alles soweit für einen erneuten Aufruf.
"Hotfolder" Überwachung ist schön, hat aber so seine Tücken. Man kann es auch anders lösen.
Der hat sich viele Gedanken zum Watcher gemacht.
Alternativ kannst du auch so ZIP prüfen und entpacken. Entweder Lock prüfen - ob die noch geschrieben wird - oder Sagen es soll nur Dateien nehmen die mindestens 5 min. alt sind. Dann sollten die - je nach Größe - vollständig geschrieben sein und keinen Lock aufweisen. Ab da dann wieder normal weiter.
Schleife oder Task der alle 5 min. prüft. Je nachdem, wie Zeitkritisch es sein soll.
Für Backup hab ich immer selber eine Lock File erstellt. Um zu verhindern das Task erneut ausgeführt wird, wenn der alten noch laufen/ hängen sollte. Wurde eine gewisse Zeit überschritten, wurden die Altlasten entsorgt und Lock gelöscht. Dann war wieder alles soweit für einen erneuten Aufruf.
"Hotfolder" Überwachung ist schön, hat aber so seine Tücken. Man kann es auch anders lösen.
ja, kann ich.
Wenn dein Skript wo auch immer einen entsprechenden Fehler wirft, wird es sich beenden und du bekommst das nicht einmal mit.
while ($true) ist igitt - es gibt eigentlich kein Fall, wo dass Sinn ergibt.
Du brauchst also ein Skript, welches alle 5 Minuten ausgeführt wird. Dann bau das auch. Nutze die Aufgabenplanung.
Dann nimmst du deine Zips, und prüfst, ob die Datei noch geöffnet ist.
Habe mal schnell was aus dem Internet kopiert und nicht getestet:
Function Confirm-FileInUse {
Param (
[parameter(Mandatory = $true)]
[string]$filePath
)
try {
$x = [System.IO.File]::Open($filePath, 'Open', 'Read') # Open file
$x.Close() # Opened so now I'm closing
$x.Dispose() # Disposing object
return $false # File not in use
}
catch [System.Management.Automation.MethodException] {
return $true # Sorry, file in use
}
}
Wenn die Datei nicht gesperrt ist, entpackst du diese und löscht die danach. Ein Sleep ist nicht notwendig.
Dann garnierst du das Ganze noch mit einem ordenlichen Log und fertig ist der Zauber
"Billig" ist egal !
Ich achte bei sowas immer darauf dass es robust läuft. Ein "toll, super" wirst du eh nicht bekommen. Nur Ärger wenn es nicht sauber läuft. Von daher alles gut. Hübsch machen kann man den Code ggf. noch - einrücken. Das sollte es dann gewesen sein.
Hier nochmal 2 Funktionen die ich verwende um den Scheduled Task vor einen "runaway" zu schützen. Prüfung auf Lock File verhindert dass Task - der z.B. alle 5 min. läuft - gestartet wird, wenn der davor noch nicht fertig ist. Gerade auch bei Datei Operationen wäre das nicht so schön.
Nur irgendwann passiert sowas vlt. doch mal. Wie dann auflösen? Ganzen Server neustarten oder Mails versenden? Je nach Vorgang kann man ggf. mit taskkill dann die alten Dinger weghauen. Was ist aber mit der Lockfile? Hier unterstelle ich das nach über 10 min. alles gut ist. Die wird dann gelöscht und neu erstellt. Somit würde sich je nach schwere des Problems das Ganze von selber auflösen.
Kommt aber stark auf die Tasks an. Manche haben ja naturbedingt einen Timeout. Wenn wir z.B. einen Webservice konsumieren.
Noch sauberer wäre es wohl, wenn man die Prozess ID festhält und nur diesen später ggf. hart killt.
[System.Diagnostics.Process]::GetCurrentProcess().Id
Wenn man das noch in die Lock Datei schreibt hätte man eine eindeutig Referenz. Wenn die PS natürlich anddre Prozesse anstößt und die nicht im gleichen Context laufen muss man die noch behandeln.
Nur so eine Idee! Aber mit Lock-Files und Process ID kannst du es noch etwas absichern. Dann eben alle 5 min. starten. Ist ja kein Java Bei C# haben wir ja auch einen Garbarge Collector!
Ansonsten versuchen immer sauber zu beenden. Zu jedem MS SQL Connect gehört auch ein Disconnect. Wenn du später noch an solche Sachen denkst sollte das ganze den RAM nicht sprenge. Oder gar 1.000 "Kopien" auf einmal offen sein.
Nur so Gedanken ....
Ich achte bei sowas immer darauf dass es robust läuft. Ein "toll, super" wirst du eh nicht bekommen. Nur Ärger wenn es nicht sauber läuft. Von daher alles gut. Hübsch machen kann man den Code ggf. noch - einrücken. Das sollte es dann gewesen sein.
Hier nochmal 2 Funktionen die ich verwende um den Scheduled Task vor einen "runaway" zu schützen. Prüfung auf Lock File verhindert dass Task - der z.B. alle 5 min. läuft - gestartet wird, wenn der davor noch nicht fertig ist. Gerade auch bei Datei Operationen wäre das nicht so schön.
Nur irgendwann passiert sowas vlt. doch mal. Wie dann auflösen? Ganzen Server neustarten oder Mails versenden? Je nach Vorgang kann man ggf. mit taskkill dann die alten Dinger weghauen. Was ist aber mit der Lockfile? Hier unterstelle ich das nach über 10 min. alles gut ist. Die wird dann gelöscht und neu erstellt. Somit würde sich je nach schwere des Problems das Ganze von selber auflösen.
Kommt aber stark auf die Tasks an. Manche haben ja naturbedingt einen Timeout. Wenn wir z.B. einen Webservice konsumieren.
Noch sauberer wäre es wohl, wenn man die Prozess ID festhält und nur diesen später ggf. hart killt.
[System.Diagnostics.Process]::GetCurrentProcess().Id
Wenn man das noch in die Lock Datei schreibt hätte man eine eindeutig Referenz. Wenn die PS natürlich anddre Prozesse anstößt und die nicht im gleichen Context laufen muss man die noch behandeln.
Nur so eine Idee! Aber mit Lock-Files und Process ID kannst du es noch etwas absichern. Dann eben alle 5 min. starten. Ist ja kein Java Bei C# haben wir ja auch einen Garbarge Collector!
Ansonsten versuchen immer sauber zu beenden. Zu jedem MS SQL Connect gehört auch ein Disconnect. Wenn du später noch an solche Sachen denkst sollte das ganze den RAM nicht sprenge. Oder gar 1.000 "Kopien" auf einmal offen sein.
Nur so Gedanken ....
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
WriteLog "Lck Erstellt"
RestartBMV
WriteLog "Restart abgeschlossen"
Remove-Item $lckFile -Force
} else {
LckTimeDiff
IF ($DiffInMin -gt 10 ) {
WriteLog "Alte Lck vorhanden"
Remove-Item $lckFile -Force
CreateLckFile
WriteLog "Lck neu erstellt"
RestartBMV
WriteLog "Restart abgeschlossen"
Remove-Item $lckFile -Force
}
}
}
Noch eine Ergänzung! Schreib Log Files! dann bekommst du es einfacher mit, wenn was schief geht. Nutze eine Function und häng es dran.
try .... ist ja bekannt. if(-not $?) mit $error[0].exception.message liefert auch brauchbare Fehlermeldungen.
Ggf. das in Kombination einbauen. Fehlerbehandlung könnte sein die Dateien zu verschieben und Lock zu releasen. Oder eine E-Mail abzusetzen.
So oder so würde ich mehr Wert auf das Error Handling an deiner Stelle legen. Vermutlich bringt dir das mehr, als wenn das System durch Dauerschleifen an seine Grenzen kommen würde. Wenn du - wie auch von @Kraemer erwähnt - ein Script alle 5 Minuten ausführst sollte nicht viel passieren.
Error Handling, doppelte Ausführung verhindern - das würde ich dann als "robustes Script" verstehen.
Arbeite mit Functions. Die tun nicht weh. Einmal diese paar 5 Zeiler da abgesetzt und alles ist rund. Der Call ist ja nur ein Wort. Mitunter muss nicht mal ein Parameter mitgegeben werden.
Zack fertig.
Function Script:WriteLog() {
Param ([string]$LogString)
$LogFile = "C:\logs\$(gc env:computername).log"
$DateTime = "[{0:dd/MM/yyyy} {0:HH:mm:ss}]" -f (Get-Date)
$LogMessage = "$Datetime $LogString"
Add-content $LogFile -value $LogMessage
}
Move-Item -Path $zipFileName -Destination d:\ -ErrorAction SilentlyContinue
if(-not $?) { $Script:MOVEErrorMsg = "Copy Failed: " + $error[0].exception.message }
try .... ist ja bekannt. if(-not $?) mit $error[0].exception.message liefert auch brauchbare Fehlermeldungen.
Ggf. das in Kombination einbauen. Fehlerbehandlung könnte sein die Dateien zu verschieben und Lock zu releasen. Oder eine E-Mail abzusetzen.
So oder so würde ich mehr Wert auf das Error Handling an deiner Stelle legen. Vermutlich bringt dir das mehr, als wenn das System durch Dauerschleifen an seine Grenzen kommen würde. Wenn du - wie auch von @Kraemer erwähnt - ein Script alle 5 Minuten ausführst sollte nicht viel passieren.
Error Handling, doppelte Ausführung verhindern - das würde ich dann als "robustes Script" verstehen.
Arbeite mit Functions. Die tun nicht weh. Einmal diese paar 5 Zeiler da abgesetzt und alles ist rund. Der Call ist ja nur ein Wort. Mitunter muss nicht mal ein Parameter mitgegeben werden.
Zack fertig.