PowerShell blockiert dein Skript: Ausführungsrichtlinie, Zone und Signatur
Die Sperre hat drei völlig verschiedene Ursachen, und für jede gibt es eine andere Antwort. Erst wenn du weißt, welche davon gerade greift, lohnt sich die Frage nach der richtigen Einstellung.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Die Fehlermeldung nennt eine Einstellung, meint aber selten die, die du gerade änderst
Der Ablauf ist in fast jedem Serverraum derselbe. Ein Skript, das gestern noch lief, bricht heute mit dem Hinweis ab, dass die Ausführung von Skripts auf diesem System deaktiviert ist. Jemand öffnet eine PowerShell mit erhöhten Rechten, setzt die Richtlinie auf RemoteSigned, bekommt keine Fehlermeldung zurück und probiert es erneut. Das Skript bricht wieder ab. Der Grund dafür steht in der Dokumentation von Microsoft in einem einzigen Satz: Ein Befehl, der die Ausführungsrichtlinie ändert, kann erfolgreich sein und trotzdem die wirksame Richtlinie nicht ändern, weil eine Ebene mit höherem Vorrang etwas anderes vorgibt.
Der zweite Grund hat mit der Richtlinie überhaupt nichts zu tun. Windows hängt an Dateien, die aus dem Internet oder aus einer nicht vertrauenswürdigen Zone stammen, einen zusätzlichen Datenstrom an, der genau das festhält. Unter RemoteSigned prüft PowerShell diese Markierung und verweigert die Ausführung, solange die Datei nicht signiert oder freigegeben ist. Für den Betrieb heißt das: Dasselbe Skript, einmal lokal geschrieben und einmal aus einem Ticketsystem heruntergeladen, verhält sich unterschiedlich, obwohl der Inhalt identisch ist.
Und dann gibt es die Reaktion, die den meisten Schaden anrichtet, weil sie so gut funktioniert. Irgendwann trägt jemand in die geplante Aufgabe ein Bypass ein, und danach läuft alles wieder. Microsoft schreibt selbst, dass die Ausführungsrichtlinie kein Sicherheitssystem ist, das Benutzer einschränkt, sondern eine Hilfe, damit niemand versehentlich etwas ausführt. Wer sie umgeht, umgeht also nichts Wesentliches. Er verliert allerdings die einzige Stelle, an der im Alltag noch sichtbar wurde, welche Skripte auf einem Server überhaupt starten dürfen.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Die Fälle, die im Serverbetrieb tatsächlich auflaufen
Sortiert nach dem, was auf dem Bildschirm steht. Der Unterschied zwischen einer Sache von zwei Minuten und einem halben Tag Suche liegt fast immer darin, ob jemand zuerst die Ebenen angesehen hat oder zuerst etwas geändert.
Symptom
Auf dem Server läuft das Skript, auf dem Arbeitsplatz bricht dasselbe Skript mit derselben Meldung ab.
Ursache
Die wirksame Vorgabe ist unterschiedlich, wenn auf keiner Ebene etwas gesetzt ist. In diesem Fall gilt auf Windows Server RemoteSigned und auf einem Windows-Client Restricted. Restricted lässt gar keine Skriptdatei zu, auch keine Profile und keine Formatdateien.
Lösung
Setz auf dem Arbeitsplatz die Richtlinie im Bereich CurrentUser auf RemoteSigned, oder besser: Verteil die Vorgabe für alle Arbeitsplätze über die Gruppenrichtlinie, damit sie nicht an jedem Gerät einzeln hängt. Auf dem Server brauchst du in diesem Fall gar nichts zu ändern.
Symptom
Set-ExecutionPolicy läuft ohne Fehler durch, Get-ExecutionPolicy zeigt danach unverändert den alten Wert.
Ursache
Eine Ebene mit höherem Vorrang gibt etwas anderes vor. Die Reihenfolge lautet MachinePolicy, UserPolicy, Process, CurrentUser, LocalMachine, und wer LocalMachine setzt, während CurrentUser oder eine Gruppenrichtlinie etwas anderes sagt, ändert nichts an der wirksamen Richtlinie.
Lösung
Ruf Get-ExecutionPolicy -List auf und lies die Liste von oben nach unten. Steht in MachinePolicy oder UserPolicy ein Wert, führt der Weg über die Gruppenrichtlinie Turn on Script Execution und nicht über die Kommandozeile. Steht der Wert in CurrentUser, setz ihn dort auf Undefined, damit die Vorgabe des Rechners wieder greift.
Symptom
Das Skript lief im Editor, nach dem Kopieren aus einem Ticket oder von einer Freigabe wird es abgelehnt.
Ursache
An der Datei hängt ein zusätzlicher Datenstrom, der sie als aus dem Internet stammend kennzeichnet. Unter RemoteSigned lehnt PowerShell genau diese Dateien ohne gültige Signatur ab, unabhängig davon, wer sie geschrieben hat.
Lösung
Prüf mit Get-Item -Stream * und entfern die Markierung mit Unblock-File, nachdem du den Inhalt gelesen hast. Für den Dauerbetrieb ist der bessere Weg, Skripte gar nicht erst über den Browser zu verteilen, sondern über eine Freigabe im lokalen Intranet oder über ein internes Repository, aus dem sie ohne Markierung ankommen.
Symptom
Auf einer Server-Core-Installation oder in einem Anmeldeskript kommt die Meldung AuthorizationManager check failed.
Ursache
PowerShell benutzt für die Prüfung der Herkunftszone Schnittstellen der Windows-Shell. Auf Server Core gibt es diese Shell nicht, und beim Anmelden kann ein Skript starten, bevor die Arbeitsoberfläche bereitsteht. Die Prüfung schlägt dann fehl, obwohl an der Datei nichts auszusetzen ist.
Lösung
Verwend für diese Aufrufe Bypass oder AllSigned, denn beide kommen ohne die Zonenprüfung aus. Bei einem Anmeldeskript ist die saubere Variante, es zu signieren und die Umgebung auf AllSigned zu stellen, statt für jeden Aufruf einzeln ein Bypass einzutragen.
Symptom
Unter AllSigned bricht das eigene Modul ab, obwohl das Hauptskript signiert ist.
Ursache
PowerShell prüft die Signatur nicht nur an .ps1, sondern auch an .psm1, .psd1, .ps1xml, .cdxml und .xaml. Häufig ist außerdem die Zeichenkodierung nach dem Signieren verändert worden, etwa weil jemand die Datei in einem anderen Editor gespeichert hat. Vor PowerShell 7.2 musste eine signierte Datei in ASCII oder in UTF-8 ohne BOM vorliegen, und jede Änderung der Kodierung macht die Signatur ungültig.
Lösung
Prüf jede Datei einzeln mit Get-AuthenticodeSignature und sieh dir den Status an. Signier Modul, Manifest und Formatdateien gemeinsam mit demselben Zertifikat, leg die Kodierung im Editor fest und nimm sie in die Vorgaben des Repositorys auf, damit sie nicht bei jedem Speichern neu ausgehandelt wird.
Symptom
Das Zertifikat ist gültig, die Signatur trotzdem nicht vertrauenswürdig.
Ursache
Vertrauen entsteht nicht am Zertifikat, sondern an der Kette dahinter. Ein Zertifikat zur Codesignatur muss von einer Zertifizierungsstelle stammen, der der Rechner vertraut. Ein selbst ausgestelltes Zertifikat läuft nur dort, wo es zusätzlich im Speicher der vertrauenswürdigen Stammzertifizierungsstellen liegt, und ist deshalb für Tests gedacht und nicht für den Betrieb.
Lösung
Stell Signaturzertifikate über eure interne Zertifizierungsstelle aus und verteil die Kette über die Gruppenrichtlinie. Signier mit einem Zeitstempeldienst, dann bleibt die Signatur auch gültig, wenn das Zertifikat abgelaufen ist, denn Signaturzertifikate laufen häufig nach einem Jahr aus.
Fünf Blicke, und die Ursache ist eingegrenzt
- 01 Get-ExecutionPolicy -List zeigt, welche der fünf Ebenen die Vorgabe gerade setzt.
- 02 Stehen MachinePolicy oder UserPolicy fest, kommt die Vorgabe aus einer Gruppenrichtlinie.
- 03 Get-Item -Stream * verrät, ob die Datei als aus dem Internet stammend markiert ist.
- 04 Lautet die Meldung AuthorizationManager check failed, fehlt die Shell für die Zonenprüfung.
- 05 Läuft es erst mit Bypass, war es nie die Richtlinie, sondern die Herkunft der Datei.
Die Reihenfolge, in der du die Sperre auseinandernimmst
Sieben Schritte, und die ersten drei kosten zusammen keine zehn Minuten. Erst danach lohnt sich die Frage, welche Einstellung dauerhaft gelten soll, denn die Antwort darauf hängt davon ab, was du in den ersten Schritten gefunden hast.
Erst alle Ebenen ansehen, nicht nur die wirksame
Get-ExecutionPolicy allein zeigt dir nur das Ergebnis. Get-ExecutionPolicy -List zeigt dir die fünf Ebenen MachinePolicy, UserPolicy, Process, CurrentUser und LocalMachine in genau der Reihenfolge, in der sie sich gegenseitig überstimmen. Steht oben etwas anderes als Undefined, kannst du dir jedes Set-ExecutionPolicy weiter unten sparen.
Stehen die oberen beiden Ebenen fest, ist es eine Gruppenrichtlinie
MachinePolicy und UserPolicy lassen sich nicht mit einem Cmdlet ändern, sie kommen aus der Einstellung Turn on Script Execution unter Administrative Templates, Windows Components, Windows PowerShell. Die Computerkonfiguration hat dabei Vorrang vor der Benutzerkonfiguration. Wer die Richtlinie in einer verwalteten Umgebung ändern will, ändert also das Objekt und nicht den Server.
Die Datei auf ihre Herkunftsmarkierung prüfen
Mit Get-Item -Stream * siehst du, ob an der Datei ein zusätzlicher Datenstrom hängt, der sie als aus dem Internet stammend kennzeichnet. Unblock-File entfernt ihn. Gut zu wissen ist dabei, dass nicht jeder Weg diese Markierung setzt: Dateien, die über curl.exe, Invoke-WebRequest oder Invoke-RestMethod ankommen, tragen sie in der Regel nicht.
Auf Server Core an die Zonenprüfung denken
Wenn die Meldung AuthorizationManager check failed lautet, ist selten die Richtlinie schuld. PowerShell fragt für die Zonenprüfung Schnittstellen der Windows-Shell ab, und die stehen auf einer Server-Core-Installation gar nicht und während der Anmeldung noch nicht zur Verfügung. Bypass und AllSigned kommen ohne diese Prüfung aus und laufen deshalb dort durch.
Für den Dauerbetrieb eine Ebene wählen und dabei bleiben
Setz die Richtlinie dort, wo sie hingehört: über die Gruppenrichtlinie, wenn sie für viele Server gelten soll, über den Bereich LocalMachine, wenn es um einen einzelnen Server geht, und über den Bereich Process oder den Parameter -ExecutionPolicy beim Start, wenn es wirklich nur um einen Aufruf geht. Was du im Bereich Process setzt, verschwindet mit der Sitzung und taucht später nicht als unerklärliche Einstellung wieder auf.
AllSigned nur mit einer funktionierenden internen Zertifizierungsstelle
AllSigned ist die einzige Einstellung, die eine echte Aussage über die Herkunft eines Skripts erzwingt, und sie ist gleichzeitig die, die ohne Vorbereitung den Betrieb anhält. Sie verlangt eine gültige Signatur an jeder Datei, auch an denen, die auf dem Server selbst entstanden sind. Ohne ausgerollte Zertifikatskette und einen geübten Signierschritt führt sie dazu, dass jemand am zweiten Tag ein Bypass einträgt.
Die eigentliche Absicherung woanders aufbauen
Wenn es darum geht, unerwünschten Code zu verhindern, gehört das in eine Anwendungssteuerung wie AppLocker oder die Anwendungssteuerung von Windows, in eine gepflegte Rechtevergabe und in eine Protokollierung, die zeigt, was tatsächlich ausgeführt wurde. Die Ausführungsrichtlinie ergänzt das, sie ersetzt es nicht.
KI-generiertDieses Bild wurde mit KI erzeugt · Yves Hoppe / KI / cmt
Was die Ausführungsrichtlinie ist, und was sie ausdrücklich nicht ist
Die Dokumentation von Microsoft ist an dieser Stelle ungewöhnlich deutlich: Die Ausführungsrichtlinie ist kein Sicherheitssystem, das Handlungen von Benutzern einschränkt. Wer ein Skript nicht starten darf, kann seinen Inhalt an der Kommandozeile eintippen und bekommt dasselbe Ergebnis. Die Richtlinie soll verhindern, dass jemand versehentlich etwas ausführt, das er nicht ausführen wollte, und genau in dieser Rolle ist sie nützlich.
Für den Betrieb hat das zwei Folgen. Die erste: Wenn in einer Sicherheitsanforderung steht, dass Skripte nicht ausführbar sein dürfen, ist die Ausführungsrichtlinie nicht die Antwort. Dafür braucht es eine Anwendungssteuerung, die entscheidet, welcher Code auf einem System überhaupt laufen darf, und eine Protokollierung, die aufzeichnet, was ausgeführt wurde. Die zweite Folge ist angenehmer: Weil die Richtlinie keine Sicherheitsgrenze ist, musst du sie nicht wie eine behandeln. Ein RemoteSigned auf allen Servern ist kein Sicherheitsproblem, sondern eine sinnvolle Grundeinstellung.
Wo die Richtlinie ihren Wert hat, ist der Alltag. Sie fängt die Datei ab, die jemand aus einem Forum kopiert und ohne Blick auf den Inhalt startet. Sie macht sichtbar, dass ein Skript von außerhalb kommt. Und sie ist unter AllSigned der Hebel, mit dem sich in einem Unternehmen tatsächlich durchsetzen lässt, dass auf Servern nur Skripte laufen, die jemand vorher freigegeben hat. Das ist eine Prozessfrage mit technischer Unterstützung, keine technische Sperre.
Fünf Ebenen und eine feste Reihenfolge
Die Richtlinie wird nicht an einer Stelle gesetzt, sondern in fünf Bereichen, die sich gegenseitig überstimmen. Der Vorrang lautet von oben nach unten: MachinePolicy, UserPolicy, Process, CurrentUser, LocalMachine. Die ersten beiden kommen aus einer Gruppenrichtlinie und lassen sich mit Set-ExecutionPolicy nicht anfassen. Process gilt nur für die laufende Sitzung und ihre untergeordneten Prozesse und liegt in der Umgebungsvariablen $Env:PSExecutionPolicyPreference statt in einer Konfigurationsdatei. CurrentUser und LocalMachine werden dauerhaft gespeichert und bleiben bestehen, bis sie jemand wieder ändert.
Aus dieser Reihenfolge erklärt sich der Fall, der am häufigsten Zeit kostet. Jemand setzt LocalMachine, weil das der Bereich ist, den Set-ExecutionPolicy ohne weitere Angabe verwendet. Vorher hatte jemand anderes einmal CurrentUser gesetzt, vielleicht vor zwei Jahren, vielleicht auf einem anderen Konto. Der neue Befehl läuft durch, meldet nichts und wirkt nicht. Get-ExecutionPolicy -List zeigt diesen Zustand in fünf Zeilen, und deshalb ist dieser Aufruf immer der erste Schritt und nie der zweite.
Der Bereich, den du in einer verwalteten Umgebung tatsächlich verwenden solltest, ist die Gruppenrichtlinie. Die Einstellung heißt Turn on Script Execution und liegt unter Administrative Templates, Windows Components, Windows PowerShell, sowohl in der Computer- als auch in der Benutzerkonfiguration, wobei die Computerkonfiguration Vorrang hat. Eine deaktivierte Einstellung entspricht Restricted. Eine aktivierte Einstellung bietet drei Möglichkeiten, die den Werten Unrestricted, RemoteSigned und AllSigned entsprechen. Nicht konfiguriert bedeutet, dass die Einstellungen aus PowerShell gelten, und das ist für die meisten Umgebungen die richtige Wahl.
Die Werte und was sie im Serverbetrieb bedeuten
Restricted lässt keine Skriptdatei zu, weder .ps1 noch Moduldateien, Formatdateien oder Profile. Einzelne Befehle funktionieren weiter. Auf einem Windows-Client ist das die wirksame Vorgabe, wenn auf keiner Ebene etwas gesetzt ist, auf einem Windows Server dagegen nicht. Dort greift in diesem Fall RemoteSigned, und dieser Unterschied ist die Erklärung für die meisten Fälle, in denen dasselbe Skript auf zwei Systemen unterschiedlich reagiert.
RemoteSigned ist der Normalfall im Serverbetrieb. Lokal geschriebene Skripte laufen ohne Signatur, Dateien mit einer Herkunftsmarkierung aus dem Internet brauchen entweder eine gültige Signatur oder ein Unblock-File. Das ist ein sinnvoller Zuschnitt, weil er die häufigste Gefahrenquelle abdeckt, ohne den Alltag anzuhalten. AllSigned verlangt die Signatur an jeder Datei und fragt bei einem Herausgeber, den das System noch nicht kennt, ausdrücklich nach. Unrestricted lässt alles zu und warnt lediglich bei Dateien außerhalb des lokalen Intranets. Bypass blockiert nichts und warnt nicht, es ist für Fälle gedacht, in denen PowerShell in eine größere Anwendung eingebettet ist, die ihr eigenes Sicherheitsmodell mitbringt.
Undefined bedeutet, dass in diesem Bereich nichts gesetzt ist. Genau das ist der Wert, den du setzt, wenn du eine alte Einstellung loswerden willst, statt eine neue darüberzulegen. Und Default ist keine eigene Regel, sondern die Rückkehr zur Vorgabe, die auf Windows-Clients und -Servern RemoteSigned lautet. Wer eine Umgebung aufräumt, setzt die unteren Bereiche auf Undefined und entscheidet oben einmal bewusst, was gelten soll.
Skripte signieren, damit die Einstellung überhaupt etwas bedeutet
Eine Signatur braucht ein Zertifikat zur Codesignatur, und für ein Unternehmen kommt das aus der internen Zertifizierungsstelle. Ein selbst ausgestelltes Zertifikat, wie es New-SelfSignedCertificate mit dem Typ CodeSigning erzeugt, ist ausdrücklich für Tests gedacht: Es funktioniert nur auf dem Rechner, auf dem es liegt, und ein damit signiertes Skript läuft nirgends sonst. Für die Verteilung im Haus muss die Kette bis zur Stammzertifizierungsstelle auf jedem Server bekannt sein, und dafür ist die Gruppenrichtlinie der übliche Weg.
Signiert wird mit Set-AuthenticodeSignature. Das Cmdlet hängt die Signatur als Kommentarblock an das Ende der Datei, der mit einem Hinweis in der Form # SIG # beginnt und endet. Geprüft wird mit Get-AuthenticodeSignature, und das lohnt sich als eigener Schritt, weil eine ungültige Signatur genauso aussieht wie gar keine, sobald sie einmal in der Ablage liegt. Wichtig ist außerdem der Zeitstempeldienst beim Signieren: Ohne ihn wird jedes signierte Skript ungültig, sobald das Zertifikat abläuft, und Signaturzertifikate laufen oft schon nach einem Jahr aus.
Zwei Stolperstellen fallen im Alltag immer wieder auf. Die erste ist die Zeichenkodierung: Wer eine signierte Datei in einem anderen Editor öffnet und speichert, kann die Kodierung ändern und macht damit die Signatur ungültig, ohne eine einzige Zeile Code angefasst zu haben. Vor PowerShell 7.2 mussten signierte Skripte in ASCII oder UTF-8 ohne BOM vorliegen. Die zweite ist der Umfang: Geprüft werden neben .ps1 auch .psm1, .psd1, .ps1xml, .cdxml und .xaml. Ein Modul, dessen Manifest nicht mitsigniert wurde, fällt unter AllSigned genauso durch wie ein unsigniertes Skript.
Was danach im Alltag stehen bleibt
Nach der Klärung bleibt eine Entscheidung, die weniger technisch ist, als sie aussieht. Entweder ihr betreibt eure Server mit RemoteSigned und verlasst euch darauf, dass Skripte aus einer kontrollierten Ablage kommen und dass die Rechtevergabe stimmt. Oder ihr geht auf AllSigned und baut den Signierschritt in die Auslieferung ein, damit niemand ihn vergessen kann. Beides ist vertretbar, der Mischzustand nicht, denn ein AllSigned mit vier Ausnahmen ist in der Wirkung ein RemoteSigned mit mehr Verwaltungsaufwand.
Damit die Entscheidung hält, gehört sie an drei Stellen hinterlegt: in die Gruppenrichtlinie, in die Anleitung für neue Kollegen und in den Bauprozess, mit dem Skripte in die Ablage kommen. Wenn das Signieren ein manueller Schritt bleibt, den jemand vor der Übergabe von Hand macht, fällt er nach der dritten dringenden Änderung weg. Wenn es ein Schritt in der Auslieferung ist, fällt stattdessen die Auslieferung auf, und das ist der gewünschte Zustand.
Der letzte Punkt betrifft die Protokollierung. Weil die Ausführungsrichtlinie keine Grenze ist, sondern eine Hilfe, brauchst du eine zweite Quelle für die Frage, was auf einem Server tatsächlich ausgeführt wurde. PowerShell kann die ausgeführten Skriptblöcke protokollieren und Sitzungen mitschreiben, und beides lässt sich zentral einsammeln. Für die Fehlersuche ist das nebenbei die schnellste Abkürzung, weil dort auch die Aufrufe stehen, die jemand mit einem Bypass an allen Einstellungen vorbeigeschoben hat.
Dazu passende Kurse
Wenn Skripte bei euch mehr Aufgaben übernehmen sollen als bisher, geben die Kurse zur Skriptautomatisierung im Serverbetrieb die Grundlage dafür.
Weil die Ausführungsrichtlinie nur eine von vielen Stellschrauben im Betrieb ist, gehören Windows-Server-Kurse mit PowerShell im Alltag zum selben Thema.
Wie sicher bist du beim Thema wirklich?
Lesen fühlt sich schnell nach Können an. Ein kurzer Test zeigt dir, was davon schon sitzt und wo sich ein Kurs lohnt. Kostenlos, ohne Anmeldung, mit einer Erklärung zu jeder Antwort.
Wo du genau das übst
Danke an Trainer Sven, welcher ein sehr detailliertes und fachliches KnowHow besitzt.
Ich beziehe mich hier nur auf die Nachschlung durch Herrn Marco Jachmann. Herr Jachmann ist überaus kompetent und hat alle Inhalte professionell vermittelt.
Sehr sehr gut aufbereitete Nachschulung mit genau dem notwendigen Engagement und der erforderlichen Vorbereitung innerhalb von 48 Stunden.
Häufige Fragen
Warum läuft dasselbe Skript auf dem Server, aber nicht auf meinem Rechner?
Ist Bypass gefährlich?
Können wir die Richtlinie zentral vorgeben?
Lohnt sich AllSigned für uns?
Warum ist ein Skript blockiert, obwohl es von unserem eigenen Fileserver kommt?
Deine Ansprechpartner
Du bist dir nicht sicher, welcher Kurs oder welches Level zu dir passt? Wir beraten dich persönlich und kostenlos.
Yves Hoppe
Weiterbildung & Beratung
Hilft dir, aus dem Windows Server-Programm den passenden Kurs für deinen Stand zu finden.
Norbert Jansen
Beratung & Inhouse
Plant mit dir Inhouse-Trainings, die auf eure Abläufe und euren Datenbestand zugeschnitten sind.
PowerShell im Serverbetrieb einmal von Grund auf sortieren
Bei cmt arbeitest du an einer Umgebung, in der Richtlinien, Zonen und Signaturen so ineinandergreifen wie bei euch, und siehst dabei, an welcher Stelle eine Sperre entsteht und welche Einstellung sie tatsächlich auflöst.