Aus mehreren Gründen, hauptsächlich aus Sicherheitsgründen, sind PowerShell-Skripte nicht so einfach portierbar und verwendbar wie Batch-Skripte. Wir können jedoch ein Batch-Skript mit unseren PowerShell-Skripten bündeln, um diese Probleme zu umgehen. Hier zeigen wir Ihnen einige dieser Problembereiche und wie Sie ein Batch-Skript erstellen, um sie zu umgehen.
Warum kann ich meine .PS1-Datei nicht einfach auf einen anderen Computer kopieren und ausführen?
Wenn das Zielsystem nicht vorkonfiguriert wurde, um das Ausführen beliebiger Skripte mit den erforderlichen Rechten und den richtigen Einstellungen zu ermöglichen, werden Sie wahrscheinlich auf einige Probleme stoßen, wenn Sie dies versuchen.
- PowerShell ist standardmäßig nicht mit der Dateierweiterung .PS1 verknüpft.
Wir haben dies zunächst in unserer PowerShell Geek School-Reihe angesprochen. Windows ordnet .PS1-Dateien standardmäßig Notepad zu, anstatt sie an den PowerShell-Befehlsinterpreter zu senden. Dies dient dazu, die versehentliche Ausführung bösartiger Skripte durch einfaches Doppelklicken zu verhindern. Es gibt Möglichkeiten, dieses Verhalten zu ändern, aber es ist wahrscheinlich nicht etwas, das Sie auf jedem Computer tun möchten, zu dem Sie Ihre Skripte mitnehmen – insbesondere, wenn einige dieser Computer nicht Ihre eigenen sind.
- PowerShell lässt standardmäßig keine externe Skriptausführung zu.
Die ExecutionPolicy-Einstellung in PowerShell verhindert standardmäßig die Ausführung externer Skripts in allen Windows-Versionen. In einigen Windows-Versionen lässt die Standardeinstellung überhaupt keine Skriptausführung zu. Wie Sie diese Einstellung ändern, haben wir Ihnen unter So erlauben Sie die Ausführung von PowerShell-Skripten unter Windows 7 gezeigt. Dies ist jedoch auch etwas, das Sie nicht auf jedem Computer tun möchten.
- Einige PowerShell-Skripts funktionieren nicht ohne Administratorberechtigungen.
Auch wenn Sie mit einem Konto auf Administratorebene ausgeführt werden, müssen Sie die Benutzerkontensteuerung (UAC) durchlaufen, um bestimmte Aktionen auszuführen. Wir möchten dies nicht deaktivieren, aber es ist trotzdem schön, wenn wir es etwas einfacher machen können.
- Einige Benutzer haben möglicherweise angepasste PowerShell-Umgebungen.
Sie werden wahrscheinlich nicht oft darauf stoßen, aber wenn Sie dies tun, kann dies die Ausführung und Fehlerbehebung Ihrer Skripts etwas frustrierend machen. Glücklicherweise können wir dies auch umgehen, ohne dauerhafte Änderungen vorzunehmen.
Schritt 1: Zum Ausführen doppelklicken.
Beginnen wir mit dem ersten Problem – .PS1-Dateizuordnungen. Sie können nicht doppelklicken, um .PS1-Dateien auszuführen, aber Sie können eine .BAT-Datei auf diese Weise ausführen. Wir schreiben also eine Batchdatei, um das PowerShell-Skript für uns über die Befehlszeile aufzurufen.
Wir müssen also nicht die Batchdatei für jedes Skript neu schreiben oder jedes Mal, wenn wir ein Skript verschieben, es wird eine selbstreferenzierende Variable verwendet, um den Dateipfad für das PowerShell-Skript zu erstellen. Damit dies funktioniert, muss die Batchdatei im selben Ordner wie Ihr PowerShell-Skript abgelegt werden und denselben Dateinamen haben. Wenn Ihr PowerShell-Skript also „MyScript.ps1“ heißt, sollten Sie Ihre Batch-Datei „MyScript.bat“ nennen und sicherstellen, dass sie sich im selben Ordner befindet. Fügen Sie dann diese Zeilen in das Batch-Skript ein:
@ECHO OFF
PowerShell.exe -Command "& '%~dpn0.ps1'"
PAUSE
Wenn die anderen Sicherheitsbeschränkungen nicht vorhanden wären, wäre das wirklich alles, was Sie brauchen, um ein PowerShell-Skript aus einer Batchdatei auszuführen. Tatsächlich sind die erste und letzte Zeile hauptsächlich nur eine Frage der Präferenz – die zweite Zeile macht wirklich die Arbeit. Hier ist die Aufschlüsselung:
@ECHO AUS deaktiviert das Befehlsecho. Dies verhindert nur, dass Ihre anderen Befehle auf dem Bildschirm angezeigt werden, wenn die Batchdatei ausgeführt wird. Diese Zeile selbst wird durch das davor stehende at-Symbol (@) ausgeblendet.
PowerShell.exe -Befehl „& ‘%~dpn0.ps1′“ führt das PowerShell-Skript tatsächlich aus. PowerShell.exe kann natürlich von jedem CMD-Fenster oder jeder Batch-Datei aufgerufen werden, um PowerShell wie gewohnt auf einer nackten Konsole zu starten. Sie können es auch verwenden, um Befehle direkt aus einer Batchdatei auszuführen, indem Sie den Parameter -Command und die entsprechenden Argumente einschließen. Dies wird zum Zielen unserer .PS1-Datei verwendet, indem die spezielle %~dpn0-Variable verwendet wird. Von einer Batchdatei aus ausgeführt, berechnet %~dpn0 den Laufwerksbuchstaben, den Ordnerpfad und den Dateinamen (ohne Erweiterung) der Batchdatei. Da sich die Batchdatei und das PowerShell-Skript im selben Ordner befinden und denselben Namen haben, wird %~dpn0.ps1 in den vollständigen Dateipfad des PowerShell-Skripts übersetzt.
PAUSE pausiert einfach die Batch-Ausführung und wartet auf Benutzereingaben. Dies ist im Allgemeinen nützlich, wenn Sie es am Ende Ihrer Batch-Dateien haben, damit Sie die Befehlsausgabe überprüfen können, bevor das Fenster verschwindet. Wenn wir jeden Schritt testen, wird die Nützlichkeit dieser Vorgehensweise immer offensichtlicher.
Die grundlegende Batch-Datei ist also eingerichtet. Zu Demonstrationszwecken wird diese Datei als „D:Script LabMyScript.bat“ gespeichert und im selben Ordner befindet sich eine „MyScript.ps1“. Sehen wir uns an, was passiert, wenn wir auf MyScript.bat doppelklicken.

Offensichtlich lief das PowerShell-Skript nicht, aber das ist zu erwarten – wir haben immerhin nur das erste unserer vier Probleme gelöst. Hier werden jedoch einige wichtige Bits demonstriert:
- Der Fenstertitel zeigt an, dass das Batch-Skript PowerShell erfolgreich gestartet hat.
- Die erste Ausgabezeile zeigt, dass ein benutzerdefiniertes PowerShell-Profil verwendet wird. Dies ist das potenzielle Problem Nr. 4, das oben aufgeführt ist.
- Die Fehlermeldung zeigt die geltenden ExecutionPolicy-Einschränkungen. Das ist unser Problem #2.
- Der unterstrichene Teil der Fehlermeldung (der nativ durch die Fehlerausgabe von PowerShell erfolgt) zeigt, dass das Batch-Skript korrekt auf das beabsichtigte PowerShell-Skript ausgerichtet war (D:Script LabMyScript.ps1). Wir wissen also zumindest, dass vieles richtig funktioniert.
Das Profil ist in diesem Fall ein einfaches einzeiliges Skript, das für diese Demonstration verwendet wird, um eine Ausgabe zu generieren, wenn das Profil aktiv ist. Auch hierfür können Sie Ihr eigenes PowerShell-Profil anpassen, wenn Sie diese Skripte selbst testen möchten. Fügen Sie einfach folgende Zeile zu Ihrem Profilskript hinzu:
Write-Output 'Custom PowerShell profile in effect!'
Die ExecutionPolicy auf dem Testsystem ist hier auf RemoteSigned gesetzt. Dies ermöglicht die Ausführung von lokal erstellten Skripten (wie das Profilskript), während Skripte von externen Quellen blockiert werden, es sei denn, sie sind von einer vertrauenswürdigen Autorität signiert. Zu Demonstrationszwecken wurde der folgende Befehl verwendet, um MyScript.ps1 als von einer externen Quelle stammend zu kennzeichnen:
Add-Content -Path 'D:Script LabMyScript.ps1' -Value "[ZoneTransfer]`nZoneId=3" -Stream 'Zone.Identifier'
Dadurch wird der alternative Datenstrom Zone.Identifier auf MyScript.ps1 festgelegt, sodass Windows annimmt, dass die Datei aus dem Internet stammt. Mit folgendem Befehl lässt es sich leicht rückgängig machen:
Clear-Content -Path 'D:Script LabMyScript.ps1' -Stream 'Zone.Identifier'
Schritt 2: ExecutionPolicy umgehen.
Das Umgehen der ExecutionPolicy-Einstellung von CMD oder einem Batch-Skript ist eigentlich ziemlich einfach. Wir ändern einfach die zweite Zeile des Skripts, um dem Befehl PowerShell.exe einen weiteren Parameter hinzuzufügen.
PowerShell.exe -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'"
Der Parameter -ExecutionPolicy kann verwendet werden, um die ExecutionPolicy zu ändern, die verwendet wird, wenn Sie eine neue PowerShell-Sitzung starten. Dies wird nicht über diese Sitzung hinaus bestehen bleiben, sodass wir PowerShell jederzeit wie folgt ausführen können, ohne die allgemeine Sicherheitslage des Systems zu schwächen. Nachdem wir das behoben haben, versuchen wir es noch einmal:

Nachdem das Skript nun ordnungsgemäß ausgeführt wurde, können wir sehen, was es tatsächlich tut. Es teilt uns mit, dass wir das Skript als eingeschränkter Benutzer ausführen. Das Skript wird tatsächlich von einem Konto mit Administratorrechten ausgeführt, aber die Benutzerkontensteuerung steht im Weg. Obwohl Details darüber, wie das Skript den Administratorzugriff überprüft, den Rahmen dieses Artikels sprengen würden, wird hier der Code zur Demonstration verwendet:
if (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator"))
{Write-Output 'Running as Administrator!'}
else
{Write-Output 'Running Limited!'}
Pause
Sie werden auch feststellen, dass die Skriptausgabe jetzt zwei „Pause“-Operationen enthält – eine aus dem PowerShell-Skript und eine aus der Batchdatei. Der Grund dafür wird im nächsten Schritt deutlicher.
Schritt 3: Administratorzugriff erhalten.
Wenn Ihr Skript keine Befehle ausführt, die eine Erhöhung erfordern, und Sie sich ziemlich sicher sind, dass Sie sich keine Sorgen machen müssen, dass die benutzerdefinierten Profile anderer Personen im Weg sind, können Sie den Rest überspringen. Wenn Sie jedoch einige Cmdlets auf Administratorebene ausführen, benötigen Sie dieses Stück.
Leider gibt es keine Möglichkeit, die UAC für die Erhöhung innerhalb einer Batchdatei oder CMD-Sitzung auszulösen. PowerShell erlaubt uns dies jedoch mit Start-Process. Bei Verwendung mit „-Verb RunAs“ in seinen Argumenten versucht Start-Process, eine Anwendung mit Administratorrechten zu starten. Wenn die PowerShell-Sitzung nicht bereits erhöht ist, wird dadurch eine UAC-Eingabeaufforderung ausgelöst. Um dies aus der Batch-Datei zum Starten unseres Skripts zu verwenden, erzeugen wir am Ende zwei PowerShell-Prozesse – einen zum Auslösen des Start-Prozesses und einen anderen, der von Start-Prozess gestartet wird, um das Skript auszuführen. Die zweite Zeile der Batchdatei muss wie folgt geändert werden:
PowerShell.exe -Command "& {Start-Process PowerShell.exe -ArgumentList '-ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -Verb RunAs}"
Wenn die Batchdatei ausgeführt wird, stammt die erste Ausgabezeile, die wir sehen, aus dem PowerShell-Profilskript. Dann wird eine UAC-Eingabeaufforderung angezeigt, wenn Start-Process versucht, MyScript.ps1 zu starten.

Nachdem Sie durch die UAC-Eingabeaufforderung geklickt haben, wird eine neue PowerShell-Instanz erstellt. Da dies eine neue Instanz ist, sehen wir natürlich wieder den Hinweis zum Profilskript. Dann wird MyScript.ps1 ausgeführt und wir sehen, dass wir uns tatsächlich in einer erhöhten Sitzung befinden.

Und das ist der Grund, warum wir hier auch zwei Pausen machen. Ohne die im PowerShell-Skript würden wir die Ausgabe des Skripts nie sehen – das PowerShell-Fenster würde einfach auftauchen und verschwinden, sobald das Skript fertig ist. Und ohne die Pause in der Batch-Datei könnten wir nicht sehen, ob beim Starten von PowerShell überhaupt Fehler aufgetreten sind.
Schritt 4: Umgang mit benutzerdefinierten PowerShell-Profilen.
Lassen Sie uns diese hässliche benutzerdefinierte Profilmitteilung jetzt loswerden, oder? Hier ist es kaum störend, aber wenn das PowerShell-Profil eines Benutzers Standardeinstellungen, Variablen oder Funktionen auf eine Weise ändert, die Sie mit Ihrem Skript möglicherweise nicht erwartet haben, können dies wirklich lästig sein. Es ist viel einfacher, Ihr Skript vollständig ohne das Profil auszuführen, sodass Sie sich darüber keine Sorgen machen müssen. Dazu müssen wir nur die zweite Zeile der Batch-Datei noch einmal ändern:
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -Verb RunAs}"
Das Hinzufügen des Parameters -NoProfile zu beiden Instanzen von PowerShell, die vom Skript gestartet werden, bedeutet, dass das Profilskript des Benutzers in beiden Schritten vollständig umgangen wird und unser PowerShell-Skript in einer ziemlich vorhersehbaren Standardumgebung ausgeführt wird. Hier können Sie sehen, dass es in keiner der gespawnten Shells einen benutzerdefinierten Profilhinweis gibt.

Wenn Sie in Ihrem PowerShell-Skript keine Administratorrechte benötigen und Schritt 3 übersprungen haben, können Sie auf die zweite PowerShell-Instanz verzichten und die zweite Zeile Ihrer Batchdatei sollte so aussehen:
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'"
Die Ausgabe sieht dann so aus:

(Natürlich können Sie für Nicht-Administrator-Skripte auch an dieser Stelle auf eine Skriptende-Pause in Ihrem PowerShell-Skript verzichten, da alles im selben Konsolenfenster erfasst wird und dort durch die Pause am Ende des Skripts festgehalten würde die Batch-Datei sowieso.)
Fertige Batch-Dateien.
Abhängig davon, ob Sie Administratorberechtigungen für Ihr PowerShell-Skript benötigen (und Sie sollten diese wirklich nicht anfordern), sollte die endgültige Batchdatei wie eine der beiden unten aussehen.
Ohne Admin-Zugriff:
@ECHO OFF
PowerShell.exe -NoProfile -ExecutionPolicy Bypass -Command "& '%~dpn0.ps1'"
PAUSE
Mit Admin-Zugriff:
@ECHO OFF
PowerShell.exe -NoProfile -Command "& {Start-Process PowerShell.exe -ArgumentList '-NoProfile -ExecutionPolicy Bypass -File ""%~dpn0.ps1""' -Verb RunAs}"
PAUSE
Denken Sie daran, die Batchdatei im selben Ordner wie das PowerShell-Skript abzulegen, für das Sie sie verwenden möchten, und geben Sie ihr denselben Namen. Unabhängig davon, auf welches System Sie diese Dateien übertragen, können Sie dann Ihr PowerShell-Skript ausführen, ohne sich mit den Sicherheitseinstellungen des Systems herumschlagen zu müssen. Sie können diese Änderungen sicherlich jedes Mal manuell vornehmen, aber das erspart Ihnen diese Mühe und Sie müssen sich nicht darum kümmern, die Änderungen später rückgängig zu machen.
Verweise: