Fotolia

Dateien und Ordner mit PowerShell automatisch verwalten

Mit diesen fortschrittlichen Automatisierungsskripten vereinfachen Sie regelmäßige Verwaltungsaufgaben wie die Migration und Organisation der Daten Ihrer Benutzer.

Viele Benutzer horten jede Datei, die sie jemals erstellt oder gespeichert haben. Als Administrator sind Sie dafür zuständig, diese zu verwalten. Das kann Sie viel Zeit und Nerven kosten.

Glücklicherweise gibt es Wege, um mit PowerShell die Datei- und Ordnerverwaltung in Ihrem Unternehmen zu vereinfachen. Sie verwenden das Cmdlet Move-Item, um Elemente anhand verschiedener Kriterien für das Verschieben auszuwählen. Sie können Dateien unter Beibehaltung der Ordnerstruktur verschieben und sogar eingreifen, wenn während der Übertragung Probleme auftreten.

Alle in diesem Artikel gezeigten Beispiele funktionieren sowohl in PowerShell 7 als auch in Windows PowerShell 5.1 auf die gleiche Weise.

PowerShell Move-Item-Befehle

Bevor Sie beginnen, möchten wir Ihnen einige Möglichkeiten vorstellen, wie Sie Move-Item-Befehle testen, da Sie mit dem automatisierten Verschieben von Dateien große Schäden anrichten können, wenn ein Filter zu breit definiert ist oder Sie den Ordnernamen falsch eingeben.

Die Standardmethode zum Testen der meisten Befehle in PowerShell ist der Parameter -WhatIf. Damit erhalten Sie eine Zeichenfolgenausgabe, die Ihnen mitteilt, welche Dateien der Befehl verschieben würde, ohne sie wirklich zu verschieben. Der Parameter lässt sich zu jedem Move-Item-Befehl hinzufügen.

Abbildung 1: Wenn Sie den Parameter -WhatIf zu einem Move-Item-Befehl hinzufügen, erfahren Sie, welche Dateien PowerShell verschieben würde, ohne sie wirklich zu verschieben.
Abbildung 1: Wenn Sie den Parameter -WhatIf zu einem Move-Item-Befehl hinzufügen, erfahren Sie, welche Dateien PowerShell verschieben würde, ohne sie wirklich zu verschieben.

Die andere Methode ist Get-ChildItem. Viele der Parameter für das Cmdlet Move-Item sind identisch mit denen für das Cmdlet Get-ChildItem. Das ist hilfreich für Tests. Um zu sehen, welche Parameter die beiden Cmdlets gemeinsam haben, verwenden Sie diesen Befehl.

(Get-Help Move-Item).parameters.parameter.name | ?{(Get-Help Get-ChildItem).parameters.parameter.name -contains $_}

Abbildung 2: Das Cmdlet Move-Item hat die gleichen Parameter wie das Cmdlet Get-ChildItem.
Abbildung 2: Das Cmdlet Move-Item hat die gleichen Parameter wie das Cmdlet Get-ChildItem.

Wenn Sie einen Move-Item-Befehl ausführen möchten, der einen dieser gemeinsamen Parameter verwendet, führen Sie den Befehl zunächst mit Get-ChildItem aus und überprüfen Sie die Ergebnisse. In manchen Fällen ist dies nützlicher als die -WhatIf-Ausgabe von Move-Item.

Verschieben von Dateien anhand Dateityp oder -name

Es gibt zahlreiche Attribute, die geeignete Filter sind, um Dateien zum Verschieben aufzufinden.

Angenommen, Sie möchten alle HTML-Dateien in einem Ordner an einen neuen Ort verschieben. Mit dem Parameter -Filter geben Sie den Erweiterungstyp mit dem Sternchen als Platzhalter an, um alle Dateien im aktuellen Verzeichnis mit der Dateierweiterung .html zu finden. Der folgende Befehl verschiebt die Dateien in ein Unterverzeichnis namens Target:

Move-Item -Path * -Filter *.html -Destination.\Target

Wenn Sie diesen Befehl von der Kommandozeile aus ausführen, erhalten Sie keine Meldung, ob diese Aktion erfolgreich war. Verwenden Sie den Parameter -Verbose, damit die Konsole Ihnen eine Rückmeldung ausgibt.

Abbildung 3: Der Parameter -Verbose zeigt den Fortschritt beim Verschieben von Dateien mit dem Move-Item Cmdlet.
Abbildung 3: Der Parameter -Verbose zeigt den Fortschritt beim Verschieben von Dateien mit dem Move-Item Cmdlet.

Der Parameter -Filter erlaubt das Auswählen von Dateien anhand bestimmter Muster in Dateinamen und -typen. Um zum Beispiel alle Dateien zu verschieben, die mit test beginnen, verwenden Sie den folgenden Befehl:

Move-Item -Path * -Filter test* -Destination.\Target -Verbose

Dateien anhand der Größe verschieben

Mit dem Cmdlet Where-Object, um nach anderen Attributen zu filtern, zum Beispiel nach Alter oder Größe. Um beispielsweise Dateien zu verschieben, die größer als 1 GB sind, suchen Sie die Dateien mit Get-ChildItem und filtern sie dann mit Where-Object:

Get-ChildItem | Where-Object {$_.Length -gt [math]::Pow(1024,3)} | Move-Item -Destination.\Target -Verbose

Abbildung 4: In this example, the code moved the Windows Server 2019 ISO file that was larger than the 1 GB criteria.
Abbildung 4: In this example, the code moved the Windows Server 2019 ISO file that was larger than the 1 GB criteria.

Verschieben von Dateien anhand ihres Alters

Beim Verschieben von Dateien anhand ihres Alters haben Sie mehrere Dateiattribute zur Verfügung. Wenn Sie sich die Ausgabe von Get-Item für eine Datei mit dem Namen security.log mit folgendem Code ansehen, erkennen Sie dort die DateTime-Werte:

(Get-Item.\security.log).psobject.properties | ?{$_.TypeNameOfValue -eq 'System.DateTime'} | Select Name,Value

Abbildung 5: Anhand der Datums- und Zeitwerte legen Sie fest, welche Dateien Sie während einer Migration verschieben lassen.
Abbildung 5: Anhand der Datums- und Zeitwerte legen Sie fest, welche Dateien Sie während einer Migration verschieben lassen.

Die Ausgabe gibt Aufschluss über das Alter der Datei, den letzten Zugriff auf die Datei und die letzte Änderung. Mit diesen Informationen erstellen Sie Code für verschiedene Zwecke. Der folgende Code sucht nach Dateien – beachten Sie, dass der Parameter -File nur Dateien betrifft, um das Verschieben von Ordnern zu vermeiden – die in den letzten zwei Wochen geändert wurden, und bewegt sie:

Get-ChildItem -File | Where-Object {$_.LastWriteTime -gt (Get-Date).AddDays(-14)} | Move-Item -Destination.\Target -Verbose

Verschieben von Dateien anhand kombinierter Kriterien

Es kommt häufig vor, dass Administratoren mehrere Kriterien haben, anhand derer sie die Dateien zum Verschieben auswählen möchten oder, dass sie die Ordnerstruktur zwischen verschiedenen Speicherorten identisch halten müssen. Sie können Befehle schreiben, die diese Situationen abdecken und sogar Dateien abfangen können, die derzeit bearbeitet werden. 

Wir nehmen alle zuvor behandelten Beispiele für einzelne Kriterien und kombinieren sie in einem Befehl. In diesem Fall verschiebt der Code alle Textdateien mit test im Namen, die kleiner als 5 KB sind und in der letzten Woche geändert wurden.

Das Cmdlet Where-Object filtert nach Größe und Änderungsdatum. Wir verwenden den -Filter-Parameter in Get-ChildItem anstelle von -Filter auf Move-Item, da Pipelines in PowerShell Befehle von links nach rechts verarbeiten, sodass das Filtern am Anfang des Befehls erfolgen sollte.

In diesem Fall verwenden wir *test*.txt als Filter, um Textdateien mit test im Namen zu erfassen. Anschließend übergeben wir über die Pipeline an Where-Object, um nach der spezifischen Größe und dem Änderungsdatum zu filtern, bevor das Skript die Pipeline an das Cmdlet Move-Item übergibt:

Get-ChildItem -Filter *test*.txt | Where-Object {$_.Length -lt (1024*5) -and $_.LastWriteTime -gt (Get-Date).AddDays(-7)} | Move-Item -Verbose

Beibehalten der Ordnerstruktur

Move-Item hat einen Nachteil: Um die Struktur eines Ordners beim Verschieben beizubehalten, müssen Sie auch den übergeordneten Ordner verschieben. Sie können den Inhalt eines Ordners und alle Unterordner nicht ohne zusätzlichen Aufwand verschieben.

Abbildung 6: Der in diesem Beispiel verwendete DemoFolder enthält mehrere Dateien und Ordner.
Abbildung 6: Der in diesem Beispiel verwendete DemoFolder enthält mehrere Dateien und Ordner.

Um alle Dateien und Ordner im DemoFolder an einen neuen Ort zu verschieben und die Dateistruktur beizubehalten, verschiebt der folgende Befehl den übergeordneten Ordner und seinen gesamten Inhalt in einen Ordner mit dem Namen Target:

Move-Item C:\tmp\DemoFolder -Destination C:\tmp\Target

Um nur den Inhalt von DemoFolder zu verschieben, verwendet das folgende Skript Get-ChildItem, um rekursiv jede Datei und jeden Ordner zu erfassen und dann den übergeordneten Quellpfad durch den übergeordneten Zielpfad zu ersetzen. Anschließend verschiebt PowerShell die Elemente mit Move-Item genau an die gewünschte Stelle. Der Parameter -Force bewirkt, dass Move-Item alle erforderlichen Ordner erstellt.

$source = 'C:\tmp\DemoFolder'

$dest = 'C:\tmp\Target'

Get-ChildItem $source -Recurse | ForEach-Object {

  $newPath = $_.FullName -replace [regex]::Escape($source),$dest

  Move-Item $_ -Destination $newPath -Force

}

Umgang mit Dateien, die aktuell bearbeitet werden

Was passiert, wenn Sie versuchen, eine Datei zu verschieben, und feststellen, dass dies fehlschlägt, weil sie in Gebrauch ist? Mit einem try-catch-Block verwenden Sie Code für das Troubleshooting, um das spezifische E/A-Problem – in diesem Fall einen System.IO.IOException-Fehler – zu erkennen und zu melden, wenn die Datei in Gebrauch ist.

Try {

  Move-Item.\SpreadSheet.xlsx -Destination.\Target -ErrorAction Stop

} Catch [System.IO.IOException] {

  Log "File:.\SpreadSheet.xlsx is in use."

}

Der Parameter -ErrorAction gibt ein Stop on Move-Item an, um zum Catch-Abschnitt zu springen, wenn der E/A-Fehler auftritt.

In diesem Beispiel protokolliert das Skript, dass die betreffende Datei in Gebrauch war. Wenn Sie Move-Item interaktiv ausführen, benachrichtigt Sie der Code, dass die Datei geöffnet ist, damit Sie sie schließen und das Skript erneut ausführen können.

Der PowerShell-Befehl Move-Item mag oberflächlich betrachtet sehr simpel sein, doch in Verbindung mit den Automatisierungsfunktionen der PowerShell-Engine erhalten Sie eine große Flexibilität bei der Dateiverwaltung. Mein Lieblingsbeispiel für die Verwendung dieses Befehls ist das Schreiben eines Skripts zum Verschieben von Dateien und Ordnern nach Feierabend. Sie konfigurieren ihn außerdem so, dass er ein Protokoll schreibt, dass Sie am nächsten Tag prüfen. Sie müssen nicht lange aufbleiben, um diese Terabytes an Daten zu verschieben, sondern haben nur genügend Vorbereitungszeit, um Ihr Skript in Form zu bringen.

Erfahren Sie mehr über Desktop-Management