PowerShell 7 Grundkurs Teil 009: Projektordner mit Datum und Logdatei sichern
Worum geht es in diesem Teil?
In diesem Teil des PowerShell-7-Grundkurses erstellen wir mit robocopy eine datierte Sicherung eines vollständigen Projektordners. Jeder echte Sicherungslauf erhält einen neuen Unterordner mit Datum und Uhrzeit im Namen. Zusätzlich wird im jeweiligen Backupordner eine Protokolldatei gespeichert.
Aus einem Projektordner wie:
C:\Projekte\MeinProjekt
entsteht beispielsweise folgende Sicherungsstruktur:
C:\Projekte\MeinProjekt
└── Backups
└── Backup_2026-09-06_20-15-30
└── backup_protokoll_2026-09-06_20-15-30.log

Backups Ordner mit Backup
Die eigentlichen Projektdateien und Unterordner werden ebenfalls in den neuen Backupordner kopiert. Der Ordner Backups wird dabei ausdrücklich von der Quelle ausgeschlossen. Dadurch kopiert ein späterer Sicherungslauf nicht die bereits vorhandenen Backups erneut mit.
Wir verwenden zwei Varianten:
- Den Ordner sichern, in dem das PowerShell-Skript und die Starter-Batchdatei liegen.
- Einen oder mehrere Projektordner über das Windows-Menü Senden an übergeben und einzeln sichern.
Was ist das Ziel?
Projektordner sollen mit wenigen Schritten in einen neuen, eindeutig datierten Backupordner kopiert werden. Anhand des Zeitstempels lässt sich später erkennen, wann die jeweilige Sicherung erstellt wurde.
Die Protokolldatei hält die Ausgabe von robocopy fest. Damit lässt sich auch nach dem Sicherungslauf nachvollziehen, welche Dateien und Ordner verarbeitet wurden und ob Fehler aufgetreten sind.
Warum ist dieser Teil wichtig?
In diesem Tutorial verbinden wir bekannte PowerShell-Grundlagen mit einem bewährten Windows-Kopierwerkzeug:
Get-Dateerzeugt einen einheitlichen Zeitstempel.$PSScriptRootliefert den Ordner des normalen PowerShell-Skripts.Join-Pathsetzt vollständige Pfade sicher aus einzelnen Bestandteilen zusammen.Get-Commandprüft, obrobocopy.exeverfügbar ist.- Ein Array sammelt die einzelnen Argumente für
robocopy. - Der Testmodus verwendet
/Lund zeigt nur an, was kopiert würde. /XDund/XFschließen festgelegte Ordner und Dateien aus./TEEzeigt die Ausgabe an und/UNILOGschreibt sie zusätzlich in eine Unicode-Protokolldatei.$LASTEXITCODEübernimmt den Rückgabecode vonrobocopy.- Die SendTo-Version verarbeitet mehrere übergebene Projektordner nacheinander.
Hinweis zur Kursreihe
Dieses Tutorial gehört zum PowerShell-7-Grundkurs. Der Aufbau orientiert sich an den entsprechenden Aufgaben im Batch- und Python-Grundkurs. Dadurch lassen sich die unterschiedlichen Schreibweisen und Möglichkeiten der drei Sprachen direkt miteinander vergleichen.
Die PowerShell-Version bleibt bewusst gut nachvollziehbar. Sie ergänzt die reine Batchlösung aber um eine zuverlässige Auswertung der besonderen robocopy-Rückgabecodes und um eine übersichtliche Zusammenfassung bei der SendTo-Verarbeitung.
Downloads zu diesem Teil
Download PowerShell 7 Grundkurs: 009_Backup_mit_Datum als ZIP-Datei.Entpacken nach:
C:\TOPTORIALS_CODE\010_PowerShell_7_Grundkurs
Der Hauptordner für diesen Teil lautet:
C:\TOPTORIALS_CODE\010_PowerShell_7_Grundkurs\009_Backup_mit_Datum
Testumgebung zum Mitmachen
Verwende für die ersten Durchläufe ausschließlich Kopien unwichtiger Dateien. Lege am besten einen eigenen Test-Projektordner mit einigen Dateien und Unterordnern an. So kannst du die Ausschlüsse, die Vorschau und den späteren Echtlauf gefahrlos kontrollieren.
Testumgebung für Windows-Automatisierung:Download TOPTORIALS_Testdaten_Windows_Automatisierung_V001.zip
Entpacken nach:
C:\TOPTORIALS_CODE\1000_TESTBEREICH
Für die Übungen zu diesem Teil kannst du darin beispielsweise einen eigenen Projektordner für die Backup-Tests verwenden.
Sicherheitshinweis
Wichtig:Prüfe vor dem ersten Start den tatsächlichen Dateinamen der Starter-Batchdatei. Nur wenn darin _test vorkommt, wird der Testmodus aktiviert.
Im Fenster muss Testmodus: JA erscheinen. robocopy erhält dann den Schalter /L und zeigt lediglich an, welche Dateien kopiert würden. Es werden keine Backupordner und keine Protokolldateien angelegt.
Ohne _test startet der Echtmodus. Bevor ein Backupordner erstellt wird, muss die Sicherheitsabfrage zusätzlich mit JA bestätigt werden.
Die Skripte verwenden bewusst nicht /MIR. Vorhandene Dateien werden daher nicht durch eine Spiegelungsfunktion aus dem Ziel gelöscht. Trotzdem solltest du die Skripte zuerst mit unwichtigen Testdaten ausprobieren und wichtige Daten zusätzlich sichern.
Die Nutzung dieses Codes erfolgt auf eigene Verantwortung. Es wird keine Haftung für Datenverluste, unbeabsichtigte Änderungen oder andere Schäden übernommen, die durch die Verwendung des Skripts entstehen könnten.
Voraussetzungen
- Eine Windows-Umgebung mit dem Systemprogramm
robocopy.exe. - PowerShell 7, erreichbar über den Befehl
pwsh. - Ausreichende Lese- und Schreibrechte in den zu sichernden Projektordnern.
- PowerShell-Skript und passende Starter-Batchdatei liegen jeweils gemeinsam in ihrem Kursordner.
- Für SendTo wird eine Verknüpfung zur Starter-Batchdatei im Windows-Ordner Senden an angelegt. Die Batchdatei selbst wird nicht dorthin kopiert.
Enthaltene Ordner und Dateien
Die beiden Varianten liegen in diesen Kursordnern:
C:\TOPTORIALS_CODE\010_PowerShell_7_Grundkurs\009_Backup_mit_Datum\02_Projektordner_sichern_mit_Log
C:\TOPTORIALS_CODE\010_PowerShell_7_Grundkurs\009_Backup_mit_Datum\03_SendTo_Projektordner_sichern_mit_Log
| Ordner | PowerShell-Skript | Starter im Testmodus |
|---|---|---|
02_Projektordner_sichern_mit_Log |
009_Backup_mit_Datum_mit_Log.ps1 |
009_backup_mit_datum_mit_log_starter_batch_test.bat |
03_SendTo_Projektordner_sichern_mit_Log |
009_SendTo_Backup_mit_Datum_mit_Log.ps1 |
009_sendto_backup_mit_datum_mit_log_starter_batch_test.bat |
Für den Echtmodus wird nur _test aus dem Namen des jeweiligen Starters entfernt. Die Namen der PowerShell-Dateien bleiben unverändert, da die Batchdateien genau diese Namen im -File-Aufruf verwenden.
Wo werden die Backups gespeichert?
Normale Variante
Die normale Variante verwendet den Ordner des PowerShell-Skripts als Quelle. Das Skript ermittelt ihn mit $PSScriptRoot. Der Unterordner Backups entsteht daher im gleichen Projektordner, in dem auch das Skript und der Starter liegen.
02_Projektordner_sichern_mit_Log
├── 009_Backup_mit_Datum_mit_Log.ps1
├── 009_backup_mit_datum_mit_log_starter_batch.bat
└── Backups
└── Backup_2026-09-06_20-15-30
SendTo-Variante
Bei SendTo wird nicht der Skriptordner gesichert. Die ausgewählten Projektordner werden vom Windows-Explorer als Argumente übergeben. Jeder gültige Projektordner erhält seinen eigenen Unterordner Backups.
Ausgewählter Projektordner
└── Backups
└── Backup_2026-09-06_20-15-30
Wichtig für SendTo:Das PowerShell-Skript und die Starter-Batchdatei bleiben gemeinsam im Kursordner. Im Ordner Senden an wird lediglich eine Verknüpfung zur Batchdatei angelegt. Wird stattdessen nur die Batchdatei dorthin kopiert, kann sie das daneben erwartete PowerShell-Skript nicht finden.
Zeitstempel, Backupordner und Protokolldatei
Der Zeitstempel wird einmal pro Skriptlauf erzeugt:
$zeitstempel = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
Ein möglicher Wert lautet:
2026-09-06_20-15-30
Daraus entstehen der Backupordner und der Name der Protokolldatei:
Backup_2026-09-06_20-15-30
backup_protokoll_2026-09-06_20-15-30.log
Bei der SendTo-Variante erhalten alle im selben Durchlauf ausgewählten Projektordner denselben Zeitstempel. Da jeder Projektordner seinen eigenen Backups-Ordner besitzt, entstehen dadurch keine Konflikte zwischen den unterschiedlichen Quellen.
Welche Ordner und Dateien werden ausgeschlossen?
Diese Ordnernamen sind in beiden PowerShell-Skripten vorbereitet:
Temp
Cache
Alte Dateien
Zusätzlich wird immer der vollständige Pfad des jeweiligen Backups-Ordners ausgeschlossen. Das ist besonders wichtig, weil sich das Ziel innerhalb des Quellordners befindet. Ohne diesen Ausschluss könnten vorhandene Sicherungen bei einem späteren Durchlauf erneut mitkopiert werden.
Diese Dateien beziehungsweise Dateimuster werden ausgeschlossen:
desktop.ini
thumbs.db
*.tmp
*.log
*.bak
Die Ausschlusslisten stehen am Anfang der Skripte und können dort bei Bedarf angepasst oder erweitert werden.
Die wichtigsten robocopy-Schalter
| Schalter | Bedeutung in diesem Tutorial |
|---|---|
/E |
Kopiert Unterordner einschließlich leerer Unterordner. |
/L |
Listet im Testmodus nur auf, was kopiert würde. |
/XJ |
Schließt Verzeichnisverknüpfungen beziehungsweise Junction Points aus. |
/R:1 |
Versucht einen fehlgeschlagenen Kopiervorgang nur einmal erneut. |
/W:1 |
Wartet vor einem erneuten Versuch eine Sekunde. |
/XD |
Schließt die danach angegebenen Verzeichnisse aus. |
/XF |
Schließt die danach angegebenen Dateien und Dateimuster aus. |
/TEE |
Zeigt die Ausgabe im Fenster an und reicht sie gleichzeitig an die Protokollierung weiter. |
/UNILOG |
Speichert die Ausgabe in einer Unicode-Protokolldatei. |
Warum wird /MIR nicht verwendet?
/MIR würde eine Quelle und ein Ziel spiegeln. Dabei können im Ziel vorhandene Elemente gelöscht werden, wenn sie in der Quelle nicht mehr vorhanden sind. Für unsere datierten, voneinander getrennten Backupordner ist diese Löschfunktion nicht erforderlich. Deshalb verwenden die Skripte bewusst kein /MIR.
Testmodus und Echtmodus
Der Starter erkennt den Modus an seinem eigenen Dateinamen:
- Enthält der Name
_test, wird das PowerShell-Skript mit-Testgestartet. - Fehlt
_test, startet das Skript im Echtmodus.
Im Testmodus wird /L in die Argumentliste von robocopy aufgenommen. robocopy untersucht die Quelle und zeigt die vorgesehenen Kopiervorgänge an, führt sie aber nicht aus.
Im Echtmodus wird vor dem Anlegen des Zielordners gefragt:
Backup jetzt erstellen? Bitte JA eingeben
Die SendTo-Version fragt entsprechend, ob alle angezeigten Backups erstellt werden sollen. Nur nach der richtigen Bestätigung beginnt der Kopiervorgang.
Optional auch ein kleines ja akzeptieren
Die getesteten Skripte verwenden bei der Sicherheitsabfrage:
if ($antwort -cne "JA") {
Der Vergleichsoperator -cne berücksichtigt die Groß- und Kleinschreibung. Daher wird nur die exakt geschriebene Eingabe JA akzeptiert. Ein kleines ja führt zum Abbruch.
Sollen auch ja, Ja und jA akzeptiert werden, kann in beiden PowerShell-Skripten -cne durch -ne ersetzt werden:
if ($antwort -ne "JA") {
Der Unterschied:-cne bedeutet sinngemäß „ungleich unter Beachtung der Groß- und Kleinschreibung“. -ne vergleicht Zeichenketten in PowerShell standardmäßig ohne Beachtung der Groß- und Kleinschreibung.
Die optionale Änderung betrifft in jedem der beiden Skripte genau eine Zeile.
Variante 1: Projektordner mit Logdatei sichern
So wird die Variante angewendet
Das PowerShell-Skript und die Starter-Batchdatei aus 02_Projektordner_sichern_mit_Log liegen gemeinsam in dem Projektordner, der gesichert werden soll.
Starte zuerst:
009_backup_mit_datum_mit_log_starter_batch_test.bat
Prüfe die Anzeige Testmodus: JA und die von robocopy ausgegebene Vorschau. Im Testmodus darf noch kein Ordner Backups entstehen.
Für den Echtlauf wird eine Kopie des Starters angelegt und nur _test aus ihrem Dateinamen entfernt:
009_backup_mit_datum_mit_log_starter_batch.bat
Starte diesen Echtmodus erst nach einem erfolgreichen Test und bestätige die Sicherung mit JA.
Vollständiges PowerShell-7-Skript
Dateiname: 009_Backup_mit_Datum_mit_Log.ps1
#requires -Version 7.0
<#
TOPTORIALS OFFICE
PowerShell 7 Grundkurs - Teil 009
Datei: 009_Backup_mit_Datum_mit_Log.ps1
Dieses Skript sichert den Ordner, in dem das Skript liegt.
Für jeden Sicherungslauf entsteht im Unterordner "Backups" ein neuer
Backupordner mit Datum und Uhrzeit im Namen.
Im Testmodus zeigt robocopy mit /L lediglich an, was kopiert würde.
Es werden dabei keine Backupordner und keine Protokolldatei angelegt.
#>
param(
[switch]$Test
)
# -----------------------------------------------------------------------------
# Einstellungen
# -----------------------------------------------------------------------------
$backupHauptordner = "Backups"
$ausgeschlosseneOrdner = @(
"Temp"
"Cache"
"Alte Dateien"
)
$ausgeschlosseneDateien = @(
"desktop.ini"
"thumbs.db"
"*.tmp"
"*.log"
"*.bak"
)
# -----------------------------------------------------------------------------
# Pfade für diesen Sicherungslauf vorbereiten
# -----------------------------------------------------------------------------
$zeitstempel = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$quellordner = $PSScriptRoot
$backupPfad = Join-Path -Path $quellordner -ChildPath $backupHauptordner
$zielordner = Join-Path -Path $backupPfad -ChildPath "Backup_$zeitstempel"
$logdatei = Join-Path -Path $zielordner -ChildPath "backup_protokoll_$zeitstempel.log"
try {
$robocopy = Get-Command -Name "robocopy.exe" -ErrorAction Stop
}
catch {
Write-Host "FEHLER: robocopy.exe wurde nicht gefunden." -ForegroundColor Red
Write-Host "Dieses Skript ist für Windows mit PowerShell 7 vorgesehen." -ForegroundColor Yellow
exit 1
}
Write-Host ""
Write-Host "Backup mit Datum und Protokolldatei" -ForegroundColor Cyan
Write-Host "-----------------------------------" -ForegroundColor Cyan
Write-Host "Quellordner: $quellordner"
Write-Host "Backup-Hauptordner: $backupPfad"
Write-Host "Neuer Backupordner: $zielordner"
Write-Host "Protokolldatei: $logdatei"
Write-Host "Testmodus: $(if ($Test) { 'JA' } else { 'NEIN' })"
Write-Host "Ausgeschlossene Ordner: $($ausgeschlosseneOrdner -join ', ')"
Write-Host "Ausgeschlossene Dateien: $($ausgeschlosseneDateien -join ', ')"
Write-Host ""
if ($Test) {
Write-Host "TESTMODUS: Es wird nur angezeigt, was robocopy kopieren würde." -ForegroundColor Yellow
Write-Host "Es werden keine Ordner und keine Protokolldatei angelegt." -ForegroundColor Yellow
}
else {
$antwort = Read-Host "Backup jetzt erstellen? Bitte JA eingeben"
if ($antwort -cne "JA") {
Write-Host "Abgebrochen. Es wurden keine Dateien kopiert." -ForegroundColor Yellow
exit 0
}
try {
if (Test-Path -LiteralPath $zielordner) {
throw "Der Zielordner existiert bereits: $zielordner"
}
[void](New-Item -ItemType Directory -Path $zielordner -ErrorAction Stop)
}
catch {
Write-Host "FEHLER: Der Backupordner konnte nicht angelegt werden." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
exit 1
}
}
# Die Argumente werden als Liste aufgebaut. Dadurch bleiben auch Pfade mit
# Leerzeichen beim Aufruf von robocopy jeweils ein zusammengehöriges Argument.
$robocopyArgumente = @(
$quellordner
$zielordner
"/E"
"/XJ"
"/R:1"
"/W:1"
)
if ($Test) {
$robocopyArgumente += "/L"
}
else {
$robocopyArgumente += "/TEE"
$robocopyArgumente += "/UNILOG:$logdatei"
}
$robocopyArgumente += "/XD"
$robocopyArgumente += $backupPfad
$robocopyArgumente += $ausgeschlosseneOrdner
$robocopyArgumente += "/XF"
$robocopyArgumente += $ausgeschlosseneDateien
Write-Host ""
Write-Host "robocopy wird gestartet ..." -ForegroundColor Cyan
Write-Host ""
& $robocopy.Source @robocopyArgumente
$robocopyCode = $LASTEXITCODE
Write-Host ""
# robocopy verwendet eigene Rückgabecodes. Die Werte 0 bis 7 melden keinen
# schwerwiegenden Kopierfehler. Erst ein Wert ab 8 bedeutet einen Fehlschlag.
if ($robocopyCode -ge 8) {
Write-Host "FEHLER: robocopy meldet den Rückgabecode $robocopyCode." -ForegroundColor Red
exit $robocopyCode
}
if ($Test) {
Write-Host "Test abgeschlossen. Es wurden keine Dateien kopiert." -ForegroundColor Green
}
else {
Write-Host "Backup erfolgreich abgeschlossen." -ForegroundColor Green
Write-Host "Backupordner: $zielordner"
Write-Host "Protokoll: $logdatei"
}
exit 0
So funktioniert die normale Variante
Der Parameterblock enthält einen Schalter:
param(
[switch]$Test
)
Wird das Skript mit -Test aufgerufen, enthält $Test einen aktivierten Schalterwert. Ohne diesen Parameter bleibt der Schalter deaktiviert.
Die drei Pfadvariablen bauen aufeinander auf:
$quellordner = $PSScriptRoot
$backupPfad = Join-Path -Path $quellordner -ChildPath $backupHauptordner
$zielordner = Join-Path -Path $backupPfad -ChildPath "Backup_$zeitstempel"
$PSScriptRoot ist der Ordner, in dem die PowerShell-Datei liegt. Join-Path hängt daran zunächst Backups und anschließend den datierten Backupnamen an.
Vor der weiteren Verarbeitung prüft:
$robocopy = Get-Command -Name "robocopy.exe" -ErrorAction Stop
ob Windows das Programm robocopy.exe finden kann. Tritt dabei ein Fehler auf, gelangt der Ablauf in den catch-Block und wird mit einer verständlichen Meldung beendet.
Im Echtmodus wird der Zielordner erst nach der Bestätigung angelegt. Test-Path verhindert, dass ein bereits vorhandener Zielordner unbemerkt erneut verwendet wird.
Die robocopy-Argumentliste
Die Argumente für das externe Programm werden zunächst in einem Array gesammelt:
$robocopyArgumente = @(
$quellordner
$zielordner
"/E"
"/XJ"
"/R:1"
"/W:1"
)
Jeder Eintrag bildet ein eigenes Argument. Dadurch bleibt beispielsweise ein Pfad wie C:\Meine Projekte\Projekt 01 auch mit seinen Leerzeichen ein zusammengehöriger Wert.
Abhängig vom Modus werden weitere Einträge ergänzt. Im Testmodus kommt /L hinzu. Im Echtmodus werden stattdessen /TEE und der vollständige /UNILOG-Eintrag ergänzt.
Der eigentliche Aufruf lautet:
& $robocopy.Source @robocopyArgumente
Der Aufrufoperator & startet das Programm, dessen vollständiger Pfad in $robocopy.Source gespeichert ist. Mit @robocopyArgumente werden die einzelnen Einträge des Arrays als getrennte Argumente an robocopy übergeben.
Die robocopy-Rückgabecodes
Direkt nach dem externen Programm übernimmt PowerShell dessen Rückgabecode:
$robocopyCode = $LASTEXITCODE
Bei robocopy bedeutet ein Wert größer als null nicht automatisch einen Fehler. Die Werte 0 bis 7 beschreiben unterschiedliche erfolgreiche oder nicht schwerwiegende Ergebnisse. Erst ab 8 meldet robocopy einen wirklichen Fehlschlag.
if ($robocopyCode -ge 8) {
Write-Host "FEHLER: robocopy meldet den Rückgabecode $robocopyCode."
exit $robocopyCode
}
Diese Auswertung ist ein wichtiger Unterschied zu vielen normalen Programmen, bei denen ausschließlich der Rückgabecode null als erfolgreich gilt.
Starter-Batchdatei für die normale Variante
Dateiname: 009_backup_mit_datum_mit_log_starter_batch_test.bat
@echo off
setlocal DisableDelayedExpansion
REM =============================================================================
REM TOPTORIALS OFFICE - PowerShell 7 Grundkurs, Teil 009
REM Datei: 009_backup_mit_datum_mit_log_starter_batch_test.bat
REM
REM Diese Starter-Batchdatei startet das zugehoerige PowerShell-7-Skript.
REM Enthaelt ihr eigener Dateiname den Text "_test", wird das Skript mit dem
REM Schalter -Test aufgerufen. In diesem Modus zeigt robocopy nur an, welche
REM Dateien gesichert wuerden, ohne einen Backupordner anzulegen.
REM
REM Fuer den Echtmodus kann eine Kopie dieser Datei angelegt und "_test" aus
REM ihrem Dateinamen entfernt werden. Vor dem echten Backup fragt das
REM PowerShell-Skript zusaetzlich nach der ausdruecklichen Bestaetigung JA.
REM =============================================================================
chcp 65001 >nul
REM In den Ordner wechseln, in dem diese Starter-Batchdatei liegt.
cd /d "%~dp0"
if errorlevel 1 (
echo FEHLER: Der Skriptordner konnte nicht geoeffnet werden.
pause
exit /b 1
)
REM Pruefen, ob der eigene Dateiname den Text "_test" enthaelt.
echo("%~n0" | find /i "_test" >nul
if not errorlevel 1 (
pwsh -NoProfile -ExecutionPolicy Bypass -File "009_Backup_mit_Datum_mit_Log.ps1" -Test
) else (
pwsh -NoProfile -ExecutionPolicy Bypass -File "009_Backup_mit_Datum_mit_Log.ps1"
)
pause
So funktioniert der Starter
cd /d "%~dp0" wechselt in den Ordner der ausgeführten Batchdatei. Das ist hier vor allem für den zuverlässigen relativen -File-Aufruf wichtig.
%~n0 liefert den Namen der aktuell ausgeführten Batchdatei ohne Pfad und Dateiendung. find /i "_test" prüft, ob dieser Name den Text _test enthält.
pwsh startet PowerShell 7. -NoProfile verhindert, dass persönliche PowerShell-Profile den kontrollierten Skriptstart beeinflussen. -ExecutionPolicy Bypass gilt nur für die gestartete Sitzung und erteilt keine zusätzlichen Datei- oder Administratorrechte. Mit -File folgt der Name des auszuführenden Skripts.
Variante 2: Projektordner über „Senden an“ sichern
SendTo-Verknüpfung einrichten
Das PowerShell-Skript und die Starter-Batchdatei bleiben gemeinsam in diesem Kursordner:
C:\TOPTORIALS_CODE\010_PowerShell_7_Grundkurs\009_Backup_mit_Datum\03_SendTo_Projektordner_sichern_mit_Log
Drücke Windows + R, gib folgenden Befehl ein und bestätige ihn:
shell:sendto
Erstelle in diesem Ordner eine Verknüpfung zur gewünschten Starter-Batchdatei. Zum Testen verweist die Verknüpfung auf die Variante mit _test. Für den Echtmodus kann später eine zweite Verknüpfung zum umbenannten Echtmodus-Starter angelegt werden.
Kopiere nicht nur die Batchdatei in den SendTo-Ordner. Sie würde dort nach dem PowerShell-Skript im falschen Ordner suchen und eine Meldung ausgeben, dass die angegebene Skriptdatei nicht erkannt oder gefunden wurde.
So wird die SendTo-Variante angewendet
- Markiere im Windows-Explorer einen oder mehrere Projektordner.
- Öffne mit der rechten Maustaste das Kontextmenü.
- Wähle Senden an und anschließend die Verknüpfung zum Teststarter.
- Kontrolliere die angezeigten Quellen, Ziele und Protokollpfade.
- Prüfe anschließend die Vorschau von
robocopy.
Dateien und ungültige Pfade werden übersprungen. Die SendTo-Version verarbeitet ausschließlich vorhandene Ordner.
Vollständiges PowerShell-7-Skript
Dateiname: 009_SendTo_Backup_mit_Datum_mit_Log.ps1
#requires -Version 7.0
<#
TOPTORIALS OFFICE
PowerShell 7 Grundkurs - Teil 009, SendTo-Variante
Datei: 009_SendTo_Backup_mit_Datum_mit_Log.ps1
Dieses Skript erhält einen oder mehrere Ordner aus dem Windows-Explorer.
In jedem gültigen Quellordner entsteht unter "Backups" ein neuer
Backupordner mit Datum, Uhrzeit und eigener Protokolldatei.
Im Testmodus zeigt robocopy mit /L lediglich an, was kopiert würde.
Es werden dabei keine Backupordner und keine Protokolldateien angelegt.
#>
param(
[switch]$Test,
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Pfade
)
# -----------------------------------------------------------------------------
# Einstellungen
# -----------------------------------------------------------------------------
$backupHauptordner = "Backups"
$ausgeschlosseneOrdner = @(
"Temp"
"Cache"
"Alte Dateien"
)
$ausgeschlosseneDateien = @(
"desktop.ini"
"thumbs.db"
"*.tmp"
"*.log"
"*.bak"
)
try {
$robocopy = Get-Command -Name "robocopy.exe" -ErrorAction Stop
}
catch {
Write-Host "FEHLER: robocopy.exe wurde nicht gefunden." -ForegroundColor Red
Write-Host "Dieses Skript ist für Windows mit PowerShell 7 vorgesehen." -ForegroundColor Yellow
exit 1
}
if (-not $Pfade -or $Pfade.Count -eq 0) {
Write-Host "FEHLER: Es wurden keine Ordner übergeben." -ForegroundColor Red
Write-Host "Bitte einen oder mehrere Ordner über 'Senden an' starten." -ForegroundColor Yellow
exit 1
}
# Nur vorhandene Ordner übernehmen. Mehrfach übergebene Ordner werden nur
# einmal in die Liste aufgenommen.
$quellordner = @()
foreach ($pfad in $Pfade) {
try {
$element = Get-Item -LiteralPath $pfad -ErrorAction Stop
if (-not $element.PSIsContainer) {
Write-Host "ÜBERSPRUNGEN: Kein Ordner: $($element.FullName)" -ForegroundColor Yellow
continue
}
if ($quellordner -notcontains $element.FullName) {
$quellordner += $element.FullName
}
}
catch {
Write-Host "ÜBERSPRUNGEN: Pfad nicht gefunden: $pfad" -ForegroundColor Yellow
}
}
if ($quellordner.Count -eq 0) {
Write-Host "FEHLER: Es wurde kein gültiger Quellordner gefunden." -ForegroundColor Red
exit 1
}
# Alle ausgewählten Ordner erhalten denselben Zeitstempel. Jeder Ordner bekommt
# aber seinen eigenen Backupordner und seine eigene Protokolldatei.
$zeitstempel = Get-Date -Format "yyyy-MM-dd_HH-mm-ss"
$plaene = @()
foreach ($quelle in $quellordner) {
$backupPfad = Join-Path -Path $quelle -ChildPath $backupHauptordner
$zielordner = Join-Path -Path $backupPfad -ChildPath "Backup_$zeitstempel"
$logdatei = Join-Path -Path $zielordner -ChildPath "backup_protokoll_$zeitstempel.log"
$plaene += [PSCustomObject]@{
Quelle = $quelle
BackupPfad = $backupPfad
Ziel = $zielordner
Protokoll = $logdatei
}
}
Write-Host ""
Write-Host "SendTo-Backup mit Datum und Protokolldatei" -ForegroundColor Cyan
Write-Host "------------------------------------------" -ForegroundColor Cyan
Write-Host "Testmodus: $(if ($Test) { 'JA' } else { 'NEIN' })"
Write-Host "Anzahl der Quellordner: $($plaene.Count)"
Write-Host "Ausgeschlossene Ordner: $($ausgeschlosseneOrdner -join ', ')"
Write-Host "Ausgeschlossene Dateien: $($ausgeschlosseneDateien -join ', ')"
Write-Host ""
for ($index = 0; $index -lt $plaene.Count; $index++) {
$plan = $plaene[$index]
Write-Host "Backup $($index + 1) von $($plaene.Count)" -ForegroundColor Cyan
Write-Host "Quelle: $($plan.Quelle)"
Write-Host "Ziel: $($plan.Ziel)"
Write-Host "Protokoll: $($plan.Protokoll)"
Write-Host ""
}
if ($Test) {
Write-Host "TESTMODUS: Es wird nur angezeigt, was robocopy kopieren würde." -ForegroundColor Yellow
Write-Host "Es werden keine Ordner und keine Protokolldateien angelegt." -ForegroundColor Yellow
}
else {
$antwort = Read-Host "Alle angezeigten Backups jetzt erstellen? Bitte JA eingeben"
if ($antwort -cne "JA") {
Write-Host "Abgebrochen. Es wurden keine Dateien kopiert." -ForegroundColor Yellow
exit 0
}
}
$erfolgreich = 0
$fehlgeschlagen = 0
foreach ($plan in $plaene) {
Write-Host ""
Write-Host "Bearbeite: $($plan.Quelle)" -ForegroundColor Cyan
if (-not $Test) {
try {
if (Test-Path -LiteralPath $plan.Ziel) {
throw "Der Zielordner existiert bereits: $($plan.Ziel)"
}
[void](New-Item -ItemType Directory -Path $plan.Ziel -ErrorAction Stop)
}
catch {
Write-Host "FEHLER: Der Backupordner konnte nicht angelegt werden." -ForegroundColor Red
Write-Host $_.Exception.Message -ForegroundColor Red
$fehlgeschlagen++
continue
}
}
$robocopyArgumente = @(
$plan.Quelle
$plan.Ziel
"/E"
"/XJ"
"/R:1"
"/W:1"
)
if ($Test) {
$robocopyArgumente += "/L"
}
else {
$robocopyArgumente += "/TEE"
$robocopyArgumente += "/UNILOG:$($plan.Protokoll)"
}
$robocopyArgumente += "/XD"
$robocopyArgumente += $plan.BackupPfad
$robocopyArgumente += $ausgeschlosseneOrdner
$robocopyArgumente += "/XF"
$robocopyArgumente += $ausgeschlosseneDateien
& $robocopy.Source @robocopyArgumente
$robocopyCode = $LASTEXITCODE
# Die robocopy-Rückgabecodes 0 bis 7 sind nicht schwerwiegend.
# Erst ein Wert ab 8 bedeutet, dass der Sicherungslauf fehlgeschlagen ist.
if ($robocopyCode -ge 8) {
Write-Host "FEHLER: robocopy meldet den Rückgabecode $robocopyCode." -ForegroundColor Red
$fehlgeschlagen++
}
else {
if ($Test) {
Write-Host "Test für diesen Ordner abgeschlossen." -ForegroundColor Green
}
else {
Write-Host "Backup für diesen Ordner abgeschlossen." -ForegroundColor Green
}
$erfolgreich++
}
}
Write-Host ""
Write-Host "Zusammenfassung" -ForegroundColor Cyan
Write-Host "---------------" -ForegroundColor Cyan
Write-Host "Erfolgreich: $erfolgreich"
Write-Host "Fehlgeschlagen: $fehlgeschlagen"
if ($Test) {
Write-Host "Im Testmodus wurden keine Dateien kopiert." -ForegroundColor Yellow
}
if ($fehlgeschlagen -gt 0) {
exit 1
}
exit 0
So funktioniert die SendTo-Variante
Der Parameter $Pfade kann mehrere Zeichenketten aufnehmen:
[Parameter(ValueFromRemainingArguments = $true)]
[string[]]$Pfade
ValueFromRemainingArguments sorgt dafür, dass die übrigen übergebenen Argumente in diesem Array gesammelt werden. Die Starter-Batchdatei liefert diese Argumente mit %*.
Für jeden Pfad verwendet das Skript:
$element = Get-Item -LiteralPath $pfad -ErrorAction Stop
-LiteralPath behandelt den übergebenen Pfad wörtlich. Anschließend zeigt $element.PSIsContainer, ob das gefundene Element ein Ordner ist. Dateien werden mit einer entsprechenden Meldung übersprungen.
Diese Bedingung verhindert eine doppelte Aufnahme desselben Ordners:
if ($quellordner -notcontains $element.FullName) {
$quellordner += $element.FullName
}
Danach erstellt das Skript für jeden gültigen Quellordner ein Planobjekt:
$plaene += [PSCustomObject]@{
Quelle = $quelle
BackupPfad = $backupPfad
Ziel = $zielordner
Protokoll = $logdatei
}
Dieses Objekt hält die vier zusammengehörenden Pfade übersichtlich beieinander. Dadurch kann das Skript zunächst alle geplanten Sicherungen anzeigen und sie anschließend nacheinander ausführen.
Die Zähler $erfolgreich und $fehlgeschlagen werden nach jedem robocopy-Lauf aktualisiert. Am Ende erscheint eine gemeinsame Zusammenfassung für alle ausgewählten Projektordner.
Starter-Batchdatei für die SendTo-Variante
Dateiname: 009_sendto_backup_mit_datum_mit_log_starter_batch_test.bat
@echo off
setlocal DisableDelayedExpansion
REM =============================================================================
REM TOPTORIALS OFFICE - PowerShell 7 Grundkurs, Teil 009, SendTo-Variante
REM Datei: 009_sendto_backup_mit_datum_mit_log_starter_batch_test.bat
REM
REM Von dieser Starter-Batchdatei kann eine Verknuepfung im Windows-Ordner
REM "Senden an" angelegt werden. Die im Explorer markierten Ordner werden mit
REM %* gesammelt an das zugehoerige PowerShell-7-Skript weitergereicht.
REM
REM Enthaelt der eigene Dateiname den Text "_test", startet das Skript im
REM Testmodus. robocopy zeigt dann nur an, was gesichert wuerde. Fuer den
REM Echtmodus kann eine Kopie angelegt und "_test" aus dem Namen entfernt
REM werden. Vor dem echten Backup ist zusaetzlich die Eingabe JA erforderlich.
REM =============================================================================
chcp 65001 >nul
REM In den Ordner wechseln, in dem Skript und Starter-Batchdatei liegen.
cd /d "%~dp0"
if errorlevel 1 (
echo FEHLER: Der Skriptordner konnte nicht geoeffnet werden.
pause
exit /b 1
)
REM Pruefen, ob der eigene Dateiname den Text "_test" enthaelt.
echo("%~n0" | find /i "_test" >nul
if not errorlevel 1 (
pwsh -NoProfile -ExecutionPolicy Bypass -File "009_SendTo_Backup_mit_Datum_mit_Log.ps1" -Test %*
) else (
pwsh -NoProfile -ExecutionPolicy Bypass -File "009_SendTo_Backup_mit_Datum_mit_Log.ps1" %*
)
pause
Der Aufbau entspricht dem normalen Starter. Der entscheidende Zusatz ist %*. Damit werden alle an die Batchdatei übergebenen Pfade an PowerShell weitergereicht.
Typische Meldungen
Testmodus
TESTMODUS: Es wird nur angezeigt, was robocopy kopieren würde.
Es werden keine Ordner und keine Protokolldateien angelegt.
Erfolgreiches Backup
Backup erfolgreich abgeschlossen.
Backupordner: C:\Projekte\MeinProjekt\Backups\Backup_2026-09-06_20-15-30
Protokoll: C:\Projekte\MeinProjekt\Backups\Backup_2026-09-06_20-15-30\backup_protokoll_2026-09-06_20-15-30.log
Datei wurde an SendTo übergeben
ÜBERSPRUNGEN: Kein Ordner: C:\Projekte\Beispiel.txt
Pfad wurde nicht gefunden
ÜBERSPRUNGEN: Pfad nicht gefunden: ...
robocopy meldet einen Fehler
FEHLER: robocopy meldet den Rückgabecode 8.
Auch größere Rückgabecodes sind möglich. Der genaue robocopy-Bericht beziehungsweise die Protokolldatei enthält weitere Informationen zur Ursache.
Typische Fehler und mögliche Ursachen
PowerShell 7 wurde nicht gefunden
Die Starter verwenden pwsh. Ist PowerShell 7 nicht installiert oder nicht über die Umgebungsvariable PATH erreichbar, kann der Aufruf nicht funktionieren.
Das PowerShell-Skript wird nicht gefunden
Prüfe, ob die Starter-Batchdatei und das zugehörige PowerShell-Skript gemeinsam im gleichen Kursordner liegen. Prüfe außerdem den exakten Dateinamen im -File-Aufruf.
Bei SendTo muss im Ordner Senden an eine Verknüpfung zur Batchdatei liegen. Wird nur die Batchdatei dorthin kopiert, sucht sie das PowerShell-Skript im SendTo-Ordner und kann es nicht finden.
Der Backupordner entsteht im falschen Projektordner
Prüfe zuerst, ob wirklich die richtige Variante gestartet wurde. Die normale Variante verwendet immer ihren eigenen Skriptordner. Die SendTo-Variante verwendet dagegen die aus dem Explorer übergebenen Projektordner.
Der Starter zeigt Testmodus: NEIN
Der tatsächliche Dateiname des Starters enthält vermutlich nicht _test. Der Hinweis innerhalb eines Kommentars aktiviert den Testmodus nicht.
Die Eingabe ja wird nicht akzeptiert
Die Originalversion verwendet den Vergleich -cne und erwartet deshalb exakt JA. Wenn Groß- und Kleinschreibung keine Rolle spielen sollen, verwende wie weiter oben gezeigt stattdessen -ne.
Bestimmte Dateien fehlen im Backup
Prüfe die Arrays $ausgeschlosseneOrdner und $ausgeschlosseneDateien. Dateien mit den Mustern *.tmp, *.log und *.bak werden in der vorbereiteten Version bewusst nicht kopiert.
Ein Backupordner mit demselben Namen existiert bereits
Der Zeitstempel enthält Sekunden, weshalb dieser Fall normalerweise nur bei zwei sehr schnell gestarteten Läufen oder bei einem bereits vorbereiteten Ordner auftreten kann. Das Skript verwendet den vorhandenen Zielordner nicht erneut, sondern bricht diesen Sicherungslauf mit einer Meldung ab.
Wichtige PowerShell-Begriffe aus diesem Tutorial
$PSScriptRoot- Enthält den vollständigen Ordnerpfad des aktuell ausgeführten PowerShell-Skripts.
Get-Date -Format- Erzeugt hier den Zeitstempel für Backupordner und Protokolldatei.
Join-Path- Setzt einen übergeordneten Pfad und einen untergeordneten Bestandteil zu einem vollständigen Pfad zusammen.
Get-Command- Sucht einen Befehl oder ein Programm und liefert hier den vollständigen Pfad zu
robocopy.exe. [switch]$Test- Definiert einen Schalterparameter für den Testmodus.
@(...)- Erzeugt ein Array, in dem mehrere Werte gesammelt werden können.
+=- Ergänzt hier weitere Einträge an eine vorhandene Argumentliste.
&- Der Aufrufoperator startet den in einer Variablen gespeicherten Programmpfad.
@robocopyArgumente- Übergibt die Arrayelemente als einzelne Argumente an das aufgerufene Programm.
$LASTEXITCODE- Enthält den Rückgabecode des zuletzt ausgeführten nativen Programms.
-ge- Prüft, ob der linke Wert größer oder gleich dem rechten Wert ist.
-cne- Prüft unter Beachtung der Groß- und Kleinschreibung, ob zwei Werte ungleich sind.
-ne- Prüft bei Zeichenketten standardmäßig ohne Beachtung der Groß- und Kleinschreibung, ob zwei Werte ungleich sind.
[void](...)- Unterdrückt die normale Objektausgabe einer Anweisung, wenn nur deren Wirkung benötigt wird.
[PSCustomObject]- Speichert bei SendTo Quelle, Backup-Hauptordner, Ziel und Protokoll als zusammengehörigen Plan.
ValueFromRemainingArguments- Sammelt die übrigen übergebenen Argumente im Parameter
$Pfade. PSIsContainer- Zeigt, ob ein mit
Get-Itemgefundenes Element ein Ordner ist. -notcontains- Prüft hier, ob ein vollständiger Ordnerpfad noch nicht in der Liste enthalten ist.
Wichtige Batch-Begriffe aus diesem Tutorial
setlocal DisableDelayedExpansion- Begrenzt Umgebungsänderungen auf die Batchdatei und deaktiviert die verzögerte Variablenerweiterung.
chcp 65001- Schaltet die Konsole für diesen Ablauf auf die UTF-8-Codepage um.
%~dp0- Liefert Laufwerk und Ordner der ausgeführten Batchdatei.
cd /d- Wechselt den aktuellen Ordner und bei Bedarf auch das Laufwerk.
%~n0- Liefert den Namen der ausgeführten Batchdatei ohne Pfad und Dateiendung.
find /i- Sucht ohne Beachtung der Groß- und Kleinschreibung nach dem Text
_test. if not errorlevel 1- Prüft hier, ob
findden gesuchten Text gefunden hat. %*- Reicht bei SendTo alle an die Batchdatei übergebenen Argumente an PowerShell weiter.
pause- Wartet am Ende auf einen Tastendruck, damit die Ausgabe gelesen werden kann.
Was haben wir in diesem Teil gelernt?
Mit Get-Date erstellen wir einen gemeinsamen Zeitstempel für den Backupordner und die dazugehörige Protokolldatei. Join-Path setzt daraus die vollständigen Zielpfade zusammen.
robocopy kopiert mit /E den vollständigen Projektinhalt einschließlich leerer Unterordner. /XD und /XF lassen festgelegte Ordner und Dateien aus. Der Backup-Hauptordner selbst wird ausgeschlossen, damit vorhandene Sicherungen nicht erneut in ein neues Backup gelangen.
Im Testmodus zeigt /L nur die vorgesehenen Kopiervorgänge an. Im Echtmodus werden die Informationen mit /TEE im Fenster angezeigt und mit /UNILOG in einer Protokolldatei gespeichert. /MIR wird bewusst nicht verwendet.
PowerShell übernimmt den robocopy-Rückgabecode über $LASTEXITCODE. Die Werte 0 bis 7 gelten dabei nicht als schwerwiegender Fehler. Erst ein Wert ab 8 kennzeichnet einen fehlgeschlagenen Sicherungslauf.
Die normale Variante sichert den Ordner des PowerShell-Skripts. Die SendTo-Version übernimmt dagegen einen oder mehrere Projektordner aus dem Windows-Explorer und legt in jedem ausgewählten Ordner eine eigene datierte Sicherung mit Protokolldatei an.
Die Sicherheitsabfrage akzeptiert in der getesteten Version ausschließlich die genaue Eingabe JA. Wer zusätzlich ein kleines ja zulassen möchte, kann den Vergleichsoperator -cne durch -ne ersetzen.
Video zu diesem Tutorial:
Das könnte Dich auch interessieren
Keine Einträge gefunden

