PowerShell-Skripte zuverlässig ausführen heißt, auch an den unbequemen Fall zu denken: Eine Datei fehlt, ein Netzlaufwerk ist nicht erreichbar oder ein geplanter Job läuft unter einem anderen Benutzerkonto als erwartet. Ein Skript, das im geöffneten PowerShell-Fenster funktioniert, kann in der Windows-Aufgabenplanung trotzdem scheitern.

In dieser Anleitung baust du drei Dinge ein, die solche Probleme sichtbar machen: eine klare Fehlerbehandlung, ein nachvollziehbares Log und einen aussagekräftigen Rückgabecode. Anschließend richtest du das Skript als geplante Aufgabe ein und prüfst, ob es auch ohne interaktive Anmeldung läuft. Falls du mit Skripten gerade erst anfängst, findest du die Grundlagen in unserem Beitrag Mit PowerShell starten.

Warum laufen PowerShell-Skripte manuell, aber nicht automatisch?

Beim manuellen Start bringt deine Sitzung einiges mit: dein Benutzerkonto, dein aktuelles Arbeitsverzeichnis, möglicherweise geladene Profile und Zugriff auf Ressourcen, die nur für dich freigegeben sind. Eine geplante Aufgabe kann unter einem anderen Konto und in einem anderen Verzeichnis starten. Außerdem sitzt niemand vor dem Bildschirm, um eine Rückfrage zu beantworten.

Ein zuverlässig geplantes Skript sollte deshalb:

  • mit eindeutigen, möglichst absoluten Dateipfaden arbeiten,
  • ohne Eingaben über Read-Host oder Bestätigungsdialoge auskommen,
  • Fehler erkennen und verständlich protokollieren,
  • bei einem Fehlschlag mit einem Rückgabecode ungleich null enden,
  • mit den Rechten des vorgesehenen Aufgabenkontos getestet werden.

PowerShell-Skripte zuverlässig ausführen: Fehler richtig behandeln

PowerShell unterscheidet zwischen Fehlern, die einen Befehl sofort beenden, und Fehlern, nach denen die Verarbeitung zunächst weiterläuft. Ein try– und catch-Block fängt beendende Fehler ab. Viele Fehler von PowerShell-Cmdlets werden jedoch erst mit -ErrorAction Stop oder $ErrorActionPreference = 'Stop' an catch weitergegeben.

Ein kleines Beispiel zeigt den Unterschied:

try {
    Get-Content -LiteralPath 'C:\Daten\eingabe.txt' `
        -ErrorAction Stop
}
catch {
    Write-Output "Lesen fehlgeschlagen: $($_.Exception.Message)"
}

Die Variable $_ enthält im catch-Block den aktuellen Fehler. Über $_.Exception.Message erhältst du eine kompakte Fehlermeldung. Für die spätere Analyse können zusätzlich der betroffene Dateipfad, der Arbeitsschritt und der Zeitpunkt wichtig sein.

Wichtig: Externe Programme verhalten sich anders als PowerShell-Cmdlets. Ein Programm kann mit einem Fehlercode enden, ohne dass dadurch automatisch catch ausgeführt wird. Prüfe nach solchen Aufrufen den Wert von $LASTEXITCODE und löse bei Bedarf selbst einen Fehler aus:

robocopy.exe C:\Quelle C:\Ziel /E

if ($LASTEXITCODE -ge 8) {
    throw "Robocopy meldet einen Fehlercode: $LASTEXITCODE"
}

Bei robocopy gelten mehrere Rückgabecodes unterhalb von 8 nicht als Fehler. Für andere Programme musst du deren eigene Bedeutung der Exit-Codes prüfen.

Logging: Was ein brauchbares Skriptprotokoll enthalten sollte

Ein Log muss nicht kompliziert sein. Für viele geplante Aufgaben reicht zunächst eine Textdatei, in der jede Zeile Zeitpunkt, Schweregrad und Meldung enthält. Gute Meldungen beantworten drei Fragen: Was wollte das Skript tun? Was ist passiert? An welcher Stelle trat der Fehler auf?

Beispiel:

2026-09-28 08:00:00 [INFO] Dateiprüfung gestartet.
2026-09-28 08:00:01 [INFO] 42 Dateien gefunden.
2026-09-28 08:00:01 [INFO] Dateiprüfung erfolgreich beendet.

Schreibe keine Passwörter, Zugriffstoken oder vollständigen vertraulichen Datensätze in das Log. Begrenze den Zugriff auf das Logverzeichnis und lege fest, wann alte Protokolle gelöscht oder archiviert werden. Ein täglicher Dateiname verhindert zumindest, dass alle Läufe in einer einzigen, immer größer werdenden Datei landen.

Vollständiges Beispiel: Ein geplantes Skript mit Fehlerbehandlung und Log

Das folgende Skript zählt Dateien in einem Verzeichnis. Die Aufgabe ist bewusst einfach, damit die Struktur für Fehlerbehandlung und Logging gut erkennbar bleibt. Speichere den Code beispielsweise als C:\Scripts\DateiReport.ps1. Passe Quell- und Logverzeichnis vor dem ersten Start an.

$ErrorActionPreference = 'Stop'

$quellverzeichnis = 'C:\Daten\Eingang'
$logverzeichnis = 'C:\ProgramData\DateiReport\Logs'
$logdatei = Join-Path $logverzeichnis (
    'datei-report-{0}.log' -f (Get-Date -Format 'yyyy-MM-dd')
)

function Write-Log {
    param(
        [Parameter(Mandatory)]
        [string] $Level,

        [Parameter(Mandatory)]
        [string] $Message
    )

    $zeitpunkt = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
    $zeile = '{0} [{1}] {2}' -f $zeitpunkt, $Level, $Message

    Add-Content -LiteralPath $logdatei `
        -Value $zeile `
        -Encoding UTF8
}

try {
    New-Item -ItemType Directory `
        -Path $logverzeichnis `
        -Force | Out-Null

    Write-Log -Level 'INFO' `
        -Message 'Dateiprüfung gestartet.'

    if (-not (Test-Path -LiteralPath $quellverzeichnis `
                            -PathType Container)) {
        throw "Quellverzeichnis fehlt: $quellverzeichnis"
    }

    $dateien = @(
        Get-ChildItem -LiteralPath $quellverzeichnis `
            -File `
            -ErrorAction Stop
    )

    Write-Log -Level 'INFO' `
        -Message ("{0} Dateien gefunden." -f $dateien.Count)

    Write-Log -Level 'INFO' `
        -Message 'Dateiprüfung erfolgreich beendet.'

    exit 0
}
catch {
    $fehlermeldung = $_.Exception.Message

    try {
        Write-Log -Level 'ERROR' -Message $fehlermeldung
    }
    catch {
        [Console]::Error.WriteLine(
            "Auch das Schreiben des Logs ist fehlgeschlagen: " +
            $_.Exception.Message
        )
    }

    [Console]::Error.WriteLine(
        "Dateiprüfung fehlgeschlagen: $fehlermeldung"
    )

    exit 1
}

Ein erfolgreicher Lauf endet mit exit 0, ein fehlgeschlagener mit exit 1. Die Aufgabenplanung kann diesen Rückgabecode als Ergebnis des letzten Laufs anzeigen. Der zweite try-Block im Fehlerfall verhindert, dass ein nicht beschreibbares Logverzeichnis die ursprüngliche Fehlermeldung vollständig verdeckt.

Teste beide Wege vor der Automatisierung: zuerst mit einem vorhandenen Quellverzeichnis, danach kurzzeitig mit einem absichtlich falschen Pfad. Beim zweiten Test muss ein Fehler gemeldet werden und der Prozess mit Code 1 enden. Stelle anschließend den richtigen Pfad wieder her.

Skript in der Windows-Aufgabenplanung einrichten

Öffne die Aufgabenplanung und wähle Aufgabe erstellen. Für regelmäßig ausgeführte Skripte ist diese Ansicht hilfreicher als der Assistent „Einfache Aufgabe erstellen“, weil du Konto, Auslöser und weitere Einstellungen genauer festlegen kannst.

  1. Vergib einen eindeutigen Namen, beispielsweise DateiReport täglich.
  2. Wähle das Benutzerkonto, unter dem das Skript später laufen soll. Dieses Konto benötigt Leserechte für C:\Daten\Eingang und Schreibrechte für das Logverzeichnis.
  3. Lege unter Trigger die gewünschte Uhrzeit fest.
  4. Erstelle unter Aktionen eine neue Aktion vom Typ Programm starten.
  5. Trage Programm, Argumente und Arbeitsverzeichnis wie unten beschrieben ein.
  6. Prüfe unter Einstellungen, was passieren soll, wenn eine Ausführung länger dauert als bis zum nächsten geplanten Start. Für viele Jobs ist „Keine neue Instanz starten“ die passende Wahl.

Für PowerShell 7 kann die Aktion so aussehen. Prüfe den tatsächlichen Installationspfad von pwsh.exe auf deinem System:

Feld in der Aufgabenplanung Beispielwert
Programm/Skript C:\Program Files\PowerShell\7\pwsh.exe
Argumente hinzufügen -NoProfile -NonInteractive -File "C:\Scripts\DateiReport.ps1"
Starten in C:\Scripts

Verwendest du Windows PowerShell 5.1, wähle stattdessen den passenden Pfad zu powershell.exe. Mit -NoProfile startet das Skript ohne persönliche Profile. -NonInteractive sorgt dafür, dass interaktive Rückfragen einen Fehler auslösen, statt eine unbeaufsichtigte Aufgabe warten zu lassen.

Das Feld Starten in ist wichtig: Ohne Angabe kann eine Aufgabe im Windows-Systemverzeichnis starten. Das Beispielskript nutzt zwar absolute Pfade, doch bei später ergänzten relativen Pfaden oder Zusatzdateien verhindert ein festgelegtes Arbeitsverzeichnis schwer zu findende Fehler.

Geplante Aufgabe richtig testen

Starte die Aufgabe nach dem Speichern einmal manuell über Ausführen in der Aufgabenplanung. Prüfe anschließend nicht nur das Feld Letztes Ausführungsergebnis, sondern auch die neu angelegte Logdatei und das tatsächliche Arbeitsergebnis.

Ein Rückgabecode von 0 zeigt bei unserem Beispiel an, dass das Skript seinen vorgesehenen Erfolgsweg erreicht hat. Ein Rückgabecode von 1 bedeutet, dass die Fehlerbehandlung ausgelöst wurde. Wenn keine Logdatei entsteht, prüfe zuerst, ob die Aufgabe überhaupt die angegebene PowerShell-Datei starten konnte und ob das Aufgabenkonto Zugriff auf die Verzeichnisse besitzt.

Teste die Aufgabe möglichst mit genau dem Konto, der PowerShell-Version und den Pfaden, die später im Regelbetrieb verwendet werden. Ein erfolgreicher manueller Start in deiner eigenen Sitzung ist dafür kein vollständiger Ersatz.

Typische Fehler bei geplanten PowerShell-Skripten

Das Skript findet Dateien nicht

Verwende absolute Pfade oder baue Pfade aus dem Speicherort des Skripts mit $PSScriptRoot auf. Verlasse dich nicht darauf, dass die Aufgabe im Verzeichnis der Skriptdatei startet. Prüfe außerdem, ob das Aufgabenkonto die Dateien lesen darf.

Ein Netzlaufwerk fehlt

Ein Laufwerksbuchstabe, den du interaktiv verbunden hast, steht einer geplanten Aufgabe häufig nicht zur Verfügung. Verwende nach Möglichkeit einen UNC-Pfad wie \\server\freigabe\datei.csv und gib dem Aufgabenkonto Zugriff auf die Freigabe und die zugrunde liegenden Dateirechte.

Das Skript wartet auf eine Eingabe

Entferne Read-Host, Bestätigungsdialoge und interaktive Anmeldungen aus unbeaufsichtigten Abläufen. Setze -NonInteractive beim Start, damit solche Stellen als Fehler auffallen.

Das Log bleibt leer

Kontrolliere den Pfad von pwsh.exe beziehungsweise powershell.exe, den Pfad der .ps1-Datei und die Schreibrechte für das Logverzeichnis. Prüfe in der Aufgabenplanung auch Verlauf und Ausführungsergebnis. Ist die Logdatei vorhanden, aber unvollständig, untersuche den letzten protokollierten Arbeitsschritt.

Das Skript wird durch die Ausführungsrichtlinie blockiert

Prüfe mit Get-ExecutionPolicy -List, welche Richtlinien gelten. Behebe die Ursache gezielt und berücksichtige Vorgaben deiner Organisation. Die Ausführungsrichtlinie ist eine zusätzliche Schutzmaßnahme, aber keine Sicherheitsgrenze. Ein pauschales -ExecutionPolicy Bypass sollte deshalb nicht zur Standardlösung für jeden geplanten Job werden.

Checkliste für den Regelbetrieb

  • Ist klar, welches Konto die Aufgabe ausführt und welche Rechte es benötigt?
  • Verwendet das Skript eindeutige Pfade und läuft es ohne Benutzereingaben?
  • Werden Fehler mit Zeitpunkt und Kontext protokolliert?
  • Liefert das Skript bei Erfolg und Fehler unterschiedliche Exit-Codes?
  • Sind Logdateien vor unberechtigtem Zugriff geschützt und wird ihre Aufbewahrung begrenzt?
  • Wurde die Aufgabe unter denselben Bedingungen getestet, unter denen sie später automatisch läuft?
  • Ist festgelegt, wie du bemerkst, wenn mehrere geplante Läufe hintereinander fehlschlagen?

Fazit

PowerShell-Skripte zuverlässig auszuführen erfordert mehr als einen funktionierenden Befehl. Erst mit klarer Fehlerbehandlung, aussagekräftigem Logging und einem kontrollierten Rückgabecode erkennst du, ob ein geplanter Lauf sein Ziel erreicht hat. In der Windows-Aufgabenplanung kommen ein passendes Aufgabenkonto, feste Pfade und ein Test ohne interaktive Sitzung hinzu.

Beginne mit einem kleinen Skript wie dem gezeigten Dateireport und prüfe bewusst auch einen Fehlerfall. Wenn beide Wege nachvollziehbar protokolliert werden, hast du eine tragfähige Grundlage für größere Automatisierungen.

Weiterführende Microsoft-Dokumentation