PowerShell 7 Grundkurs 004: Dateien automatisch nach Dateityp sortieren
Worum geht es in diesem Teil?
In diesem vierten Teil des PowerShell-7-Grundkurses sortieren wir Dateien automatisch nach ihrer Dateiendung in passende Unterordner.
Aus Dateien wie:
urlaub.jpg
intro.mp4
rechnung.pdf
umsatz.xlsx
projekt.zip
entsteht zum Beispiel diese übersichtliche Ordnerstruktur:
01_Bilder
02_Videos
03_Dokumente
04_Tabellen
05_Archive

Vorher

Powershell 7: Nachher
Die Dateiendungen und die dazugehörigen Zielordner werden in einer geordneten Hashtable gespeichert. Dadurch lässt sich die Sortierung später leicht erweitern oder an die eigenen Anforderungen anpassen.
Es gibt wieder zwei Varianten:
01_Einfach
02_SendTo_Dateien_nach_Typ_sortieren
Die einfache Variante wird direkt in den Ordner kopiert, dessen Dateien sortiert werden sollen.
Die zweite Variante ist eine SendTo-Version. Damit können ein oder mehrere Ordner im Windows-Explorer markiert und über Senden an an das PowerShell-7-Skript übergeben werden.
Was ist das Ziel?
Das Ziel ist ein verständliches PowerShell-7-Skript, das bekannte Dateitypen erkennt und die Dateien in vorbereitete Kategorien einsortiert.
Dabei gelten einige wichtige Sicherheitsregeln:
Zuerst wird nur getestet.
Im Testmodus werden keine Dateien verschoben.
Im Testmodus werden keine Ordner erstellt.
Vorhandene Zieldateien werden nicht überschrieben.
Unbekannte Dateitypen bleiben im Ausgangsordner liegen.
Dateien werden nicht automatisch umbenannt.
Vor dem echten Sortieren muss JA eingegeben werden.
Das Skript kann die Meldungen außerdem wahlweise nur im Fenster anzeigen, als Logdatei speichern, in die Zwischenablage kopieren oder beide zusätzlichen Ausgaben verwenden.
Warum ist dieser Teil wichtig?
In diesem Teil lernen wir mehrere wichtige PowerShell-Grundlagen kennen:
Parameter und Switch-Parameter
Variablen und Arrays
geordnete Hashtables
foreach-Schleifen
if-Abfragen
Where-Object
Dateiendungen auswerten
Pfade mit Join-Path zusammensetzen
Dateien und Ordner mit Test-Path prüfen
Ordner mit New-Item erstellen
Dateien mit Move-Item verschieben
Protokolle in Arrays sammeln
Protokolle als Textdatei speichern
Text in die Zwischenablage kopieren
mehrere Ordner über SendTo übergeben
Besonders wichtig ist der Unterschied zwischen einem normalen Programmlauf und einem Testlauf.
Das Skript zeigt im Testmodus, was bei der echten Ausführung passieren würde, verändert den ausgewählten Ordner aber nicht.
Hinweis zur verwendeten Version
Auf dieser Seite wird die im Tutorial verwendete Version beschrieben:
Version: 1.0
Stand: 2026-08-03
Die Codebeispiele und Erklärungen entsprechen genau dieser Tutorialversion.
Eine weiterführende Fehlerbehandlung mit try, catch und -ErrorAction Stop ist in Version 1.0 noch nicht enthalten.
Hinweis zur Kursreihe
Diese PowerShell-7-Reihe ist Teil einer größeren Windows-Automatisierungsreihe.
Viele Aufgaben werden in mehreren Sprachen umgesetzt:
Batch
PowerShell 7
Python
Dadurch kann man gut vergleichen, wie dieselbe Aufgabe in unterschiedlichen Sprachen gelöst wird.
Der Code ist bewusst ausführlich aufgebaut. Funktionen oder Klassen wären ebenfalls möglich, würden diesen Grundkurs aber unnötig komplizierter machen.
Deshalb verwenden wir gut sichtbare Variablen, Schleifen, Abfragen, Zähler und Meldungen.
Downloads zu diesem Teil
Für diesen Teil gibt es zwei PowerShell-7-Skripte und die dazugehörigen Starter-Batchdateien.
Dateien für PowerShell 7 Grundkurs Teil 004:
Download PowerShell 7 Grundkurs: 004_Dateien_nach_Typ_sortieren als ZIP-Datei.
Entpacken nach:
C:\TOPTORIALS_CODE\010_PowerShell_7_Grundkurs
Falls der Ordner noch nicht existiert, lege ihn vorher im Explorer an.
Nach dem Entpacken entsteht dort:
C:\TOPTORIALS_CODE\010_PowerShell_7_Grundkurs\004_Dateien_nach_Typ_sortieren
Darin befinden sich diese beiden Unterordner:
01_Einfach
02_SendTo_Dateien_nach_Typ_sortieren
Testumgebung zum Mitmachen
Für diese Tutorialreihe gibt es zusätzlich eine vorbereitete Testumgebung.
Sie enthält vorbereitete Ordner und Beispieldateien, mit denen die Skripte gefahrlos ausprobiert werden können.
Testumgebung für Windows-Automatisierung:
Download TOPTORIALS_Testdaten_Windows_Automatisierung_V001.zip
Entpacken nach:
C:\TOPTORIALS_CODE\1000_TESTBEREICH
Falls dieser Ordner noch nicht existiert, lege ihn vorher im Explorer an.
Für den PowerShell-7-Grundkurs kann der entpackte Ordner so benannt werden:
TOPTORIALS_Testdaten_Windows_Automatisierung_PowerShell_7_V001
Ein möglicher Testpfad wäre dann:
C:\TOPTORIALS_CODE\1000_TESTBEREICH\TOPTORIALS_Testdaten_Windows_Automatisierung_PowerShell_7_V001\004_Dateien_nach_Typ_sortieren
Sicherheitshinweis
Wichtiger Hinweis:
Die Skripte werden auf eigene Verantwortung verwendet. Teste sie zuerst in einer separaten Testumgebung und nicht direkt mit wichtigen Originaldateien.
Solange _test im Namen der Starter-Batchdatei steht, wird das PowerShell-Skript mit dem Schalter -Test gestartet.
In diesem Modus werden keine Dateien verschoben und keine Zielordner erstellt.
Erst nachdem das angezeigte Ergebnis geprüft wurde, kann _test aus dem Namen der Starter-Batchdatei entfernt werden.
Beim echten Lauf erscheint zusätzlich eine Sicherheitsabfrage. Nur die exakte Eingabe JA startet das Verschieben.
Vorhandene Dateien im Zielordner werden nicht überschrieben. Trotzdem sollte die echte Ausführung zunächst mit Kopien unwichtiger Dateien getestet werden.
Enthaltene Dateien
Zu diesem Teil gehören zwei Varianten.
Variante 1: Einfach
01_Einfach
├── 004_dateien_nach_typ_sortieren.ps1
└── 004_dateien_nach_typ_sortieren_starter_batch_test.bat
Variante 2: SendTo-Dateien nach Typ sortieren
02_SendTo_Dateien_nach_Typ_sortieren
├── 004_sendto_dateien_nach_typ_sortieren.ps1
└── 004_sendto_dateien_nach_typ_sortieren_starter_batch_test.bat
Variante 1: Dateien im aktuellen Ordner sortieren
Die einfache Variante wird direkt in den Ordner kopiert, dessen Dateien sortiert werden sollen.
Danach wird diese Datei per Doppelklick gestartet:
004_dateien_nach_typ_sortieren_starter_batch_test.bat
Solange _test im Dateinamen steht, läuft nur die Vorschau.
Das Skript meldet dann zum Beispiel:
WÜRDE VERSCHIEBEN: "urlaub.jpg" nach "01_Bilder"
WÜRDE VERSCHIEBEN: "intro.mp4" nach "02_Videos"
Unbekannte Dateitypen werden von Version 1.0 nicht verarbeitet. Sie bleiben unverändert im Ausgangsordner liegen und erscheinen nicht in der Zusammenfassung.
Wenn alles richtig aussieht, wird ausschließlich _test aus dem Namen der Starter-Batchdatei entfernt:
004_dateien_nach_typ_sortieren_starter_batch.bat
Die PowerShell-Datei selbst wird nicht umbenannt.
Der komplette Code der einfachen PowerShell-7-Datei
Die Datei heißt:
004_dateien_nach_typ_sortieren.ps1
# ============================================================
# TOPTORIALS OFFICE - PowerShell 7 Grundkurs
# Script: 004_dateien_nach_typ_sortieren.ps1
# Beschreibung: Sortiert Dateien nach Dateityp in Unterordner.
# Autor: Chris
# YouTube: https://www.youtube.com/@TOPTORIALS-OFFICE
# Webseite: https://www.toptorials.com
# Version: 1.0
# Stand: 2026-08-03
# ============================================================
param (
[switch]$Test
)
Write-Host ""
Write-Host "Dateien werden nach Typ sortiert..."
Write-Host ""
$basisOrdner = (Get-Location).Path
# ------------------------------------------------------------
# Welche zusätzliche Ausgabe soll erstellt werden?
# Wichtig: Immer nur EINE der folgenden Varianten aktiv lassen.
# ------------------------------------------------------------
# Variante 1: Nur Bildschirmausgabe
$logDateiErstellen = $false
$zwischenablageVerwenden = $false
# Variante 2: Logdatei erstellen
# $logDateiErstellen = $true
# $zwischenablageVerwenden = $false
# Variante 3: Nur in die Zwischenablage kopieren
# $logDateiErstellen = $false
# $zwischenablageVerwenden = $true
# Variante 4: Logdatei erstellen und in die Zwischenablage kopieren
# $logDateiErstellen = $true
# $zwischenablageVerwenden = $true
# ------------------------------------------------------------
# Dateitypen und Zielordner festlegen
# ------------------------------------------------------------
$kategorien = [ordered]@{
"01_Bilder" = @(".jpg", ".jpeg", ".png", ".gif", ".webp")
"02_Videos" = @(".mp4", ".mov", ".mkv", ".avi")
"03_Dokumente" = @(".pdf", ".docx", ".txt")
"04_Tabellen" = @(".xlsx", ".xls", ".csv")
"05_Archive" = @(".zip", ".rar", ".7z")
}
$anzahlVerschoben = 0
$anzahlUebersprungen = 0
$protokoll = @()
if ($Test) {
$testmodusText = "JA"
}
else {
$testmodusText = "NEIN"
}
$protokoll += "Dateien werden nach Typ sortiert."
$protokoll += "Zielordner: $basisOrdner"
$protokoll += "Testmodus: $testmodusText"
$protokoll += ""
Write-Host "Zielordner: $basisOrdner"
Write-Host "Testmodus: $testmodusText"
Write-Host ""
# ------------------------------------------------------------
# Sicherheitsabfrage bei der echten Ausführung
# ------------------------------------------------------------
if (-not $Test) {
Write-Host "ACHTUNG: Dieses Skript wird Dateien wirklich verschieben."
Write-Host ""
$antwort = Read-Host "Zum Fortfahren JA eingeben"
if ($antwort -ne "JA") {
Write-Host ""
Write-Host "Abgebrochen."
Write-Host ""
Read-Host "Drücke Enter zum Beenden"
exit
}
}
# ------------------------------------------------------------
# Zielordner erstellen
# Im Testmodus werden keine Ordner angelegt.
# ------------------------------------------------------------
if (-not $Test) {
foreach ($kategorie in $kategorien.Keys) {
$zielOrdner = Join-Path -Path $basisOrdner -ChildPath $kategorie
if (-not (Test-Path -LiteralPath $zielOrdner -PathType Container)) {
New-Item -ItemType Directory -Path $zielOrdner | Out-Null
}
}
}
# ------------------------------------------------------------
# Dateien sortieren
# Es werden nur Dateien direkt im Basisordner verarbeitet.
# Unterordner werden nicht durchsucht.
# ------------------------------------------------------------
$dateien = Get-ChildItem -LiteralPath $basisOrdner -File
foreach ($kategorie in $kategorien.Keys) {
$zielOrdner = Join-Path -Path $basisOrdner -ChildPath $kategorie
$erweiterungen = $kategorien[$kategorie]
$passendeDateien = $dateien | Where-Object {
$_.Extension.ToLowerInvariant() -in $erweiterungen
}
foreach ($datei in $passendeDateien) {
$zielDatei = Join-Path -Path $zielOrdner -ChildPath $datei.Name
if (Test-Path -LiteralPath $zielDatei) {
if ($Test) {
$meldung = "WÜRDE ÜBERSPRINGEN: `"$($datei.Name)`" - Datei existiert bereits in `"$kategorie`""
}
else {
$meldung = "ÜBERSPRUNGEN: `"$($datei.Name)`" - Datei existiert bereits in `"$kategorie`""
}
Write-Host $meldung
$protokoll += $meldung
$anzahlUebersprungen++
}
else {
if ($Test) {
$meldung = "WÜRDE VERSCHIEBEN: `"$($datei.Name)`" nach `"$kategorie`""
}
else {
Move-Item -LiteralPath $datei.FullName -Destination $zielOrdner
$meldung = "VERSCHOBEN: `"$($datei.Name)`" nach `"$kategorie`""
}
Write-Host $meldung
$protokoll += $meldung
$anzahlVerschoben++
}
}
}
# ------------------------------------------------------------
# Zusammenfassung
# ------------------------------------------------------------
$protokoll += ""
$protokoll += "Fertig."
Write-Host ""
Write-Host "Fertig."
Write-Host ""
if ($Test) {
$meldung1 = "Anzahl Dateien, die verschoben würden: $anzahlVerschoben"
$meldung2 = "Anzahl Dateien, die übersprungen würden: $anzahlUebersprungen"
Write-Host $meldung1
Write-Host $meldung2
Write-Host ""
Write-Host "Es wurden keine Dateien verschoben und keine Ordner erstellt."
Write-Host "Wenn alles richtig aussieht, entferne _test aus dem Namen der Starter-Batchdatei."
$protokoll += $meldung1
$protokoll += $meldung2
$protokoll += "Es wurden keine Dateien verschoben und keine Ordner erstellt."
}
else {
$meldung1 = "Gesamt verschoben: $anzahlVerschoben Datei(en)"
$meldung2 = "Übersprungen wegen Namenskonflikt: $anzahlUebersprungen Datei(en)"
Write-Host $meldung1
Write-Host $meldung2
$protokoll += $meldung1
$protokoll += $meldung2
}
# ------------------------------------------------------------
# Optionale Ausgabe als Logdatei und in die Zwischenablage
# ------------------------------------------------------------
$protokollText = $protokoll -join [Environment]::NewLine
$zeitstempel = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$logDatei = Join-Path -Path $basisOrdner -ChildPath "sortierprotokoll_$zeitstempel.log"
if ($logDateiErstellen) {
$protokollText | Set-Content -LiteralPath $logDatei -Encoding UTF8
Write-Host ""
Write-Host "Das Protokoll wurde erstellt:"
Write-Host $logDatei
}
if ($zwischenablageVerwenden) {
$protokollText | Set-Clipboard
Write-Host ""
Write-Host "Das Protokoll wurde zusätzlich in die Zwischenablage kopiert."
}
Write-Host ""
Read-Host "Drücke Enter zum Beenden"
Code der einfachen PowerShell-7-Datei erklärt
Testmodus als Switch-Parameter
param (
[switch]$Test
)
Mit param werden Parameter festgelegt, die beim Start an das PowerShell-Skript übergeben werden können.
[switch] ist ein Schalterparameter. Er benötigt keinen zusätzlichen Wert.
Wird das Skript mit:
-Test
gestartet, ist $Test wahr. Ohne den Schalter ist $Test falsch.
Text im PowerShell-Fenster ausgeben
Write-Host ""
Write-Host "Dateien werden nach Typ sortiert..."
Write-Host ""
Write-Host gibt Text direkt im PowerShell-Fenster aus.
Ein leerer Text erzeugt eine Leerzeile und macht die Ausgabe übersichtlicher.
Aktuellen Arbeitsordner ermitteln
$basisOrdner = (Get-Location).Path
Get-Location liefert den aktuellen Arbeitsordner.
Mit .Path wird daraus der vollständige Pfad ausgelesen und in $basisOrdner gespeichert.
Die Starter-Batchdatei wechselt vorher in ihren eigenen Ordner. Deshalb ist dieser Ordner gleichzeitig der Basisordner für die Sortierung.
Zusätzliche Ausgaben auswählen
$logDateiErstellen = $false
$zwischenablageVerwenden = $false
Mit diesen beiden booleschen Variablen wird festgelegt, ob zusätzlich eine Logdatei erstellt und das Protokoll in die Zwischenablage kopiert werden soll.
$false bedeutet ausgeschaltet.
$true bedeutet eingeschaltet.
Immer nur eine der vorbereiteten Varianten sollte aktiv sein.
Dateitypen und Zielordner festlegen
$kategorien = [ordered]@{
"01_Bilder" = @(".jpg", ".jpeg", ".png", ".gif", ".webp")
"02_Videos" = @(".mp4", ".mov", ".mkv", ".avi")
"03_Dokumente" = @(".pdf", ".docx", ".txt")
"04_Tabellen" = @(".xlsx", ".xls", ".csv")
"05_Archive" = @(".zip", ".rar", ".7z")
}
In der geordneten Hashtable $kategorien wird jedem Zielordner ein Array mit passenden Dateiendungen zugeordnet.
[ordered] sorgt dafür, dass die Kategorien in der angegebenen Reihenfolge verarbeitet werden.
Weitere Dateitypen können einfach zu einem vorhandenen Array hinzugefügt werden.
Eine neue Kategorie könnte ebenfalls als weiterer Eintrag ergänzt werden.
Zähler und Protokoll vorbereiten
$anzahlVerschoben = 0
$anzahlUebersprungen = 0
$protokoll = @()
Die ersten beiden Variablen zählen verschobene beziehungsweise übersprungene Dateien.
Im Testmodus zählt $anzahlVerschoben die Dateien, die bei einer echten Ausführung verschoben würden.
$protokoll ist zunächst ein leeres Array. Darin werden die Meldungen des Skripts gesammelt.
Testmodus als Text darstellen
if ($Test) {
$testmodusText = "JA"
}
else {
$testmodusText = "NEIN"
}
Ist der Schalter -Test aktiv, wird JA gespeichert. Andernfalls wird NEIN gespeichert.
Dieser Text erscheint später im Fenster und im Protokoll.
Sicherheitsabfrage im Echtmodus
if (-not $Test) {
$antwort = Read-Host "Zum Fortfahren JA eingeben"
if ($antwort -ne "JA") {
exit
}
}
-not $Test bedeutet, dass der Testmodus nicht aktiv ist.
Nur in diesem Fall erscheint die Sicherheitsabfrage.
Mit -ne wird geprüft, ob die Eingabe ungleich JA ist. Jede andere Eingabe beendet das Skript.
Zielordner erstellen
if (-not $Test) {
foreach ($kategorie in $kategorien.Keys) {
$zielOrdner = Join-Path -Path $basisOrdner -ChildPath $kategorie
if (-not (Test-Path -LiteralPath $zielOrdner -PathType Container)) {
New-Item -ItemType Directory -Path $zielOrdner | Out-Null
}
}
}
Dieser Block wird nur im Echtmodus ausgeführt.
$kategorien.Keys liefert die Namen der Zielordner.
foreach verarbeitet diese Namen nacheinander.
Join-Path verbindet den Basisordner mit dem jeweiligen Kategorienamen.
Test-Path prüft, ob der Ordner bereits existiert.
Fehlt der Ordner, wird er mit New-Item erstellt.
Out-Null unterdrückt die sonst angezeigte Objektausgabe von New-Item.
In Version 1.0 werden im Echtmodus alle fünf Kategorieordner angelegt, auch wenn für eine Kategorie momentan keine passende Datei vorhanden ist.
Dateien im Basisordner erfassen
$dateien = Get-ChildItem -LiteralPath $basisOrdner -File
Get-ChildItem liest den Inhalt des Basisordners aus.
Durch -File werden nur Dateien erfasst.
Da kein Parameter wie -Recurse verwendet wird, werden Unterordner nicht durchsucht.
Kategorien nacheinander verarbeiten
foreach ($kategorie in $kategorien.Keys) {
$zielOrdner = Join-Path -Path $basisOrdner -ChildPath $kategorie
$erweiterungen = $kategorien[$kategorie]
}
Die äußere foreach-Schleife verarbeitet jede Kategorie.
Der passende Zielordner wird zusammengesetzt und die zugehörigen Dateiendungen werden in $erweiterungen gespeichert.
Passende Dateien filtern
$passendeDateien = $dateien | Where-Object {
$_.Extension.ToLowerInvariant() -in $erweiterungen
}
Die Pipeline übergibt alle erfassten Dateien an Where-Object.
$_ steht jeweils für die aktuell geprüfte Datei.
Mit .Extension wird ihre Dateiendung ausgelesen.
ToLowerInvariant() wandelt die Endung in Kleinbuchstaben um.
Mit -in wird geprüft, ob diese Endung im Array der aktuellen Kategorie enthalten ist.
Vollständigen Zielpfad zusammensetzen
$zielDatei = Join-Path -Path $zielOrdner -ChildPath $datei.Name
Hier werden der Zielordner und der ursprüngliche Dateiname zu einem vollständigen Zielpfad verbunden.
Dieser Pfad wird anschließend für die Konfliktprüfung verwendet.
Vorhandene Zieldateien schützen
if (Test-Path -LiteralPath $zielDatei) {
# Datei überspringen
}
Existiert im Zielordner bereits eine Datei mit demselben Namen, wird die Quelldatei nicht verschoben.
Im Testmodus erscheint:
WÜRDE ÜBERSPRINGEN
Im Echtmodus erscheint:
ÜBERSPRUNGEN
Die vorhandene Datei wird nicht überschrieben und die Quelldatei wird nicht automatisch umbenannt.
Testmodus und echtes Verschieben
if ($Test) {
$meldung = "WÜRDE VERSCHIEBEN: ..."
}
else {
Move-Item -LiteralPath $datei.FullName -Destination $zielOrdner
$meldung = "VERSCHOBEN: ..."
}
Im Testmodus wird nur eine Meldung vorbereitet.
Im Echtmodus verschiebt Move-Item die Datei in den Kategorienordner.
$datei.FullName enthält den vollständigen Quellpfad.
$zielOrdner enthält den Zielordner.
Version 1.0 enthält an dieser Stelle noch keine zusätzliche Fehlerbehandlung mit try und catch.
Unbekannte Dateitypen
Dateien, deren Endung in keiner Kategorie vorkommt, werden von den Filtern nicht ausgewählt.
Sie bleiben deshalb unverändert im Basisordner liegen.
Version 1.0 erzeugt für unbekannte Dateitypen keine eigene Meldung und zählt sie nicht als übersprungen.
Protokoll zu Text verbinden
$protokollText = $protokoll -join [Environment]::NewLine
Mit -join werden die einzelnen Einträge des Arrays zu einem zusammenhängenden Text verbunden.
[Environment]::NewLine setzt zwischen die Einträge einen zum Betriebssystem passenden Zeilenumbruch.
Zeitstempel und Logdatei
$zeitstempel = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$logDatei = Join-Path -Path $basisOrdner -ChildPath "sortierprotokoll_$zeitstempel.log"
Get-Date erzeugt einen Zeitstempel.
Dadurch erhält jede Logdatei einen eindeutigen Namen, zum Beispiel:
sortierprotokoll_2026-08-03_14-30-25.log
Protokoll speichern und kopieren
$protokollText | Set-Content -LiteralPath $logDatei -Encoding UTF8
Set-Content schreibt das Protokoll als UTF-8-Datei.
Mit:
$protokollText | Set-Clipboard
wird derselbe Text in die Windows-Zwischenablage kopiert.
Starter-Batchdatei der einfachen Variante
Die Datei heißt:
004_dateien_nach_typ_sortieren_starter_batch_test.bat
@echo off
REM ============================================================
REM TOPTORIALS OFFICE - PowerShell 7 Grundkurs
REM Script: 004_dateien_nach_typ_sortieren_starter_batch_test.bat
REM Beschreibung: Startet das PowerShell-7-Skript im Testmodus.
REM Autor: Chris
REM YouTube: https://www.youtube.com/@TOPTORIALS-OFFICE
REM Webseite: https://www.toptorials.com
REM Version: 1.0
REM Stand: 2026-08-03
REM
REM Hinweis:
REM Solange _test im Dateinamen steht, wird -Test uebergeben.
REM Fuer die echte Ausfuehrung _test aus dem Dateinamen entfernen.
REM ============================================================
chcp 65001 >nul
cd /d "%~dp0"
echo %~n0 | find /i "_test" >nul
if not errorlevel 1 (
pwsh -ExecutionPolicy Bypass -File "004_dateien_nach_typ_sortieren.ps1" -Test
) else (
pwsh -ExecutionPolicy Bypass -File "004_dateien_nach_typ_sortieren.ps1"
)
Code der einfachen Starter-Batchdatei erklärt
Ausgabe der Befehle ausblenden
@echo off
Dadurch werden die ausgeführten Batchbefehle nicht zusätzlich im Fenster angezeigt.
Codepage auf UTF-8 setzen
chcp 65001 >nul
Dieser Befehl stellt die Konsole auf UTF-8 um.
>nul blendet die Meldung über den Wechsel der Codepage aus.
In den Ordner der Starterdatei wechseln
cd /d "%~dp0"
%~dp0 enthält Laufwerk und Ordnerpfad der gestarteten Batchdatei.
cd /d wechselt in diesen Ordner und bei Bedarf auch auf ein anderes Laufwerk.
Dadurch findet die Starterdatei das PowerShell-Skript im gleichen Ordner.
Nach _test im Dateinamen suchen
echo %~n0 | find /i "_test" >nul
%~n0 enthält den Namen der gestarteten Batchdatei ohne Dateiendung.
find /i sucht unabhängig von Groß- und Kleinschreibung nach _test.
Testmodus oder Echtmodus starten
if not errorlevel 1 (
pwsh -ExecutionPolicy Bypass -File "004_dateien_nach_typ_sortieren.ps1" -Test
) else (
pwsh -ExecutionPolicy Bypass -File "004_dateien_nach_typ_sortieren.ps1"
)
Wurde _test gefunden, wird das PowerShell-Skript mit -Test gestartet.
Wurde _test nicht gefunden, fehlt dieser Schalter und das Skript läuft nach der Sicherheitsabfrage im Echtmodus.
Variante 2: Dateien über SendTo sortieren
Die SendTo-Variante ist für einen praktischen Alltagsworkflow im Windows-Explorer gedacht.
Ein oder mehrere Ordner können markiert und über:
Rechtsklick
Senden an
Dateien nach Typ sortieren
an das Skript übergeben werden.
Jeder gültige Ordner wird einzeln verarbeitet.
Der komplette Code der SendTo-PowerShell-Datei
Die Datei heißt:
004_sendto_dateien_nach_typ_sortieren.ps1
# ============================================================
# TOPTORIALS OFFICE - PowerShell 7 Grundkurs
# Script: 004_sendto_dateien_nach_typ_sortieren.ps1
# Beschreibung: Sortiert Dateien übergebener Ordner nach Dateityp in Unterordner.
# Autor: Chris
# YouTube: https://www.youtube.com/@TOPTORIALS-OFFICE
# Webseite: https://www.toptorials.com
# Version: 1.0
# Stand: 2026-08-03
# ============================================================
param (
[switch]$Test,
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Ordner
)
Write-Host ""
# ------------------------------------------------------------
# Prüfen, ob mindestens ein Ordner übergeben wurde
# ------------------------------------------------------------
if (-not $Ordner -or $Ordner.Count -eq 0) {
Write-Host "Bitte sende mindestens einen Ordner an dieses Skript."
Write-Host ""
Write-Host "Du kannst einen Ordner im Explorer rechts anklicken"
Write-Host "und anschließend 'Senden an' verwenden."
Write-Host ""
Read-Host "Drücke Enter zum Beenden"
exit
}
# ------------------------------------------------------------
# Welche zusätzliche Ausgabe soll erstellt werden?
# Wichtig: Immer nur EINE der folgenden Varianten aktiv lassen.
# ------------------------------------------------------------
# Variante 1: Nur Bildschirmausgabe
$logDateiErstellen = $false
$zwischenablageVerwenden = $false
# Variante 2: Logdatei erstellen
# $logDateiErstellen = $true
# $zwischenablageVerwenden = $false
# Variante 3: Nur in die Zwischenablage kopieren
# $logDateiErstellen = $false
# $zwischenablageVerwenden = $true
# Variante 4: Logdatei erstellen und in die Zwischenablage kopieren
# $logDateiErstellen = $true
# $zwischenablageVerwenden = $true
# ------------------------------------------------------------
# Dateitypen und Zielordner festlegen
# ------------------------------------------------------------
$kategorien = [ordered]@{
"01_Bilder" = @(".jpg", ".jpeg", ".png", ".gif", ".webp")
"02_Videos" = @(".mp4", ".mov", ".mkv", ".avi")
"03_Dokumente" = @(".pdf", ".docx", ".txt")
"04_Tabellen" = @(".xlsx", ".xls", ".csv")
"05_Archive" = @(".zip", ".rar", ".7z")
}
$gesamtProtokoll = @()
if ($Test) {
$testmodusText = "JA"
}
else {
$testmodusText = "NEIN"
}
# ------------------------------------------------------------
# Alle übergebenen Ordner nacheinander verarbeiten
# ------------------------------------------------------------
foreach ($ordnerPfad in $Ordner) {
if (-not (Test-Path -LiteralPath $ordnerPfad -PathType Container)) {
Write-Host "ÜBERSPRUNGEN: Der übergebene Pfad ist kein Ordner:"
Write-Host $ordnerPfad
Write-Host ""
continue
}
$basisOrdner = (Resolve-Path -LiteralPath $ordnerPfad).Path
$anzahlVerschoben = 0
$anzahlUebersprungen = 0
$protokoll = @()
$protokoll += "Dateien werden nach Typ sortiert."
$protokoll += "Zielordner: $basisOrdner"
$protokoll += "Testmodus: $testmodusText"
$protokoll += ""
Write-Host "Dateien werden nach Typ sortiert in:"
Write-Host $basisOrdner
Write-Host ""
Write-Host "Testmodus: $testmodusText"
Write-Host ""
# --------------------------------------------------------
# Sicherheitsabfrage bei der echten Ausführung
# --------------------------------------------------------
if (-not $Test) {
Write-Host "ACHTUNG: Dieses Skript wird Dateien in diesem Ordner wirklich verschieben."
Write-Host ""
$antwort = Read-Host "Zum Fortfahren JA eingeben"
if ($antwort -ne "JA") {
Write-Host ""
Write-Host "Dieser Ordner wurde übersprungen."
Write-Host ""
continue
}
}
# --------------------------------------------------------
# Zielordner erstellen
# Im Testmodus werden keine Ordner angelegt.
# --------------------------------------------------------
if (-not $Test) {
foreach ($kategorie in $kategorien.Keys) {
$zielOrdner = Join-Path -Path $basisOrdner -ChildPath $kategorie
if (-not (Test-Path -LiteralPath $zielOrdner -PathType Container)) {
New-Item -ItemType Directory -Path $zielOrdner | Out-Null
}
}
}
# --------------------------------------------------------
# Dateien sortieren
# Es werden nur Dateien direkt im Basisordner verarbeitet.
# Unterordner werden nicht durchsucht.
# --------------------------------------------------------
$dateien = Get-ChildItem -LiteralPath $basisOrdner -File
foreach ($kategorie in $kategorien.Keys) {
$zielOrdner = Join-Path -Path $basisOrdner -ChildPath $kategorie
$erweiterungen = $kategorien[$kategorie]
$passendeDateien = $dateien | Where-Object {
$_.Extension.ToLowerInvariant() -in $erweiterungen
}
foreach ($datei in $passendeDateien) {
$zielDatei = Join-Path -Path $zielOrdner -ChildPath $datei.Name
if (Test-Path -LiteralPath $zielDatei) {
if ($Test) {
$meldung = "WÜRDE ÜBERSPRINGEN: `"$($datei.Name)`" - Datei existiert bereits in `"$kategorie`""
}
else {
$meldung = "ÜBERSPRUNGEN: `"$($datei.Name)`" - Datei existiert bereits in `"$kategorie`""
}
Write-Host $meldung
$protokoll += $meldung
$anzahlUebersprungen++
}
else {
if ($Test) {
$meldung = "WÜRDE VERSCHIEBEN: `"$($datei.Name)`" nach `"$kategorie`""
}
else {
Move-Item -LiteralPath $datei.FullName -Destination $zielOrdner
$meldung = "VERSCHOBEN: `"$($datei.Name)`" nach `"$kategorie`""
}
Write-Host $meldung
$protokoll += $meldung
$anzahlVerschoben++
}
}
}
# --------------------------------------------------------
# Zusammenfassung für diesen Ordner
# --------------------------------------------------------
$protokoll += ""
$protokoll += "Fertig."
Write-Host ""
Write-Host "Fertig."
Write-Host ""
if ($Test) {
$meldung1 = "Anzahl Dateien, die verschoben würden: $anzahlVerschoben"
$meldung2 = "Anzahl Dateien, die übersprungen würden: $anzahlUebersprungen"
Write-Host $meldung1
Write-Host $meldung2
Write-Host ""
Write-Host "Es wurden keine Dateien verschoben und keine Ordner erstellt."
$protokoll += $meldung1
$protokoll += $meldung2
$protokoll += "Es wurden keine Dateien verschoben und keine Ordner erstellt."
}
else {
$meldung1 = "Gesamt verschoben: $anzahlVerschoben Datei(en)"
$meldung2 = "Übersprungen wegen Namenskonflikt: $anzahlUebersprungen Datei(en)"
Write-Host $meldung1
Write-Host $meldung2
$protokoll += $meldung1
$protokoll += $meldung2
}
# --------------------------------------------------------
# Optionale Ausgabe als Logdatei
# Für jeden übergebenen Ordner wird eine eigene Datei erstellt.
# --------------------------------------------------------
$protokollText = $protokoll -join [Environment]::NewLine
$zeitstempel = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$logDatei = Join-Path -Path $basisOrdner -ChildPath "sortierprotokoll_$zeitstempel.log"
if ($logDateiErstellen) {
$protokollText | Set-Content -LiteralPath $logDatei -Encoding UTF8
Write-Host ""
Write-Host "Das Protokoll wurde erstellt:"
Write-Host $logDatei
}
$gesamtProtokoll += $protokoll
$gesamtProtokoll += ""
$gesamtProtokoll += "============================================================"
$gesamtProtokoll += ""
Write-Host ""
Write-Host "============================================================"
Write-Host ""
}
# ------------------------------------------------------------
# Optionale Ausgabe in die Zwischenablage
# Bei mehreren Ordnern enthält sie alle Protokolle.
# ------------------------------------------------------------
if ($zwischenablageVerwenden -and $gesamtProtokoll.Count -gt 0) {
$gesamtProtokollText = $gesamtProtokoll -join [Environment]::NewLine
$gesamtProtokollText | Set-Clipboard
Write-Host "Alle Protokolle wurden zusätzlich in die Zwischenablage kopiert."
Write-Host ""
}
if ($Test) {
Write-Host "Der Test ist abgeschlossen."
Write-Host "Wenn alles richtig aussieht, entferne _test aus dem Namen der Starter-Batchdatei."
Write-Host ""
}
Read-Host "Drücke Enter zum Beenden"
Besonderheiten der SendTo-PowerShell-Datei
Mehrere Ordner entgegennehmen
param (
[switch]$Test,
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Ordner
)
Der Testmodus wird wieder über [switch]$Test gesteuert.
[string[]]$Ordner definiert einen benannten Parameter, der mehrere Textwerte aufnehmen kann.
In diesen Textwerten stehen die Pfade der übergebenen Ordner.
ValueFromRemainingArguments = $true sorgt dafür, dass alle nach den bekannten Parametern verbleibenden Startargumente in $Ordner gesammelt werden.
Die SendTo-Version verwendet deshalb nicht die automatische Variable $args.
Prüfen, ob ein Ordner übergeben wurde
if (-not $Ordner -or $Ordner.Count -eq 0) {
# Hinweis anzeigen und Skript beenden
}
Dieser Block erkennt, ob die SendTo-Datei ohne übergebene Ordner gestartet wurde.
-or bedeutet, dass mindestens eine der beiden Bedingungen zutreffen muss.
Alle übergebenen Ordner verarbeiten
foreach ($ordnerPfad in $Ordner) {
# aktuellen Ordner verarbeiten
}
Die Schleife geht alle in $Ordner gespeicherten Pfade nacheinander durch.
Dadurch können mehrere Ordner gleichzeitig markiert und über Senden an gestartet werden.
Gültigen Ordnerpfad prüfen
if (-not (Test-Path -LiteralPath $ordnerPfad -PathType Container)) {
Write-Host "ÜBERSPRUNGEN: Der übergebene Pfad ist kein Ordner:"
continue
}
-PathType Container prüft, ob der Pfad ein Ordner ist.
Einzelne Dateien oder ungültige Pfade werden übersprungen.
continue beendet nur den aktuellen Schleifendurchlauf. Danach wird mit dem nächsten übergebenen Pfad weitergemacht.
Ordnerpfad vollständig auflösen
$basisOrdner = (Resolve-Path -LiteralPath $ordnerPfad).Path
Resolve-Path ermittelt den vollständigen Pfad des übergebenen Ordners.
Dieser Pfad wird anschließend als Basisordner für die Sortierung verwendet.
Zähler für jeden Ordner zurücksetzen
$anzahlVerschoben = 0
$anzahlUebersprungen = 0
$protokoll = @()
Diese Variablen stehen innerhalb der äußeren Schleife.
Dadurch beginnt die Zählung für jeden übergebenen Ordner wieder bei null und jeder Ordner erhält sein eigenes Protokoll.
Sicherheitsabfrage für jeden Ordner
Im Echtmodus erscheint die Sicherheitsabfrage für jeden gültigen Ordner einzeln.
Wird nicht exakt JA eingegeben, wird nur dieser eine Ordner übersprungen.
Danach kann der nächste übergebene Ordner verarbeitet werden.
Gesamtprotokoll aufbauen
$gesamtProtokoll += $protokoll
$gesamtProtokoll += ""
$gesamtProtokoll += "============================================================"
$gesamtProtokoll += ""
Nach jedem Ordner wird dessen Protokoll an $gesamtProtokoll angehängt.
Die Trennlinie macht die Ergebnisse mehrerer Ordner übersichtlicher.
Wenn die Zwischenablage aktiviert ist, enthält sie am Ende die Protokolle aller verarbeiteten Ordner.
Starter-Batchdatei der SendTo-Variante
Die Datei heißt:
004_sendto_dateien_nach_typ_sortieren_starter_batch_test.bat
@echo off
REM ============================================================
REM TOPTORIALS OFFICE - PowerShell 7 Grundkurs
REM Script: 004_sendto_dateien_nach_typ_sortieren_starter_batch_test.bat
REM Beschreibung: Startet das PowerShell-7-SendTo-Skript im Testmodus.
REM Autor: Chris
REM YouTube: https://www.youtube.com/@TOPTORIALS-OFFICE
REM Webseite: https://www.toptorials.com
REM Version: 1.0
REM Stand: 2026-08-03
REM
REM Hinweis:
REM Solange _test im Dateinamen steht, wird -Test uebergeben.
REM Fuer die echte Ausfuehrung _test aus dem Dateinamen entfernen.
REM ============================================================
chcp 65001 >nul
cd /d "%~dp0"
echo %~n0 | find /i "_test" >nul
if not errorlevel 1 (
pwsh -ExecutionPolicy Bypass -File "004_sendto_dateien_nach_typ_sortieren.ps1" -Test %*
) else (
pwsh -ExecutionPolicy Bypass -File "004_sendto_dateien_nach_typ_sortieren.ps1" %*
)
Besonderheit der SendTo-Starterdatei
Die SendTo-Starterdatei verwendet zusätzlich:
%*
%* enthält alle an die Batchdatei übergebenen Argumente.
Das können beispielsweise mehrere vollständige Ordnerpfade sein.
Die Batchdatei gibt diese Argumente an PowerShell weiter.
Durch:
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Ordner
werden die übergebenen Pfade anschließend im PowerShell-Array $Ordner gespeichert.
SendTo-Verknüpfung einrichten
Damit die SendTo-Variante im Windows-Explorer verwendet werden kann, wird eine Verknüpfung zur Starter-Batchdatei benötigt.
Den SendTo-Ordner öffnen:
Windows-Taste + R
shell:sendto
Enter
In diesem Ordner wird eine Verknüpfung zu folgender Datei abgelegt:
004_sendto_dateien_nach_typ_sortieren_starter_batch_test.bat
Danach können ein oder mehrere Ordner markiert und über das Kontextmenü an das Skript gesendet werden.
Wird die Starterdatei später für den Echtmodus umbenannt, muss die vorhandene Verknüpfung gegebenenfalls aktualisiert oder neu erstellt werden.
Optionale Ausgaben
Für beide Varianten sind vier Ausgabemöglichkeiten vorbereitet.
Nur Bildschirmausgabe
$logDateiErstellen = $false
$zwischenablageVerwenden = $false
Bildschirmausgabe und Logdatei
$logDateiErstellen = $true
$zwischenablageVerwenden = $false
Bildschirmausgabe und Zwischenablage
$logDateiErstellen = $false
$zwischenablageVerwenden = $true
Bildschirmausgabe, Logdatei und Zwischenablage
$logDateiErstellen = $true
$zwischenablageVerwenden = $true
Die SendTo-Version erstellt bei aktivierter Logausgabe für jeden verarbeiteten Ordner eine eigene Logdatei.
Die Zwischenablage enthält bei mehreren Ordnern ein gemeinsames Gesamtprotokoll.
Typische Fehler und Hinweise
PowerShell 7 wurde nicht gefunden
Die Starterdateien verwenden:
pwsh
Dieser Befehl gehört zu PowerShell 7.
Falls pwsh nicht gefunden wird, muss geprüft werden, ob PowerShell 7 installiert und über die Umgebungsvariable PATH erreichbar ist.
Das PowerShell-Skript wurde nicht gefunden
PowerShell-Datei und Starter-Batchdatei müssen gemeinsam im gleichen Ordner liegen.
Die Dateinamen müssen genau mit den Namen im Startercode übereinstimmen.
Die SendTo-Datei wurde per Doppelklick gestartet
Beim direkten Doppelklick wird kein Ordner übergeben.
Dann erscheint:
Bitte sende mindestens einen Ordner an dieses Skript.
Die SendTo-Variante sollte über das Kontextmenü Senden an gestartet werden.
Eine einzelne Datei wurde an die SendTo-Variante übergeben
Die SendTo-Version dieses Kursteils verarbeitet Ordner.
Einzelne Dateien werden als ungültige Eingabe übersprungen.
Eine Datei wurde nicht sortiert
Prüfe, ob ihre Dateiendung in $kategorien eingetragen ist.
Unbekannte Dateitypen bleiben in Version 1.0 ohne zusätzliche Meldung im Ausgangsordner liegen.
Eine Datei wurde wegen eines Namenskonflikts übersprungen
Im Zielordner existiert bereits eine Datei mit demselben Namen.
Das Skript überschreibt oder benennt diese Datei nicht automatisch um.
Es wurden im Echtmodus alle Kategorieordner erstellt
Das ist in Version 1.0 vorgesehen.
Beim echten Lauf werden alle in $kategorien eingetragenen Zielordner erstellt, auch wenn einzelne Kategorien momentan keine passenden Dateien enthalten.
Es wurde keine Logdatei erstellt
Die Logausgabe ist standardmäßig ausgeschaltet.
Zum Aktivieren muss eine vorbereitete Variante mit:
$logDateiErstellen = $true
verwendet werden.
Ein Fehler beim Erstellen oder Verschieben ist aufgetreten
Version 1.0 enthält noch keine eigene Fehlerbehandlung mit try und catch.
Die von PowerShell angezeigte Fehlermeldung sollte deshalb direkt im Fenster geprüft werden.
Nützliche PowerShell-Begriffe aus diesem Teil
| Begriff | Bedeutung |
|---|---|
param |
Definiert Parameter eines PowerShell-Skripts |
[switch]$Test |
Schaltet den Testmodus ein |
[string[]]$Ordner |
Array für mehrere übergebene Ordnerpfade |
ValueFromRemainingArguments |
Sammelt verbleibende Startargumente im angegebenen Parameter |
Get-Location |
Liefert den aktuellen Arbeitsordner |
Resolve-Path |
Ermittelt einen vollständigen vorhandenen Pfad |
[ordered]@{} |
Erstellt eine geordnete Hashtable |
@() |
Erstellt ein Array |
foreach |
Verarbeitet mehrere Einträge nacheinander |
Where-Object |
Filtert Objekte anhand einer Bedingung |
$_ |
Aktuelles Objekt innerhalb einer Pipeline |
.Extension |
Liefert die Dateiendung |
ToLowerInvariant() |
Wandelt Text zuverlässig in Kleinbuchstaben um |
-in |
Prüft, ob ein Wert in einer Sammlung enthalten ist |
Get-ChildItem |
Liest Dateien und Ordner aus |
Join-Path |
Verbindet Bestandteile zu einem Pfad |
Test-Path |
Prüft, ob eine Datei oder ein Ordner existiert |
New-Item |
Erstellt hier einen neuen Ordner |
Move-Item |
Verschiebt eine Datei |
Read-Host |
Liest eine Eingabe ein |
Write-Host |
Gibt Text im PowerShell-Fenster aus |
Set-Content |
Schreibt Inhalt in eine Datei |
Set-Clipboard |
Kopiert Text in die Zwischenablage |
-join |
Verbindet mehrere Textelemente |
continue |
Springt zum nächsten Schleifendurchlauf |
exit |
Beendet das Skript |
%* |
Alle an eine Batchdatei übergebenen Argumente |
Was haben wir gelernt?
In diesem Teil wurden mehrere wichtige Grundlagen gezeigt:
Mit [switch]$Test lässt sich ein Testmodus einschalten.
Get-Location liefert den aktuellen Arbeitsordner.
Eine geordnete Hashtable verbindet Kategorien mit Dateiendungen.
Get-ChildItem erfasst die Dateien im Basisordner.
Where-Object filtert Dateien nach ihrer Endung.
Extension liefert die Dateiendung einer Datei.
Join-Path setzt Pfade sicher zusammen.
Test-Path erkennt vorhandene Ordner und Zieldateien.
New-Item erstellt im Echtmodus die Kategorieordner.
Move-Item verschiebt Dateien in die passenden Zielordner.
Vorhandene Zieldateien werden nicht überschrieben.
Unbekannte Dateitypen bleiben im Ausgangsordner liegen.
Arrays sammeln Meldungen für ein Protokoll.
Set-Content schreibt das Protokoll in eine Logdatei.
Set-Clipboard kopiert das Protokoll in die Zwischenablage.
%* übergibt in Batch alle ausgewählten Ordner.
[string[]]$Ordner speichert die übergebenen Ordnerpfade.
foreach verarbeitet mehrere SendTo-Ordner nacheinander.
Damit haben wir eine einfache Version für den aktuellen Ordner und eine praktische SendTo-Variante erstellt.
Die einfache Variante eignet sich besonders gut zum Lernen und Testen.
Die SendTo-Variante ist praktisch für den Alltag, weil mehrere Ordner direkt aus dem Windows-Explorer an das Skript übergeben werden können.
Video zu diesem Tutorial:
Das könnte Dich auch interessieren
Keine Einträge gefunden

