Wenn man eine Ansammlung mehrerer Tausend Dateien hat, welche unsortiert in einem Ordner abgelegt sind, kann es praktisch sein, diese Dateien nach Alter zu sortieren. Noch besser ist es, wenn man diese Aufgabe nicht manuell ausführen muss, sondern automatisiert – zum Beispiel per Windows PowerShell.
Mit der PowerShell automatisch Dateien archivieren
Im konkreten Fall ging es um ein Verzeichnis, in welchem seit fast zehn Jahren Ausgangsrechnungen als PDF-Dateien abgelegt wurden. Dort waren mehrere zehntausend Dateien zusammengekommen, wodurch Windows inzwischen äußerst träge reagierte, wenn man diesen Ordner aufrief. Die Idee war: Mittels eines PowerShell Skripts die Dateien nach Datum sortieren.
Das Archiv sollte nach Jahren aufgebaut sein und danach die Dateien nach Monaten abgelegt werden. Also einen Ordner für das Jahr (z.B. 2021) und darin mehrere Ordner für die Monate (01, 02, … 12). Ausschlaggebend sollte das Änderungsdatum der PDF-Datei sein.
Das fertige Skript sah dann folgendermaßen aus:
# Skript für die automatische Verteilung von Dateien nach deren Änderungsdatum
# Dateien werden in einen Archivordner verschoben und darin nach Jahr und Monat in Unterordnern sortiert.
# Dateiendungen sind frei wählbar
$tage = 7 # Dateien, die älter sind als dieser Wert (in Tagen) werden verschoben.
$quelle = "C:\Temp" # Dateien aus diesem Verzeichnis werden verschoben
$ziel = "C:\Temp\ARCHIV" # Basisverzeichnis für die Archive
$dateityp = "*.docx", "*.pdf" # Array erweiterbar durch ,"*.xyz"
$DatumVorXTagen = (Get-Date).AddDays(-$tage)
gci $quelle -PipelineVariable anzahl | where {$_.lastwritetime -lt $DatumVorXTagen -and -not $_.psiscontainer} | %{
gci $_.FullName -Filter * -include $dateityp -recurse -File | group {$_.LastWriteTime.ToString('yyyy\MM')} | %{
$zielordner = "$ziel$($_.Name)"
if(!(Test-Path $zielordner)){md $zielordner | out-null}
$_.Group | move-item -Destination $zielordner -Force -Verbose
}
}
Mit Parametern nur bestimmte Dateien nach Datum sortieren
Das Skript wurde noch dahingehend erweitert, dass einerseits nur die Dateien verschoben werden, die ein bestimmtes Alter erreicht haben, andererseits sollte der/die Dateitypen anpassbar sein.
- Variable $tage
Ist das Änderungsdatum der Datei älter als diese Anzahl Tage, wird die Datei verschoben und sortiert - Variable $quelle
Quellpfad der Dateien, die archiviert werden sollen (Unterordner werden nicht mit eingeschlossen) - Variable $ziel
Basispfad für das Dateiarchiv. Dort wird die Unterstruktur (Jahr – Monat) angelegt - Variable $dateityp
Angabe der Dateiendungen, die bei der Archivierung berücksichtigt werden sollen.
Das Skript kann anschließend z.B. per Aufgabenplanung automatisch zu festgelegten Zeiten ausgeführt werden. Dadurch werden zukünftig alle neuen Dateien nach Datum sortiert und in die entsprechenden Archivordner verschoben.
Ebenfalls interessant:
Dieser Artikel ist wie alle anderen auf dieser Seite kostenlos für Dich und ich hoffe, ich konnte Dir weiterhelfen. Wer möchte, kann diesem Blog eine kleine Aufmerksamkeit in Form einer kleinen Spende (PayPal) oder über die Amazon Wunschliste zukommen lassen.
Danke für diese anschaulichen Ausführungen. Änderungsdatum der Datei entspricht dem SaveTimeStamp, korrekt?
Danke OneDrive ist das ja leider nicht mehr unbedingt das Mass der Dinge (hier haben die Dateien leider des Öftern neue Zeitstempel bekommen, ohne dass sich inhaltlich die Datei geändert hat) Kenne Sie eine Möglichkeit, dass man die Dateien mit Ihrem Skript so sortieren kann, dass es nicht auf den Dateizeitstempel im Suchordner, sondern wirklich auf den realen Bearbeitungszeitstempel reagiert? Bei Bildern zB. würde man von Aufnahmedatum sprechen.
beste Grüsse
René
Hallo René,
bei Bildern sind diese Informationen in den EXIF-Daten gespeichert. Diese können meines Wissens (noch) nicht direkt ausgelesen werden. Eine kurze Suche bei Google zeigt, dass einige sich bereits mit dem Problem beschäftigt haben – möglicherweise findest Du irgendwo eine Funktion zum Importieren, die diese Daten ausliest.
Ansonsten gibt es neben „LastWriteTime“ noch die Attribute „CreationTime“ (Erstelldatum) und „LastAccessTime“ (Letzter Zugriff am). Eventuell hilft das ja bereits weiter.
Viele Grüße, René :-)
Hallo Réne,
vielen Dank für Dein Script!
Es ist genau das, was ich benötige, jedoch legt er mir keine Orderstruktur an =>
C:\test2\2020M10\TRA_200078.pdf“
Er erzeugt lediglich nur einen Ordner mit 2020M10..
Hinweis: Die Datei ist vom 15.10.2020
Auch wenn ich hier das Script änder =>“group {$_.LastWriteTime.ToString(‚yyyy.MM.dd)“
erzeugt er mir nur einen Ordner => C:\test2\2020.10.15\TRA_200078.pdf“.
Über schnelle Hilfe wäre ich sehr dankbar
VG
Hallo Rüdiger,
Das Skript legt nur Ordner für den Tag/Monat an, für den es auch Dateien gibt. Ich habe das gerade bei mir nochmal erfolgreich getestet: Ich hatte zwei Dateien (eine von 2021-09 und eine von 2021-08). Das Skript hat mir daraufhin 2 Ordner angelegt, in denen jeweils die Datei abgelegt wurde.
Wenn Du weiterhin Probleme damit hast, schick mir doch mal Dein Skript per E-Mail (siehe Impressum).
Grüße René
Hallo Réne,
vielen Dank für Deine schnelle Antwort!
Auch bei mir legt er 2 Ordner an, aber ich wünschte, er würde wie auf dem Screenshot von Dir zu sehen,
entsprechende Unterordner anlegen.
Also die *.pdf-Datei ist vom 15.10.2020 sollte er einen Ordner mit Jahr (2020) darin
ein Unterordner mit Monat und dann Tag erstellen und das PDF dorthin verschieben.
Da ich es hier mit extrem vielen Dateien zu tun habe, bräuchte ich diese Struktur.
Ahja, schön wäre es auch, wenn das Programm nicht nur das Startverzeichnis (bei mir „c:\test\“ sondern auch die Unterordner mit durchforstet :-)
=>
# Script von René Albarus
# https://www.tech-faq.net/dateien-nach-datum-sortieren-per-powershell/?unapproved=9431&moderation-hash=9751018b37f0f9cf11e1444d433a3a93#comment-9431
# Skript für die automatische Verteilung von Dateien nach deren Änderungsdatum
# Dateien werden in einen Archivordner verschoben und darin nach Jahr und Monat in Unterordnern sortiert.
# Dateiendungen sind frei wählbar
$tage = 7 # Dateien, die älter sind als dieser Wert (in Tagen) werden verschoben.
$quelle = „C:\test“ # Dateien aus diesem Verzeichnis werden verschoben
$ziel = „C:\test2\“ # Basisverzeichnis für die Archive
$dateityp = „*.docx“, „*.pdf“ # Array erweiterbar durch ,“*.xyz“
$DatumVorXTagen = (Get-Date).AddDays(-$tage)
gci $quelle -PipelineVariable anzahl | where {$_.lastwritetime -lt $DatumVorXTagen -and -not $_.psiscontainer} | %{
gci $_.FullName -Filter * -include $dateityp -recurse -File | group {$_.LastWriteTime.ToString(‚yyyy.MM.dd‘)} | %{
$zielordner = „$ziel$($_.Name)“
if(!(Test-Path $zielordner)){md $zielordner | out-null}
$_.Group | move-item -Destination $zielordner -whatif
}
}
Vielen Dank Réne!
Hi,
das Problem liegt vermutlich darin, dass der Wert in der Klammer von LastWriteTime.To.String in zwei Hochmommas stehen muss. In Deinem Beispiel ist das erste Komma unten. Es muss also z.B. heißten (yyyy\\MM\dd) -> Damit legt er für das Jahr, den Monat und den Tag jeweils einen neuen Ordner an. Bitte versuche das mal.
Die Unterordner kannst Du auch „mitnehmen“ dafür einfach hinter „gci $quelle“ ein „-recurse“ setzen, also -> gci $quelle -recurse -PipelineVariable anzahl ….
Hallo Réne,
vielen Dank. Mit den Hochkommas war wohl eher ein „copy-paste“-Fehler, mit (yyyy\\MM\\dd) (Allerdings mit 2 \\ )
und den -recurse hat es nun geklappt.
Vielen Dank nochmals für Deine kompetente Hilfe!
VG
Freut mich, dass es jetzt funktioniert hat. VG