none
Alte Daten löschen nach x Tagen, aber Schnell.... RRS feed

  • Frage

  • Hallo zusammen

    Simple Aufgabe und bestimmt nicht neu, jedoch weiss ich nicht nach was ich suchen muss

    Ausganslage:
    In einem Verzeichnis sollen alle Datei älter x Tage gelöscht werden. Das heisst ich darf den Ordner nicht einfach löschen. Jedoch sind da 500'000+ Dateien in der Struktur.

    Der Ansatz ist aktuell:
    Dateien "einzeln" raussuchen und löschen. Was einfach ewig dauert.

    Kann ich das auf einfache weise Parallel abfahren?
    Ist mein Code so schlecht? :(

    Danke

    Gruss Tobias

    $DatumVor1Tagen = (Get-Date).AddDays(-1)
    
    $ProtokollPfad = "c:\temp\"
    $Counter = 0
    
    
    
    #Quellen zum löschen
    #Älter 1 Tag: Alle Quellen die nach einem Tage gelöscht werden sollen.@("path1","path2","path3")
    $Source_1day = @("\\m\a\c\Test02","\\m\a\c\Test03")
    
    
    
    
    #Protokoll 
    start-transcript "$ProtokollPfad $(get-date -format MMddyyHHmmss).txt" 
    
    #Löschen was älter ist als ein Tag aus $Source_1day
    ForEach ($Source in $Source_1day)
    {
        get-childitem "$Source" -recurse | where {$_.lastwritetime -lt $DatumVor1Tagen -and -not $_.psiscontainer} |% {remove-item $_.fullname -force -verbose }
       
    }
    
    

    Mittwoch, 19. September 2018 13:54

Antworten

  • Das Erstellen der Liste lässt sich leider nicht parallelisieren, da die Gefahr der mehrfachen Einträge gegeben ist.
    Du kannst allerdings die Aufgabe in mehrere Schritte zerlegen.

    Statt der option "-recurse" solltest du nach Dateien und Verzeichnissen trennen.
    Im ersten Schritt alle Dateien eines Verzeichnisses ermitteln und in ein Array laden.
    Mittels Start-Job kannst du dann das Array übergeben und dann im Hintergrund die gefundenn Dateien löschen.
    Dein Script rennt dann weiter und kann nun die Verzeichnisse durchgehen.

    Je Verzeichnis machst du dann denselben Vorgang, zuerst die Dateien, dann wieder Verzeichnis je Verzeichnis.

    Um das ganze zu vereinfachen, machst du das in einer Funktion, die als Parameter das Startvereichnis bekommt und sich mit den Subverzeichnissen dann rekursiv aufruft.

    Somit hast du dann viele parallele Jobs, die sich dann individuell um das anschließende Löschen kümmern.

    https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/start-job?view=powershell-6

    Um noch einen drauf zu setzen, kann man ein Array auch noch parallel verarbeiten lassen:
    https://technet.microsoft.com/de-de/library/jj713711.aspx?f=255&MSPPError=-2147217396

    Mittels "foreach -parallel" lässt sich das Löschen innerhalb eines Jobs noch mal parallelisieren, da die Runtime für die Verteilung nach Prozessoranzahl sorgt.
    Zusätzlich könnte man auch das Abarbeiten der Subverzeichnisse ebenso mittels -parallel durchführen, allerdings wird das eher kontraproduktiv, da die Parallellibrary nach Möglichkeit eben nicht mehr Threads als CPU's startet und dann eher Warteschleifen einzieht.

    Mittwoch, 19. September 2018 14:32

Alle Antworten

  • Das Erstellen der Liste lässt sich leider nicht parallelisieren, da die Gefahr der mehrfachen Einträge gegeben ist.
    Du kannst allerdings die Aufgabe in mehrere Schritte zerlegen.

    Statt der option "-recurse" solltest du nach Dateien und Verzeichnissen trennen.
    Im ersten Schritt alle Dateien eines Verzeichnisses ermitteln und in ein Array laden.
    Mittels Start-Job kannst du dann das Array übergeben und dann im Hintergrund die gefundenn Dateien löschen.
    Dein Script rennt dann weiter und kann nun die Verzeichnisse durchgehen.

    Je Verzeichnis machst du dann denselben Vorgang, zuerst die Dateien, dann wieder Verzeichnis je Verzeichnis.

    Um das ganze zu vereinfachen, machst du das in einer Funktion, die als Parameter das Startvereichnis bekommt und sich mit den Subverzeichnissen dann rekursiv aufruft.

    Somit hast du dann viele parallele Jobs, die sich dann individuell um das anschließende Löschen kümmern.

    https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/start-job?view=powershell-6

    Um noch einen drauf zu setzen, kann man ein Array auch noch parallel verarbeiten lassen:
    https://technet.microsoft.com/de-de/library/jj713711.aspx?f=255&MSPPError=-2147217396

    Mittels "foreach -parallel" lässt sich das Löschen innerhalb eines Jobs noch mal parallelisieren, da die Runtime für die Verteilung nach Prozessoranzahl sorgt.
    Zusätzlich könnte man auch das Abarbeiten der Subverzeichnisse ebenso mittels -parallel durchführen, allerdings wird das eher kontraproduktiv, da die Parallellibrary nach Möglichkeit eben nicht mehr Threads als CPU's startet und dann eher Warteschleifen einzieht.

    Mittwoch, 19. September 2018 14:32
  • In einem Verzeichnis sollen alle Datei älter x Tage gelöscht werden.

    Muss es Powershell sein? Robocopy kann das out of the box und arbeitet multithreaded.

    Kann ich das auf einfache weise Parallel abfahren?

    Das hilft nur, wenn das Dateisystem drunter (bzw. der Datenträger) dann nicht zum Flaschenhals wird. Die Wahrscheinlichkeit dafür ist aber sehr hoch.

         get-childitem "$Source" -recurse | where {$_.lastwritetime -lt $DatumVor1Tagen -and -not $_.psiscontainer} |% {remove-item $_.fullname -force -verbose }

    Pipe ist schlecht für die Performance. Ganz schlecht. Schneller ist Foreach ($file in $files){}

    • Als Antwort vorgeschlagen Evgenij Smirnov Mittwoch, 19. September 2018 18:06
    Mittwoch, 19. September 2018 16:08
  • Warum immer Drittprodukte wenn es die PowerShell ebenso kann.
    Und außerdem ist es eine nette Fingerübung.

    Schließlich schlagt ihr ja auch häufig genug Powershell als Lösung vor.

    Donnerstag, 20. September 2018 06:45
  • Warum immer Drittprodukte wenn es die PowerShell ebenso kann.
    Und außerdem ist es eine nette Fingerübung.

    Schließlich schlagt ihr ja auch häufig genug Powershell als Lösung vor.

    Robocopy ist kein Drittprodukt. Es war bereits Teil der Betriebssystems-Distribution, als PowerShell noch extra installiert werden musste.

    Es ist halt einfach nur Fakt, dass, wenn man große Operationen über NTFS-Dateisysteme machen muss, es zwar vergleichbar leistungsfähige, robuste und schnelle Utilities gibt, aber keine *besseren*.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Donnerstag, 20. September 2018 08:08
  • Moin,

    ich wage einmal zu bezweifeln (ohne es jetzt geprüft zu haben), dass 500.000x Get-Item aufrufen irgendwas mit "schnell" zu tun hätte.

    Wenn man schon in .NET-Klassen reingeht, dann würde man 

    if ([System.IO.Directory]::GetLastWriteTime($File) -lt $DatumVor1Tagen) {...}
    schreiben. Dann besorgt man sich nur genau die Property, die man braucht, und nicht das ganze Objekt und dann auch noch über einen Provider.


    Evgenij Smirnov

    I work @ msg services ag, Berlin -> http://www.msg-services.de
    I blog (in German) @ http://it-pro-berlin.de
    my stuff in PSGallery --> https://www.powershellgallery.com/profiles/it-pro-berlin.de/
    Exchange User Group, Berlin -> https://exusg.de
    Windows Server User Group, Berlin -> http://www.winsvr-berlin.de
    Mark Minasi Technical Forum, reloaded -> http://newforum.minasi.com


    In theory, there is no difference between theory and practice. In practice, there is.

    Donnerstag, 20. September 2018 08:15
  • Ob der Unterschied hier so groß sein wird bleibt auszutesten.
    Immerhin muss ja sowieso in beiden Fällen das Objekt (Datei, Verzeichnis) gelesen werden um die Attribute auslesen zu können. Ein Zugriff auf das File-Objekt muss also sowieso erfolgen.
    Da Powershell .Net-basiert ist, könnte nämlich Get-Item (was ja sehr allgemein für alles Mögliche herhalten muss) auf Verzeichnisse die System.IO-Klassen sowieso bemühen.

    Ergänzend mit einem

    foreach -parallel (...)

    wäre durch multithreading ggf. eine Performancesteigerung möglich, wenn das Filesystem das nicht wegen interner Synchronisierung ausbremst. Daher meine Empfehlung, dies je Verzeichnis getrennt zu gestalten.

    Donnerstag, 20. September 2018 08:43
  • > Ob der Unterschied hier so groß sein wird bleibt auszutesten.

    Ja, bleibt auszutesten - wird aber so sein. Ich erinnere mich an einen Vortrag auf der Powershell Conference 2016 genau über die Geschwindigkeit beim Dateihandling, und da landet Powershell sehr weit hinten, .NET (C#) ein wenig weiter vorne und Win32 (PInvoke) weit vorne. Noch schneller geht es dann mit direktem Zugriff auf NTFS-Datenstrukturen über PowerForensics.

    https://github.com/psconfeu/2016/tree/master/%C3%98yvind%20Kallstad/ChasingTheSeconds

    Donnerstag, 20. September 2018 14:11