Das Beste aus zwei Welten
PowerShell-Skripte als Batch verpacken
Mit der PowerShell enthält Windows eine ziemlich mächtige und moderne Umgebung für die Skriptprogrammierung. Anwendern wirft Microsoft mit einer übervorsichtigen Ausführungsrichtlinie und mangelhafter Integration in den Explorer aber dicke Knüppel zwischen die Beine. Ein c’t-Skript ändert das.
Windows enthält zwei miteinander konkurrierende Plattformen zur Skript-Programmierung: die klassische Eingabeaufforderung mit ihrer Batch-Sprache und die PowerShell. Als Entwickler ist man mit der PowerShell besser bedient, denn deren Sprache ist wesentlich moderner und bietet weitaus mehr Möglichkeiten als die in die Jahre gekommene Batch-Sprache. Aus Anwendersicht hat aber letztere klare Vorteile: Batch-Dateien lassen sich einfach per Doppelklick im Explorer starten oder per Rechtsklick als Administrator ausführen. Man kann per Drag & Drop Dateien auf eine Batch-Datei ziehen und sie ihr so als Parameter übergeben. Und Windows erlaubt per Grundeinstellung das Ausführen von Batch-Dateien. Die PowerShell ist dagegen erst mal so konfiguriert, dass man sie nur interaktiv benutzen kann; die Ausführung von Skripten muss der Anwender zunächst per Ausführungsrichtlinie erlauben oder sich beim Aufruf der PowerShell mit komplexen Befehlszeilenoptionen herumschlagen.
Für Power-User oder Administratoren, die ständig mit der PowerShell arbeiten, mögen diese Hakeleien beherrschbar sein, spätestens wenn man ein Skript aber an unbedarftere Anwender weitergeben will, stellen sie ein echtes Hindernis dar. Abhilfe schafft dann gern mal die Volte, zusätzlich zu dem Skript auch noch eine Batch-Datei zu liefern, die nichts anderes tut, als das Skript aufzurufen und die PowerShell dabei mit den nötigen Kommandozeilenoptionen zu versorgen. Das birgt aber die Gefahr, dass dieses Pärchen versehentlich auseinandergerissen wird und dann nicht mehr funktioniert.
Verschnürt
Ideal wäre es, wenn man ein Dateiformat hätte, das das Beste aus den beiden Skript-Welten in sich vereint. Der im Folgenden vorgestellte Lösungsansatz setzt genau das um: Er bettet ein PowerShell-Skript in eine Batch-Datei ein, die sich dann wie jede andere verwenden lässt, also unter anderem einfach per Doppelklick zu starten ist. Der Batch-Code extrahiert das Skript wieder in eine temporäre PowerShell-Datei und bastelt einen Befehl zusammen, der die PowerShell zusammen mit dem Skript und den erwähnten Kommandozeilenoptionen startet. Nachdem das Skript durchgelaufen ist, löscht der Batch-Code es wieder.
Das Zusammenschnüren der BatchDatei erledigt – was auch sonst? – ein PowerShell-Skript; es heißt ConvertTo-BatchFile.ps1 und steht unter ct.de/y22p zum Download bereit. Wie der untenstehende Code zeigt, nimmt es den Namen der zu verpackenden PowerShell-Datei als $PsFile und den der zu schreibenden Batch-Datei als $Destination entgegen. Fehlt letzterer, erzeugt ihn das Skript, indem es in $PsFile die Endung „.ps1“ durch „.cmd“ ersetzt.
Zeile 14 liest den Inhalt des zu verpackenden Skripts in die Variable $text ein. Der Here-String ab Zeile 15 ($header) definiert den Batch-Code, der gleich das Skript ergänzen soll. Er enthält in Zeile 17 einen Platzhalter {0}, den Zeile 26 durch die Anzahl der Zeilen des Codes ersetzt (dazu gleich mehr). Schließlich setzt das Skript den $header und den $text zusammen und schreibt das Ganze in die Ausgabedatei.
Die wichtigsten Befehle des Batch-Codes stehen in den Zeilen 17 und 18: Erstere benutzt das Windows-eigene Programm more, um eine Kopie der gerade laufenden Batch-Datei ("%~f0") in den %temp%-Ordner zu schreiben und dabei die Endung wieder durch „.ps1“ zu ersetzen ("%temp%\%~n0.ps1"). Der Aufruf macht sich zunutze, dass man more mit der Option +n anweisen kann, die ersten n Zeilen der Ausgabe zu überspringen – also genau die Zeilen, die das Konvertierungs-Skript zuvor der PowerShell-Datei hinzugefügt hat. Die Zahl n stammt dabei aus der oben erwähnten Ersetzung des Platzhalters {0}. Wenn Sie für Ihre Zwecke den Batch-Code ändern wollen, zum Beispiel die abschließende pause-Zeile entfernen, sollten Sie das also besser im Konvertierungs-Skript machen, damit die Zeilenzahl nachher in der Batch-Datei stimmt. Andernfalls müssen Sie daran denken, die Zahl dort nachzuführen.
Der powershell-Aufruf in Zeile 18 enthält die Option -ExecutionPolicy Bypass, damit die Skript-Verarbeitung auf einem Zielrechner unabhängig von einer dort möglicherweise vorhandenen restriktiven Ausführungsrichtlinie klappt. Mit dem abschließenden %* reicht die Batch-Datei alle Argumente an das Skript weiter, die sie selbst übergeben bekommen hat.
Packautomat
Das Skript ConvertTo-BatchFile.ps1 kann sich auch selbst in eine Batch-Datei verpacken, wenn Sie es mit ihrem eigenen Dateinamen als Argument aufrufen. Das bietet sich an, wenn Sie es regelmäßig benutzen: Später zu konvertierende PowerShell-Skripte können Sie dann einfach per Drag & Drop auf die Batch-Datei ziehen. Alternativ verfrachten Sie die Batch-Datei ins „Senden an“-Menü. Dazu wählen Sie aus ihrem Kontextmenü im Explorer den Befehl „Kopieren“ und geben in die Eingabezeile des Explorer shell:sendto ein. Im SendTo-Ordner rechtsklicken Sie auf einen freien Fleck und wählen den Befehl „Als Verknüpfung einfügen“. Die entstehende Verknüpfung können Sie nach eigenem Gusto umbenennen – ihr Name erscheint fürderhin als Eintrag im Untermenü „Senden an“ des Kontextmenüs von Dateien.
Es soll hier nicht verschwiegen werden, dass wir vor einiger Zeit schon mal eine ähnliche Lösung wie das hier beschriebene Skript vorgestellt haben („Batch ruft PowerShell“, c’t 8/2019, S. 168). Weil sie die temporäre PowerShell-Datei beim Aufruf zeilenweise mit echo-Befehlen selbst geschrieben hat, war sie aber recht fehleranfällig und hatte ihre Probleme mit bestimmten Sonderzeichen und mit Leerzeilen im Skript. Außerdem war sie nicht so bequem in der Handhabung.
ConvertTo-BatchFile.ps1 räumt einen bedeutenden Vorbehalt aus dem Weg, der Sie vielleicht bislang davon abgehalten hat, sich näher mit der PowerShell zu beschäftigen. Geben Sie ihr eine Chance – auf längere Sicht ist sie für Skripter weitaus mächtiger als Batch-Dateien. (hos@ct.de)
ConvertTo-BatchFile.ps1: ct.de/y22p