Sollte diese Batch-Datei zu PowerShell wechseln? — Bestandsaufnahme von cmd/bat-Assets und die Migrationsentscheidung

· · PowerShell, Windows, Batch-Datei, cmd, VBScript, Nutzung vorhandener Ressourcen, Betriebsoptimierung, Skript

„Bei der Servermigration ist uns ein ganzer Berg 20 Jahre alter Batch-Dateien aufgefallen. Sollten wir die alle in PowerShell neu schreiben?“ — Diese Frage ist ein fester Bestandteil jeder Beratung zu Legacy-Assets. Kopien und Backups, Wrapper zum Starten von Anwendungen, nächtliche Integrationsjobs. cmd-Batch-Dateien (bat) tragen bis heute still den Windows-Betrieb im Feld mit.

Um die Antwort gleich vorwegzunehmen: Nein, Sie müssen nicht alle neu schreiben. Es gibt keinen Plan, bat in absehbarer Zeit abzuschaffen, und das Umschreiben von etwas, das funktioniert, ist selbst ein Fehlerrisiko. Gleichzeitig gibt es durchaus Batch-Dateien, bei denen „so lassen, wie sie sind“ gefährlich ist: solche, die VBScript aufrufen, solche, die Fehler verschlucken, solche, die demnächst geändert werden. Ohne diese Unterscheidung sind sowohl „alles behalten“ als auch „alles migrieren“ Unfälle, die nur auf ihren Moment warten.

Dieser Artikel richtet sich an interne IT- und Betriebsmitarbeiter kleiner und mittelständischer Unternehmen. Er legt Kriterien für die Bestandsaufnahme von bat-Assets und die Migrationsentscheidung dar, die Fallstricke, die spezifisch für bat sind, wie man bat und PowerShell während der Übergangsphase koexistieren lässt, sowie eine Referenztabelle zum Umschreiben.

1. Zunächst das Fazit

  • Es gibt keinen Plan, cmd.exe oder bat abzuschaffen, aber Microsoft erklärt ausdrücklich, dass für die Windows-Automatisierung PowerShell empfohlen wird. Die offizielle Richtung lautet: Wer etwas Neues schreibt, schreibt PowerShell.1
  • VBScript wurde im Oktober 2023 offiziell als veraltet eingestuft, mit einem veröffentlichten gestuften Plan, der ein optionales Feature (Feature on Demand) vorsieht, bevor es aus dem Betriebssystem entfernt wird. Assets, die VBScript per cscript / wscript aus bat aufrufen, sind die Gruppe mit der höchsten Migrationsdringlichkeit.23 Als offiziell vorgeschlagener Ersatz gilt PowerShell.4
  • Die Migrationsentscheidung ist keine „Alles“-Entscheidung, sondern eine Sortierung. Läuft zuverlässig, keine Änderungen geplant → behalten. Änderungen stehen an, Fehlerbehandlung nötig, Protokollierung nötig → migrieren. Hängt von VBScript ab → zuerst migrieren. Kapitel 4 enthält die Entscheidungstabelle.
  • Die strukturellen Schwächen von bat sind: kein Anhalten bei Fehlern, die Fallstricke von %ERRORLEVEL% und die Zeichenkodierung. if errorlevel 1 ist ein Test auf „1 oder größer“5, und %errorlevel% bricht, wenn eine gleichnamige Umgebungsvariable definiert ist.5
  • Der Gewinn einer Migration zu PowerShell besteht in der Objekt-Pipeline, der Fehlerbehandlung mit try/catch6, Probeläufen mit -WhatIf7 und Tests mit Pester. „Fehler bemerken, sicher ausprobieren, automatisch testen können“ ist der eigentliche Wert der Migration.
  • Für die Übergangsphase ist der Aufruf von powershell.exe / pwsh aus bat mit -File die realistische Lösung. Der von exit im Skript zurückgegebene Exitcode wird direkt an %ERRORLEVEL% auf der bat-Seite weitergereicht, sodass Sie das Innenleben ersetzen können, während die bestehende Jobsteuerung erhalten bleibt.89
  • Schreiben Sie hervorragende externe Befehle wie robocopy nicht um — rufen Sie sie unverändert aus PowerShell auf. Die Exitcodes reichen von 0 bis 8 und darüber, nach einem eigenwilligen Schema, bei dem 8 und höher einen Fehler bedeutet; das Einzige, was Sie korrekt umsetzen müssen, ist die Prüfung von $LASTEXITCODE.1011
  • Bauen Sie die Ausführungsrichtlinie in Ihr Verteilungsdesign ein. Der Standardwert ist Restricted (keine Skriptausführung) auf Client-Betriebssystemen mit Windows PowerShell 5.1 und RemoteSigned auf Windows Server und PowerShell 7. Selbst unter RemoteSigned werden unsignierte Skripte mit der Internet-Markierung blockiert.12

2. Warum jetzt darüber nachdenken — cmd bleibt, VBScript verschwindet

Beginnen wir mit den zugrunde liegenden Fakten. Windows verfügt über zwei Befehlszeilen-Shells, cmd (die Eingabeaufforderung) und PowerShell, und die offizielle Dokumentation von Microsoft stellt fest, dass „für die robusteste und aktuellste Windows-Automatisierung PowerShell empfohlen wird, statt Windows-Befehlen oder Windows Script Host“.1 Doch eine Empfehlung ist nur eine Empfehlung: cmd selbst taucht nicht auf der Liste der veralteten Windows-Funktionen auf. Es gibt derzeit keinen Plan, dass bestehende Batch-Dateien aufhören zu funktionieren.

VBScript ist der Gegenfall. Im Oktober 2023 wurde die Einstufung von VBScript als veraltet offiziell bekannt gegeben. Ein veröffentlichter Plan sieht vor, dass es in künftigen Windows-Versionen als optionales Feature (Feature on Demand) ausgeliefert wird, bevor es aus dem Betriebssystem entfernt wird.2 Zunächst wird es vorinstalliert ausgeliefert, sodass morgen nichts stoppt3 — aber die Richtung, die Entfernung, steht fest. Windows Server 2025 hat es ebenfalls in ein FoD überführt, wobei die Migration zu PowerShell offiziell als Ersatz vorgeschlagen wird.4

Der wichtige Punkt hierbei ist, dass sich VBScript in Ihren bat-Assets versteckt. Der Aufruf von VBScript aus bat mit etwas wie cscript //nologo convert.vbs war in den 2000er-Jahren ein gängiges Muster. Eine so aufgebaute Batch-Datei ist nicht „sicher, weil sie bat ist“ — sie teilt das Schicksal von VBScript. Prüfen Sie bei der Bestandsaufnahme daher immer nicht nur die bat-Dateien selbst, sondern auch, was sie aufrufen (Kapitel 7 enthält ein Skript zum Scannen). Eine vollständige Untersuchung der VBScript- und VBA-Assets im gesamten Unternehmen wird ausführlich in „Preparing for VBScript Deprecation: An Audit Guide for VBA and Internal Tools“ behandelt.

3. Die Fallstricke von bat und was Sie mit PowerShell gewinnen

Betrachten wir als Grundlage für die Migrationsentscheidung konkret die strukturellen Schwächen von bat. Die folgende Batch-Datei ist eine Form, die man für Backups überall sieht.

@echo off
rem Nächtliches Backup (die Art von riskanter Batch-Datei, die man überall sieht)
xcopy C:\data \\backup01\share\data /E /Y
echo Backup abgeschlossen >> C:\logs\backup.log

In dieser Batch-Datei stecken drei leicht zu übersehende Probleme.

  • Sie stoppt nicht bei Fehlern. Erreicht xcopy die Zielfreigabe nicht und schlägt fehl, fährt cmd standardmäßig mit der nächsten Zeile fort, und im Protokoll steht „Backup abgeschlossen“. Um Fehler zu erkennen, müssen Sie jedes Mal selbst eine if errorlevel-Prüfung schreiben.
  • %ERRORLEVEL% birgt Fallstricke. if errorlevel 1 bedeutet nicht „der Exitcode ist gleich 1“ — sondern „1 oder größer“.5 Und die Schreibweise %errorlevel% ist so spezifiziert, dass sie „zum aktuellen Exitcode erweitert wird, sofern keine Umgebungsvariable namens ERRORLEVEL definiert ist“; sobald also jemand set ERRORLEVEL=0 schreibt, ist jede nachfolgende Prüfung defekt.5 Zusammen mit dem Mechanismus exit /b <Zahl> zur Rückgabe von Exitcodes13 braucht es einiges an Wissen, um dies korrekt umzusetzen.
  • Unfälle mit der Zeichenkodierung. cmd lebt traditionell in einer Shift_JIS-geprägten Welt, und noch heute passieren Unfälle: Eine als UTF-8 neu gespeicherte bat-Datei wird zu Zeichensalat, oder ein Pfad mit Sonderzeichen funktioniert nicht richtig. Das vollständige Bild dieses Problems finden Sie in „Windows Text Encodings and Line Endings - The Basics of Mojibake and CRLF/LF“.

Schreibt man denselben Vorgang in PowerShell, ändert sich der Umgang mit Fehlern strukturell.

# Nächtliches Backup (Grundgerüst der PowerShell-Version)
$ErrorActionPreference = 'Stop'   # Fehler auf „Stopp“ ausrichten
try {
    # Als Quelle „den Inhalt des Ordners“ angeben, C:\data\*. Würde man 'C:\data' übergeben,
    # entstünde ab dem zweiten Lauf eine Verschachtelung als data\data, sobald der Zielordner existiert
    Copy-Item -Path 'C:\data\*' -Destination '\\backup01\share\data' -Recurse -Force
    Add-Content -Path 'C:\logs\backup.log' -Value "$(Get-Date -Format o) Backup abgeschlossen"
    exit 0
}
catch {
    # Was fehlgeschlagen ist und wo, kann als strukturierte Information festgehalten werden
    Add-Content -Path 'C:\logs\backup.log' -Value "$(Get-Date -Format o) Fehlgeschlagen: $($_.Exception.Message)"
    exit 1
}

try/catch fängt anweisungsbeendende Fehler ab, und Aufräumarbeiten können in finally erfolgen.6 PowerShell stellt außerdem -WhatIf als gemeinsamen Mechanismus bereit, der anzeigt, „was geändert worden wäre“, ohne den destruktiven Vorgang tatsächlich auszuführen7, sodass Sie ein umgeschriebenes Skript sicher gegen die Produktivumgebung proben können. Fügen Sie noch Pester-Tests hinzu, können Sie fortlaufend automatisch prüfen, ob „es funktionieren sollte“ (siehe „Testing PowerShell with Pester — A Practical Approach to Making Operations Scripts Harder to Break“). Das Design von Fehlerbehandlung und Wiederholungsversuchen selbst wird ausführlich in „PowerShell Error Handling and Retry Design — From the try/catch Trap to Exit Codes and Retry Best Practices“ behandelt, das zeitgleich mit diesem Artikel veröffentlicht wurde.

Was Sie durch die Migration gewinnen, ist also keine syntaktische Neuheit, sondern operative Qualität: Sie können Fehler bemerken, Dinge sicher ausprobieren und sie mit Tests absichern. Umgekehrt bringt dieser Wert bei einer Batch-Datei wie einem einfachen Start-Wrapper wenig, weil ein Fehler ohnehin sofort auffällt. Deshalb ist eine Sortierung notwendig.

4. Nicht alles migrieren — eine Entscheidungstabelle zur Sortierung

Punkt Optionen Wie zu beurteilen ist
Läuft zuverlässig, keine Änderungen geplant, einfach So belassen / Migrieren Ein Anwendungs-Start-Wrapper oder wenige Zeilen zum Kopieren können bleiben. Das Umschreiben selbst ist ein neues Risiko
Ruft VBScript auf (cscript/wscript) Behalten / Zuerst migrieren Der Plan „veraltet → FoD → Entfernung“ für VBScript wurde offiziell bekannt gegeben. Untätigkeit führt zu einem Abschaltdatum2
Änderungen an der Spezifikation oder neue Funktionen stehen an In bat überarbeiten / Zuerst migrieren, dann überarbeiten Der Zeitpunkt der Änderung ist die Gelegenheit zur Migration. Überarbeitung und Testaufbau gleichzeitig erledigen
Fehlererkennung, Protokollierung oder Wiederholungsversuche erforderlich Prüfungen zu bat hinzufügen / Migrieren Alles mit if errorlevel abzudecken ist schwer wartbar. Hier zahlen sich try/catch und strukturierte Protokollierung aus6
Nächtlicher Job (über die Aufgabenplanung gestartet) Unverändert lassen / Migration erwägen Bei unbeaufsichtigter Ausführung zählt gerade die Fehlerbehandlung. Gleichzeitig das Ausführungskonto und 0x1-Probleme prüfen
Ein externer Befehl wie robocopy spielt die Hauptrolle Mit Cmdlets neu implementieren / Externen Befehl behalten und aufrufen Die Neuimplementierung eines bewährten Befehls ist ein Verlustgeschäft. Nur den Aufruf und die Prüfung nach PowerShell verlagern10
Der Autor ist ausgeschieden, das Verhalten ist undokumentiert Nicht anfassen / Verhalten festhalten, dann entscheiden Erst die aktuellen Ein-/Ausgaben und den Zeitplan dokumentieren. Nicht umschreiben, was Sie nicht verstehen

Bei Unentschlossenheit gelten zwei Prinzipien. Erstens: Migrieren Sie in der Reihenfolge des Werts, nicht in der Reihenfolge des Alters. Zweitens: Wenn Sie etwas anfassen, beginnen Sie mit dem Lesen (Bestandsaufnahme und Dokumentation).

5. Die realistische Lösung für die Übergangsphase — PowerShell aus bat aufrufen und den Exitcode zurückgeben

Nach der Sortierung treten die meisten Standorte in eine Übergangsphase ein, in der „ein Teil noch bat ist, ein Teil PowerShell“. Die nützliche Anordnung besteht darin, die bat-Datei als Einstiegspunkt (die Schnittstelle zur Jobsteuerung) zu behalten und nur ihr Innenleben durch PowerShell zu ersetzen. Job-Scheduler und Betriebshandbücher schauen weiterhin auf den Pfad der bat-Datei, sodass Sie das Innenleben modernisieren können, ohne etwas im Umfeld zu beschädigen.

@echo off
rem Einstiegs-bat: ruft job.ps1 im selben Ordner auf und reicht den Exitcode weiter
rem %~dp0 ist der Ordner, in dem diese bat-Datei selbst liegt (der Standardtrick aus der offiziellen Doku)
rem Ist noch die Umgebungsvariable set ERRORLEVEL=... von jemandem vorhanden, verbirgt sie
rem vor %ERRORLEVEL% den echten Exitcode, daher vor dem Aufruf löschen, um den dynamischen Wert wiederherzustellen
rem Die Ausführungsrichtlinie hier nicht überschreiben. Die Angabe von -ExecutionPolicy gilt für den
rem vorrangigen Process-Bereich und schwächt AllSigned & Co., das ein Admin konfiguriert hat, still ab
set "ERRORLEVEL="
powershell.exe -NoProfile -File "%~dp0job.ps1"
exit /b %ERRORLEVEL%

Den Speicherort des Skripts mit %~dp0 statt über das aktuelle Verzeichnis aufzulösen, ist genau das, was die offizielle Dokumentation als Beispiel für den Aufruf aus einer Batch-Datei zeigt.9 Um es unter PowerShell 7 auszuführen, ändern Sie einfach powershell.exe in pwsh (5.1 und 7 werden getrennt installiert und können koexistieren; zur Wahl zwischen beiden siehe „The Differences Between Windows PowerShell 5.1 and PowerShell 7 — A Practical Guide to Migrating In-House Scripts“, das zeitgleich mit diesem Artikel veröffentlicht wurde).

Die Weitergabe des Exitcodes lässt sich folgendermaßen zusammenfassen.

  • Endet das Skript mit exit 4, wird der Prozess-Exitcode zu 4 und kann auf der bat-Seite über %ERRORLEVEL% empfangen werden. Dieses Zusammenspiel ist in der offiziellen Dokumentation mit einem durchgerechneten Beispiel belegt.8
  • Bei Aufruf mit -File endet ein Skript, das mit einer unbehandelten Ausnahme abbricht, mit Exitcode 1, und mit 0 bei normalem Abschluss. Um „fehlgeschlagen, aber trotzdem 0“ zu vermeiden, ist es sicherer, wenn das Skript selbst Erfolg oder Misserfolg feststellt und explizit exit aufruft.914
  • Das Ergebnis des Aufrufs eines externen Befehls aus PowerShell landet in der automatischen Variable $LASTEXITCODE.11

Eine auf robocopy aufgebaute Batch-Datei ist ein gutes Beispiel für diese Form. robocopy ist ein bewährter Befehl mit Wiederholungsversuchen (standardmäßig sage und schreibe eine Million Versuche mit 30 Sekunden Wartezeit), Spiegelung und Protokollierung10, und es gibt keinen Grund, ihn mit Copy-Item neu zu implementieren. Sein Exitcode-Schema ist allerdings eigenwillig: 0 bedeutet „nichts zu kopieren“, 1 bedeutet „erfolgreich kopiert“, und 8 oder höher bedeutet Fehler.10 Wenden Sie die allgemeine Regel „alles außer 0 ist ein Problem“ an, wird ein völlig normaler Kopiervorgang fälschlich als Fehler eingestuft.

# robocopy unverändert verwenden und nur die Prüfung in PowerShell richtig umsetzen
# /r:2 /w:5 — die Standardeinstellung von einer Million Wiederholungen entspricht bei einem unbeaufsichtigten Job praktisch einem Hängenbleiben, daher unbedingt begrenzen
robocopy 'C:\data' '\\backup01\share\data' /MIR /R:2 /W:5 /NP /LOG+:'C:\logs\robocopy.log'

if ($LASTEXITCODE -ge 8) {
    Write-Error "robocopy fehlgeschlagen (Exitcode: $LASTEXITCODE)"
    exit 1
}
Write-Host "Synchronisierung abgeschlossen (Exitcode: $LASTEXITCODE)"  # 0-7 sind Erfolgsergebnisse
exit 0

6. Referenztabelle zum Umschreiben — bat-Vokabular in PowerShell

Hier die Referenztabelle für das tatsächliche Umschreiben. Verwenden Sie sie nicht als mechanische Ersetzungsliste, sondern als Vergleich der Frage „wie drücke ich dieselbe Absicht aus?“

bat-Form PowerShell-Standard Hinweise
copy / move / del / md Copy-Item / Move-Item / Remove-Item / New-Item Destruktive Vorgänge zunächst mit -WhatIf proben7
xcopy / robocopy robocopy unverändert aufrufen Nicht neu implementieren. 8 oder höher als Fehler über $LASTEXITCODE behandeln1011
for %%f in (*.csv) do ... Get-ChildItem *.csv \| ForEach-Object { ... } Es fließen Objekte, keine Dateinamen-Zeichenketten
if errorlevel 1 goto :error try/catch + $ErrorActionPreference = 'Stop' Externe Befehle werden weiterhin über den Exitcode beurteilt6
set VAR=value $var = 'value' (Umgebungsvariablen sind $env:VAR) Prozess-Umgebungsvariablen und Variablen sind unterscheidbar
call :sub / goto function Argumenten können Typen und Validierung mitgegeben werden
findstr Select-String Treffende Zeilen kommen als Objekte zurück, die sich nachgelagert verarbeiten lassen
>> log.txt Start-Transcript / Add-Content Transcript ist der einfache Weg, einen ganzen Lauf mitzuschneiden
rem #

Das grundlegende PowerShell-Vokabular — wie man Cmdlets findet, die Pipeline, Praktiken zur Bestätigung — ist in „PowerShell Command Basics — The Operations to Learn First and How to Use Them Safely“ zusammengestellt.

7. Ein gestuftes Migrationsverfahren — Bestandsaufnahme → Klassifizierung → Pilot → Parallelbetrieb

Zum Abschluss der in vier Stufen gegliederte Ablauf.

(1) Bestandsaufnahme. Beginnen Sie mit einer rein lesenden Untersuchung. Ermitteln Sie mechanisch, wo sich die bat-Dateien befinden und ob sie von VBScript abhängen.

# Bestandsaufnahme der bat-Assets: eine Übersicht der Speicherorte plus Erkennung von VBScript-Aufrufen (sichere, rein lesende Untersuchung)
# Jeder Ort, der nicht aufgelistet werden konnte, wird zu einer Lücke in der Bestandsaufnahme, daher mit -ErrorVariable festhalten und später offenlegen
$targets = Get-ChildItem -Path 'C:\', 'D:\jobs', '\\fileserver\scripts' -Recurse `
    -Include '*.bat', '*.cmd' -File -ErrorAction SilentlyContinue -ErrorVariable enumErrors

$readErrors = @()
$report = foreach ($file in $targets) {
    # Bei einem cscript/wscript/.vbs-Aufruf als „abhängig von VBScript“ markieren
    # Bereits aufgelistete Pfade mit -LiteralPath übergeben (ein Dateiname mit eckigen Klammern,
    # etwa [2026]job.bat, würde von -Path als Wildcard interpretiert und träfe eine andere Datei)
    # Dateien, deren Inhalt wegen Sperrung o. Ä. nicht gelesen werden konnte, ebenfalls in $readErrors festhalten
    $vbs = Select-String -LiteralPath $file.FullName -Pattern 'cscript|wscript|\.vbs' -Quiet `
        -ErrorAction SilentlyContinue -ErrorVariable +readErrors
    [pscustomobject]@{
        Path          = $file.FullName
        LastWriteTime = $file.LastWriteTime
        UsesVBScript  = $vbs
    }
}
$report | Sort-Object UsesVBScript -Descending | Export-Csv 'C:\audit\bat-inventory.csv' -NoTypeInformation -Encoding UTF8

# Eine Liste der Orte führen, die nicht untersucht werden konnten (ist sie nicht leer, ist die Bestandsaufnahme unvollständig)
# Sowohl Orte, deren Auflistung fehlschlug, als auch aufgelistete, aber nicht lesbare Dateien einbeziehen
@($enumErrors) + @($readErrors) | ForEach-Object { $_.TargetObject } |
    Set-Content -Path 'C:\audit\bat-uninspected.txt'

(2) Risikoklassifizierung. Wenden Sie die Entscheidungstabelle aus Kapitel 4 auf die Ergebnisse der Bestandsaufnahme an und sortieren Sie sie in „behalten“, „migrieren“ und „zuerst migrieren (VBScript-abhängig)“. Halten Sie gleichzeitig fest, wodurch jede bat-Datei gestartet wird (Aufgabenplanung, ein Job-Management-Tool, ein Mensch) und welchen Wirkungsbereich ein Fehlschlag hätte. Zu Ausführungskonten für nächtliche Jobs und dem „endet mit 0x1“-Problem siehe „When Task Scheduler Tasks Don’t Run or Exit with 0x1 — Isolating the Cause and Designing for Reliable Operation“.

(3) Pilot. Wählen Sie ein Skript mit geringer Auswirkung aus und schreiben Sie es mit dem Einstiegs-bat-Ansatz aus Kapitel 5 um. Bauen Sie an dieser Stelle die Ausführungsrichtlinie in das Design ein. Der Windows-Standard ist RemoteSigned, sodass lokal erstellte Skripte laufen, unsignierte Skripte mit der Internet-Markierung jedoch blockiert werden.12 Die Fehlersuche, wenn die Verteilung über eine Netzwerkfreigabe daran scheitert, sowie das vollständige Design einschließlich eines Signaturprozesses sind in „PowerShell Execution Policy and Script Signing“ zusammengefasst, das zeitgleich mit diesem Artikel veröffentlicht wurde.

(4) Parallelbetrieb. Lassen Sie die alte bat-Datei und das neue Skript für einen bestimmten Zeitraum nebeneinander laufen. Trennen Sie ihre Ausgabeziele und gleichen Sie die Ergebnisse ab, lassen Sie das neue Skript zunächst nur mit -WhatIf oder mit reiner Protokollierung laufen, und sorgen Sie dafür, dass ein Rollback nichts weiter bedeutet, als den Job wieder auf die bat-Datei zeigen zu lassen — richten Sie all das ein, bevor Sie die alte bat-Datei außer Dienst stellen, und die Migration selbst wird so gut wie nie zu einem Vorfall.

8. Zusammenfassung

  • Es gibt keinen Plan, cmd oder bat abzuschaffen, aber die offizielle Empfehlung lautet PowerShell. VBScript hingegen hat einen veröffentlichten Plan „veraltet → FoD → Entfernung“, daher hat aus bat aufgerufenes VBScript die höchste Migrationspriorität.
  • Migration ist Sortierung, nicht „alles“. Behalten Sie die Batch-Dateien, die zuverlässig laufen und sich nie ändern, und migrieren Sie diejenigen, die sich ändern, Fehlerbehandlung und Protokollierung benötigen und von VBScript abhängen.
  • bat stoppt nicht bei Fehlern, if errorlevel 1 ist ein Test auf „1 oder größer“, und %errorlevel% bricht, wenn eine gleichnamige Umgebungsvariable existiert. PowerShell bietet über try/catch, -WhatIf und Pester „bemerken, proben, absichern“.
  • Für die Übergangsphase ist der Aufruf von powershell.exe -File (oder pwsh -File) aus einer Einstiegs-bat-Datei die realistische Lösung, wobei der Exitcode über exit und %ERRORLEVEL% zurückgegeben wird.
  • Schreiben Sie hervorragende externe Befehle wie robocopy nicht um — bringen Sie nur die $LASTEXITCODE-Prüfung korrekt zum Laufen (8 oder höher bedeutet Fehler).
  • Der Ablauf lautet: Bestandsaufnahme (beginnend beim Lesen) → Risikoklassifizierung → Pilot → Parallelbetrieb. Vergessen Sie auch nicht das Design von Ausführungsrichtlinie und Verteilung.

Verwandte Artikel

Verwandte Beratungsbereiche

Die KomuraSoft LLC übernimmt die Bestandsaufnahme von Legacy-Assets, in denen bat, VBScript und PowerShell gemischt vorkommen, samt der Ausarbeitung von Migrationsplänen, die Umstellung nächtlicher Jobs auf PowerShell einschließlich des dazugehörigen Betriebsdesigns sowie die Untersuchung von Fehlern, die im Zuge einer Migration auftreten. Auch das Entschlüsseln einer Batch-Datei, deren Autor längst nicht mehr im Unternehmen ist, ist ein guter Ausgangspunkt für eine Anfrage.

  1. Microsoft Learn, Windows Commands. Dazu, dass Windows über zwei Shells verfügt, die Eingabeaufforderung (cmd) und PowerShell, und zur offiziellen Aussage, dass für die robusteste und aktuellste Windows-Automatisierung PowerShell statt Windows-Befehlen oder Windows Script Host empfohlen wird.  2

  2. Microsoft Learn, Deprecated features for Windows client. Dazu, dass die Einstufung von VBScript als veraltet im Oktober 2023 bekannt gegeben wurde, und zum Plan, es in künftigen Windows-Versionen als Feature on Demand auszuliefern, bevor es aus dem Betriebssystem entfernt wird.  2 3

  3. Microsoft Learn, Resources for deprecated features. Dazu, dass das VBScript-Feature on Demand anfangs vorinstalliert ist und während der Vorbereitung auf die Außerdienststellung ohne Unterbrechung genutzt werden kann.  2

  4. Microsoft Learn, Features removed or no longer developed in Windows Server. Dazu, dass VBScript in Windows Server 2025 als FoD ausgeliefert und in einer späteren Version entfernt wird, und dass PowerShell als Ersatz für Aufgabenautomatisierung und Skripting vorgeschlagen wird.  2

  5. Microsoft Learn, if. Dazu, dass „if errorlevel “ ein Größer-gleich-Test ist, der wahr ist, wenn der Exitcode des vorangegangenen Programms gleich der Zahl oder höher ist, und dass %errorlevel% eine Erweiterung ist, die voraussetzt, dass keine Umgebungsvariable namens ERRORLEVEL existiert, und andernfalls deren Wert zurückgibt.  2 3 4

  6. Microsoft Learn, about_Try_Catch_Finally. Dazu, wie try/catch/finally-Blöcke anweisungsbeendende und skriptbeendende Fehler behandeln, wie catch einen Ausnahmetyp angeben kann, und wie finally unabhängig vom Auftreten eines Fehlers ausgeführt wird und für Aufräumarbeiten genutzt werden kann.  2 3 4

  7. Microsoft Learn, about_CommonParameters. Zu den Risikominderungsparametern (-WhatIf/-Confirm), die Cmdlets bieten, die System oder Daten verändern, und dazu, dass -WhatIf nur eine Beschreibung der Auswirkung anzeigt, ohne den Befehl auszuführen.  2 3

  8. Microsoft Learn, about_Language_Keywords. Dazu, wie das exit-Schlüsselwort $LASTEXITCODE setzt und auf der cmd.exe-Seite %ERRORLEVEL% entspricht, zum durchgerechneten Beispiel, bei dem ein mit pwsh -File ausgeführtes Skript, das mit exit 4 endet, im %ERRORLEVEL% des Aufrufers als 4 beobachtet wird, und dazu, dass das Fehlen einer exit-Anweisung 0 bei normalem Abschluss und 1 bei einer unbehandelten Ausnahme bedeutet.  2

  9. Microsoft Learn, about_Pwsh. Zur Verwendung des -File-Parameters von pwsh, zum offiziellen Beispiel, %~dp0 beim Aufruf aus einem Batch-Skript für das Ausführungsverzeichnis zu verwenden, dazu, dass der Exitcode bei einem skriptbeendenden Fehler unter -File 1 ist, und dazu, dass ein Beenden mit dem exit-Befehl diese Zahl zum Exitcode macht.  2 3

  10. Microsoft Learn, robocopy. Zum Exitcode-Schema von robocopy (0 = nichts zu kopieren, 1 = alle Dateien erfolgreich kopiert, 8 und höher = ein oder mehrere Fehlschläge), dazu, dass der Standardwert für Wiederholungsversuche /r:1000000 (eine Million) mit einer Standardwartezeit von /w:30 Sekunden ist, sowie zu Optionen wie Spiegelung und Protokollierung.  2 3 4 5

  11. Microsoft Learn, about_Automatic_Variables. Dazu, dass die automatische Variable $LASTEXITCODE den Exitcode eines nativen Programms oder Skripts enthält, und dazu, wie sich ihr Wert bei der Ausführung eines Skripts mit -File bestimmt (1 bei einer Ausnahme, der an exit übergebene Wert, oder 0 bei normalem Abschluss).  2 3

  12. Microsoft Learn, about_Execution_Policies. Dazu, dass die Standard-Ausführungsrichtlinie unter Windows RemoteSigned ist, dass RemoteSigned für aus dem Internet stammende Skripte eine Signatur eines vertrauenswürdigen Herausgebers verlangt, für lokal erstellte Skripte jedoch keine, sowie zur Bedeutung der einzelnen Richtlinien (Restricted, AllSigned, Bypass usw.).  2

  13. Microsoft Learn, exit. Dazu, dass „exit /b “ ein Batch-Skript beendet und den angegebenen Wert in der Umgebungsvariable ERRORLEVEL setzt, und wie er beim Beenden von cmd selbst zum Prozess-Exitcode wird. 

  14. Microsoft Learn, about_PowerShell_exe. Zur Spezifikation des -File-Parameters von powershell.exe in Windows PowerShell 5.1, zur %windir%-Syntax für die Übergabe von Umgebungsvariablen aus cmd.exe und zur Behandlung von Exitcodes. 

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Dieser Artikel ist direkt mit den folgenden Leistungen verbunden.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Sollten wirklich alle Batch-Dateien im Unternehmen zu PowerShell migriert werden?
Eine Migration aller Dateien wird nicht empfohlen. Bei einer Batch-Datei, die seit Jahren zuverlässig läuft und für die keine Änderungen geplant sind, wird das Umschreiben selbst zu einer neuen Fehlerquelle. Vorrangige Kandidaten sind Dateien, die demnächst geändert werden, die Fehlerbehandlung und Protokollierung benötigen, sowie solche, die VBScript (cscript/wscript) aufrufen. Es entspricht der bewährten Praxis, sie mit einer Entscheidungstabelle zu sortieren und die lohnenden Fälle schrittweise zu migrieren.
Werden cmd.exe und Batch-Dateien abgeschafft?
cmd.exe steht nicht auf der Liste der veralteten Windows-Funktionen, und es gibt keine Ankündigung zur Entfernung. Microsoft erklärt jedoch ausdrücklich, dass für die Automatisierung unter Windows PowerShell statt Windows-Befehlen oder WSH empfohlen wird. VBScript hingegen wurde im Oktober 2023 offiziell als veraltet eingestuft, und ein gestufter Plan wurde veröffentlicht, wonach es in künftigen Windows-Versionen zu einem optionalen Feature (Feature on Demand) wird, bevor es aus dem Betriebssystem entfernt wird. bat selbst wird weiterlaufen, aber der Tag wird sicher kommen, an dem das von Ihren bat-Dateien aufgerufene VBScript nicht mehr funktioniert.
Wie ruft man ein PowerShell-Skript aus einer Batch-Datei auf?
Übergeben Sie das Skript mit dem Parameter -File an powershell.exe (oder pwsh.exe für PowerShell 7). Für ein Skript im selben Ordner wie die bat-Datei ist die Auflösung des Speicherorts über %~dp0 – wie in „powershell.exe -NoProfile -File "%~dp0job.ps1"“ – die in der offiziellen Dokumentation gezeigte Schreibweise. Beachten Sie, dass die Angabe von -ExecutionPolicy für den vorrangigen Process-Bereich gilt und dadurch eine vom Administrator konfigurierte Richtlinie abschwächt; lassen Sie sie daher in der bat-Datei weg und überlassen Sie die Steuerung der Ausführungsrichtlinie der Umgebung. Wenn das Skript mit exit einen Zahlenwert zurückgibt, wird dieser Wert direkt an %ERRORLEVEL% auf der bat-Seite weitergereicht, sodass Sie das Innenleben zu PowerShell verlagern können, während die bestehende Jobsteuerung unverändert bleibt.
Welche Fallstricke birgt %ERRORLEVEL% in bat?
Der klassische Fallstrick ist, dass „if errorlevel 1“ bedeutet „wahr, wenn der Exitcode 1 oder größer ist“ – ein Größer-gleich-Test, kein Gleichheitstest. Außerdem ist %errorlevel% eine dynamische Erweiterung, die voraussetzt, dass keine Umgebungsvariable namens ERRORLEVEL definiert ist; definieren Sie also selbst eine mit set ERRORLEVEL=0, wird ab diesem Zeitpunkt immer dieser Wert zurückgegeben. Darüber hinaus fährt bat standardmäßig auch dann mit der nächsten Zeile fort, wenn ein Befehl fehlschlägt, sodass jeder Fehler, dessen Prüfung Sie zu schreiben vergessen haben, still verschluckt wird. Das relative Fehlen solcher Fallstricke ist der eigentliche Beweggrund für die Migration zu PowerShell, das über eine echte Fehlerbehandlung verfügt.
Wie schreibt man eine Batch-Datei, die robocopy verwendet, in PowerShell um?
Die Standardantwort lautet: nicht umschreiben. robocopy ist ein hervorragender externer Befehl mit bewährten Funktionen für Wiederholungsversuche, Spiegelung und Protokollierung, und Sie können ihn direkt aus PowerShell aufrufen. Eine Neuimplementierung mit Copy-Item bedeutet viel Aufwand bei geringerer Zuverlässigkeit. Worauf Sie achten müssen, ist die Interpretation des Exitcodes: robocopy liefert Werte von 0 bis 8 und darüber, wobei 8 und höher einen Fehler bedeuten und 1 ein erfolgreiches Kopieren. Prüfen Sie auf der PowerShell-Seite $LASTEXITCODE und behandeln Sie „8 oder größer“ als Fehler.
Ich bin bei der Verteilung eines PowerShell-Skripts auf die Ausführungsrichtlinie gestoßen. Was sollte ich tun?
Die Standard-Ausführungsrichtlinie (RemoteSigned) verlangt für Skripte, die als aus dem Internet stammend markiert sind, eine Signatur. Wird die Verteilung über eine Netzwerkfreigabe blockiert, klären Sie zunächst die Ursache; als dauerhafte Lösung sind entweder ein Signaturprozess oder eine Vereinheitlichung über Gruppenrichtlinien der richtige Weg. Das Anhängen von -ExecutionPolicy Bypass beim Aufruf aus einer Batch-Datei ist bequem, doch verwenden Sie es nur, nachdem Sie bestätigt haben, dass dies tatsächlich dem beabsichtigten Zustand des Richtliniendesigns Ihrer Organisation entspricht.

Autorenprofil

Profilseite des Artikelautors.

Go Komura

Geschäftsführer von KomuraSoft LLC

Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.

Zurück zum Blog