Windows Server 2025 / PowerShell-Fehler behandeln und Ausführungen protokollieren

Mit try, catch und finally, gezielter Fehlerbehandlung und einem eigenen Protokoll je Durchlauf lassen sich Fehler und Teilergebnisse von PowerShell-Aufgaben nachvollziehen. Ein beendeter Befehl bedeutet noch nicht, dass die gesamte Verwaltungsaufgabe erfolgreich war.

Machen Sie Fehler sichtbar

Diese Übung liest eine Datei und schreibt ein Protokoll, ohne Rollen, Dienste oder Netzwerkeinstellungen zu ändern. Ein echtes Installations- oder Kontoverwaltungsskript muss zusätzlich festhalten, welche Änderungen nach einem Fehler bereits bestehen bleiben. Der Wechsel in catch macht frühere Aktionen nicht automatisch rückgängig.

Manche Fehler lassen PowerShell weiterarbeiten und lösen standardmäßig kein catch aus. Ein Befehl innerhalb von try reicht daher nicht aus: -ErrorAction Stop wandelt unterstützte nicht beendende Fehler in abfangbare beendende Fehler um. Die Dokumentation zur PowerShell-Fehlerbehandlung erläutert den Unterschied.

Bereiten Sie Eingabe und vollständiges Skript vor

Erstellen Sie zuerst C:\LabScripts und speichern Sie in C:\LabScripts\input.txt genau eine Zeile mit dem unveränderten Text lab ready. Speichern Sie den vollständigen folgenden Code als C:\LabScripts\Read-LabFile.ps1 und prüfen Sie die Endungen .txt und .ps1. Verwenden Sie UTF-8; bei Nicht-ASCII-Zeichen im Skript wählen Sie UTF-8 mit Byte Order Mark (BOM), wie in der Dokumentation zur Zeichenkodierung beschrieben. Für Windows PowerShell 5.1 sind Leserechte auf die Eingabe und Berechtigungen zum Erstellen oder Beschreiben von C:\LabLogs erforderlich. Das Skript speichert strukturierte Daten im Format JSON (JavaScript Object Notation); der Dateiname enthält Zeitstempel und kurze Kennung.

param(
    [Parameter(Mandatory=$true)]
    [string]$InputPath
)
$logDirectory = 'C:\LabLogs'
New-Item -ItemType Directory -Path $logDirectory -Force -ErrorAction Stop | Out-Null
$runLabel = (Get-Date -Format 'yyyyMMdd-HHmmss') + '-' + ([guid]::NewGuid().ToString('N').Substring(0,6))
$logPath = Join-Path $logDirectory ($runLabel + '.json')
$result = [ordered]@{
    StartedAt = (Get-Date).ToString('o')
    ComputerName = $env:COMPUTERNAME
    InputPath = $InputPath
    Success = $false
    LineCount = $null
    ErrorId = $null
    ErrorMessage = $null
}
$exitStatus = 0
try {
    $lines = @(Get-Content -LiteralPath $InputPath -ErrorAction Stop)
    $result.LineCount = $lines.Count
    $result.Success = $true
}
catch {
    $result.ErrorId = $_.FullyQualifiedErrorId
    $result.ErrorMessage = $_.Exception.Message
    $exitStatus = 1
    Write-Warning $result.ErrorMessage
}
finally {
    $result.FinishedAt = (Get-Date).ToString('o')
    $result | ConvertTo-Json | Set-Content -LiteralPath $logPath -Encoding UTF8 -ErrorAction Stop
}
Write-Output $logPath
exit $exitStatus

Vergleichen Sie Erfolg und Fehler unter gleichen Bedingungen

Geben Sie die Befehle in einer PowerShell-Konsole ein. Jeder Aufruf von powershell.exe startet einen eigenen Prozess; exit beendet diesen Prozess, während die ursprüngliche Konsole verfügbar bleibt. Führen Sie zuerst den Aufruf für die vorhandene Datei aus und lesen Sie unmittelbar danach $LASTEXITCODE. Wiederholen Sie das Paar anschließend mit missing-input.txt, die tatsächlich fehlen muss. Löschen Sie dafür weder die gültige Eingabe noch eine Systemdatei:

powershell.exe -NoProfile -File 'C:\LabScripts\Read-LabFile.ps1' -InputPath 'C:\LabScripts\input.txt'
$LASTEXITCODE
powershell.exe -NoProfile -File 'C:\LabScripts\Read-LabFile.ps1' -InputPath 'C:\LabScripts\missing-input.txt'
$LASTEXITCODE

Bei der einzeiligen Eingabe muss der erste Aufruf 0 liefern und ein JSON-Protokoll mit Success=true sowie LineCount=1 ohne Fehlerdetails erzeugen. Für die fehlende Datei werden 1, Success=false und LineCount=null erwartet; ErrorId und ErrorMessage müssen gefüllt sein. Die Fehlermeldung kann je nach Sprache variieren. Öffnen Sie jeweils die ausgegebene JSON-Datei in einem Texteditor und prüfen Sie InputPath, ComputerName, StartedAt und FinishedAt. Vergleichen Sie die neuen Protokolle, ohne sie mit einer älteren Datei im Ordner zu verwechseln.

Blockiert eine Richtlinie die Skriptausführung, erfüllen Sie die Ausführungs- und Signaturanforderungen Ihrer Organisation. Schwächen Sie für dieses Beispiel keine globalen Einstellungen ab.

Verstehen Sie die Abschnitte der Fehlerbehandlung

Abschnitt Zweck in diesem Skript
try Datei lesen und Zeilenanzahl erfassen
catch Kennung und Meldung des abgefangenen Fehlers erfassen; einen Fehler-Exitcode festlegen
finally Ergebnis unabhängig vom Erfolg des Lesevorgangs zu speichern versuchen

Microsofts Referenz zu try, catch und finally erklärt die Behandlung beendender Fehler. In diesem Skript wird C:\LabLogs vor try angelegt: Schlägt diese Vorbereitung fehl, erfasst das folgende catch den Fehler nicht. finally versucht das Ergebnis zu speichern, garantiert aber weder freien Speicherplatz noch Schreibrechte. Success beschreibt den Lesevorgang; prüfen Sie zusätzlich, ob eine gültige neue JSON-Datei vorhanden ist. Auch das Schreiben verwendet -ErrorAction Stop. Ein fehlendes Protokoll ist kein Beleg für eine fehlerfrei abgeschlossene Aufgabe.

Externe Programme liefern eigene Exitcodes. In Windows PowerShell 5.1 löst ein Wert ungleich null nicht automatisch catch aus. Prüfen Sie $LASTEXITCODE direkt nach dem Programm und erzeugen Sie bei Bedarf mit throw einen beendenden Fehler. Ein weiteres externes Programm kann den Wert ersetzen; -ErrorAction Stop allein wandelt externe Exitcodes nicht in Ausnahmen um.

Legen Sie Kriterien für sichere Wiederholungen fest

  • Erfassen Sie Server, Ziel sowie Start- und Endzeit.
  • Prüfen Sie den vorhandenen Zustand, um doppelte Erstellung und unbeabsichtigtes Überschreiben zu vermeiden.
  • Protokollieren Sie erfolgreiche und fehlgeschlagene Schritte getrennt.
  • Halten Sie Passwörter, Token und unnötige Inhalte von Benutzerdateien aus Protokollen heraus.
  • Dokumentieren Sie bei einer Rücknahmefunktion deren unterstützten Umfang und Fehler bei der Wiederherstellung.

Verwenden Sie wieder den Pfad zu input.txt und führen Sie das Skript erneut aus. Erwartet werden ein neuer Exitcode 0 und ein neues JSON-Protokoll mit Success=true sowie LineCount=1. Bewahren Sie benötigte Nachweise auf, bevor Sie ausschließlich die identifizierten temporären Übungsdateien entfernen. SilentlyContinue pauschal einzusetzen verbirgt Fehler und ersetzt keine Fehlerbehandlung.