Best Practices
Allgemein
Unveränderliche Konfiguration in der Produktion in Erwägung ziehen
PowerShell Universal basiert auf einem skriptbasierten Konfigurationssystem. Dadurch können neue Instanzen von PowerShell Universal ohne Datenbankaufrufe und direkt aus einem Repository von Skripten konfiguriert werden. Das bedeutet, dass es bei der Bereitstellung in der Produktion vorteilhaft ist, ein gut getestetes Artefakt als Grundlage für Ihre PowerShell Universal-Konfiguration zu verwenden.
Sie können Werkzeuge wie Docker Compose verwenden, um PowerShell Universal-Konfigurationsdateien in ein Container-Image zu schichten, ohne ein Produktionssystem manuell aktualisieren zu müssen. PowerShell Universal bietet außerdem eine Deployment-Funktion, mit der Konfigurationen direkt auf einer Instanz veröffentlicht werden können. Sie können dann ein System für Continuous Deployment verwenden, um Ihre Produktionsinstanzen als Teil eines automatisierten Workflows zu aktualisieren.
Je nach Ihren Anforderungen, die typischerweise von der Teamgröße und der Nutzung abhängen, ist diese Art der Konfiguration möglicherweise nicht erforderlich.
Code First Editing deaktivieren, wenn es nicht verwendet wird
Die Funktion Code First Editing erkennt Änderungen im Repository-Verzeichnis mithilfe eines Dateisystem-Watchers. Diese Funktion ist nützlich, wenn eine PowerShell Universal-Konfiguration direkt aus dem Dateisystem mit Werkzeugen wie Visual Studio Code entwickelt wird. Allerdings kann dies unerwartete Nebenwirkungen haben, wenn Sie die Funktion nicht verwenden. Zum Beispiel kann das Schreiben von Dateien in das Repository, etwa von Protokollen, dazu führen, dass das PowerShell Universal-Konfigurationssystem sich unnötig neu lädt.
Wenn Sie Änderungen über die Admin-Konsole, per Git-Sync oder mithilfe von Deployments vornehmen, sollten Sie das automatische Neuladen deaktivieren. Dies erhöht die Leistung und verringert zugleich das Risiko unerwarteter Änderungen an Ihrer bereitgestellten Konfiguration.

Nicht-integrierte Umgebungen bevorzugen
Die integrierte Umgebung ist zwar schnell und einfach zu verwenden, führt jedoch alle Ihre PowerShell-Operationen innerhalb des PowerShell Universal-Dienstes aus. Probleme mit einem einzelnen Skript oder Endpunkt können die Stabilität des Systems beeinträchtigen.
Bei der Verwendung nicht-integrierter Umgebungen wird ein externer PowerShell-Prozess gestartet. Für APIs und Dashboards kann dieser Prozess langlebig sein, kann aber neu gestartet werden, ohne den Rest des Systems zu beeinträchtigen. Bei Jobs und Terminals wird für jede Instanz des Jobs und Terminals ein neuer Prozess gestartet. Wenn Jobs und Terminals beendet werden, wird der Prozess beendet, und alle von diesem Prozess belegten Ressourcen werden vom System zurückgewonnen.
Zusätzlich kann beim Laden von Modulen in die integrierte Umgebung der Prozessraum mit verschiedenen Versionen von gängigen DLLs verunreinigt werden, die PSU möglicherweise selbst verwendet. Dies kann zu Assembly-Bindungsproblemen führen, die dazu führen können, dass die importierten Module nicht wie erwartet funktionieren.
Die Umgebungen PowerShell 7 und Windows PowerShell 5.1 bieten die größte Kompatibilität mit Modulen, da sie die ausführbare Programmdatei Universal.Agent nutzen, die das Laden von Assemblys steuern kann – im Gegensatz zu pwsh.exe oder powershell.exe.
Problematische Module isolieren
Komplexe PowerShell-Module können Probleme mit PowerShell Universal verursachen. Bestimmte Module sind nicht dafür ausgelegt, in einem langlebigen Prozess wie PowerShell Universal gehostet zu werden. Sie sollten diese Module in vorübergehenden Operationen wie Jobs verwenden.
Zum Beispiel kann dbatools Datenbankverbindungen leaken, wenn es direkt in der integrierten Umgebung von PowerShell Universal verwendet wird. Um dies zu vermeiden, können Sie einen externen Prozess starten, indem Sie einen PowerShell Universal-Job in einer nicht-integrierten Umgebung ausführen. Das Skript wird ausgeführt, der Prozess wird beendet, und die Datenbankverbindung wird automatisch zurückgewonnen.
Nachfolgend finden Sie eine Liste einiger Module, mit denen wir Probleme festgestellt haben.
VMware PowerCLI – Das Verbindungsmanagement ist auf den Prozess begrenzt
Az – Das Verbindungsmanagement ist auf den Prozess begrenzt
Benutzerdefinierte Module nutzen
Das Erstellen benutzerdefinierter Module stellt sicher, dass Sie dieselbe Funktionalität in der gesamten PowerShell Universal-Plattform verwenden können, ohne Code zu duplizieren. Sie können dieselben Funktionen in APIs, Skripten und Dashboards verwenden, ohne die Logik duplizieren zu müssen.
Die Reduzierung der Skriptmenge an all diesen Stellen kann Ihnen helfen, Probleme besser zu testen und zu isolieren, die durch die Integration mit der Plattform oder durch das Modul selbst verursacht werden.
Erwägen Sie außerdem, Funktionen zu erstellen, die komplexe Dashboard-Komponenten umschließen. Dies reduziert die Gesamtkomplexität des Dashboard-Skripts und macht es leicht zu debuggen und zu lesen.
Eine Cache-Lebensdauer festlegen
Wenn Sie Set-PSUCache verwenden, stellen Sie sicher, dass Sie eine Art Lebensdauer für den Cache festlegen. Dies ist besonders wichtig, wenn Sie Daten haben, die nicht ständig verwendet werden und groß sind. Daten, die ohne Lebensdauer in den Cache gelegt werden, werden nie an das System zurückgegeben.
Sie können zum Beispiel die gleitende Ablauffrist verwenden, um Cache-Daten nach einer Stunde ablaufen zu lassen, wenn sie eine Zeit lang nicht verwendet werden.
Größe des persistenten Caches begrenzen oder partitionieren
Der persistente Cache speichert Daten in der PSU-Datenbank. Die Daten werden mit der PSSerializer-Klasse serialisiert, die Teil des PowerShell SDK ist. Dieses Datenformat ist dasselbe, das von PowerShell Remoting verwendet wird. Da es ein XML-Format ist, sind diese Daten deutlich größer als eine binäre Speicherung. Das Speichern vieler Objekte in einem einzelnen zwischengespeicherten Element führt zu schlechter Deserialisierungsleistung, sobald die Daten bestimmte Grenzen erreichen.
Dies kann den PowerShell Universal-Server negativ beeinflussen, da er jedes Mal, wenn die Daten aus dem Cache gelesen werden, eine große Zeichenkette abrufen und dann deserialisieren muss.
Erwägen Sie, kleinere Teilmengen der Objekte auszuwählen, die Sie speichern möchten. Wählen Sie zum Beispiel nur die Eigenschaften aus, die Sie benötigen, anstatt des gesamten Objekts.
Erwägen Sie, Daten in kleineren Partitionen zu speichern. Wenn möglich, segmentieren Sie die Daten in kleinere Blöcke, um das Abrufen eines großen Wertes aus der Datenbank zu vermeiden.
Protokollebene in der Produktion reduzieren
Die Standard-Protokollebenen für PowerShell Universal sind ausführlich. Um die Leistung des Systems zu verbessern, können Sie die Protokollebenen reduzieren. Dies muss an zwei Stellen erfolgen.
Zunächst sollten Sie die Einstellung für die System-Protokollebene reduzieren. Diese finden Sie in appsettings.json. Erwägen Sie, die Ebene von Verbose auf Warning oder Error zu ändern.
Zweitens können Sie die Protokollierungsziele anpassen, um Ebenen zu ändern oder die protokollierten Funktionen zu reduzieren.
APIs
Rückgabe hochkomplexer Objekte vermeiden
Standardmäßig serialisieren API-Endpunkte zurückgegebene Objekte mit ConvertTo-Json zu JSON. Obwohl die Plattform die Tiefe des JSON einschränkt, können hochkomplexe Objekte dazu führen, dass das Cmdlet außer Kontrolle gerät und viel CPU verbraucht. PowerShell Universal versucht, diese Verarbeitung abzubrechen, wenn sie erkannt wird, aber sie verursacht dennoch Probleme mit Ihrer API-Umgebung.
Stellen Sie sicher, dass Sie die Komplexität der Objekte verstehen, die Sie zurückgeben. Wenn Objekte zu komplex sind, erwägen Sie die Verwendung von Select-Object, um eine Teilmenge der zurückgegebenen Daten auszuwählen. Sie können ConvertTo-Json auch selbst aufrufen, um den Parameter -Depth zu steuern.
Ein Beispiel dafür wäre die Rückgabe von Process-Objekten mit Get-Process. Aufgrund der Komplexität des Process-Typs verursacht dies Probleme bei der Serialisierung. Wählen Sie stattdessen nur eine Teilmenge der erforderlichen Eigenschaften aus.
Langlaufende Prozesse in APIs vermeiden
Der HTTP-Thread-Pool ist in seiner Größe begrenzt. Langlaufende Prozesse in APIs können dazu führen, dass der Pool erschöpft wird, was Probleme für den gesamten PowerShell Universal-Server verursachen kann. Wenn Sie planen, eine API zu haben, die mehr als ein paar Sekunden benötigt, erwägen Sie, dass die API einen Job startet. Sie können dann eine zweite API erstellen, um den Status der von der ersten API zurückgegebenen Jobs zu prüfen. So wird sichergestellt, dass die Operation weiterverarbeitet wird, der HTTP-Thread-Pool aber die verfügbare Verbindung zurückgewinnt.
Zum Beispiel könnten Sie die folgenden APIs haben. Der erste Endpunkt startet einen Job und gibt die Job-ID zurück. Der zweite Endpunkt ruft die Pipeline-Ausgabe für den angegebenen Job ab.
Um diese Endpunkte aufzurufen, könnten wir Folgendes mit Invoke-RestMethod tun.
Automatisierung
Unnötige Job-Ausgaben reduzieren
Das Speichern von Job-Ausgaben ist zwar für Auditing-Zwecke nützlich, aber das Speichern aller Job-Ausgaben kann dazu führen, dass Ihr Speicher stark anwächst, was wiederum die Leistung Ihres PowerShell Universal-Systems verlangsamt. Einige Schritte, die Sie unternehmen können, um die Job-Ausgabe im Zaum zu halten, sind folgende.
Pipeline-Ausgabe verwerfen
Wenn Sie die Pipeline-Ausgabe nicht verwenden möchten, können Sie PowerShell Universal anweisen, sie zu verwerfen. Dies reduziert die Menge der gespeicherten Daten und erhöht auch die Leistung Ihrer Jobs, da das System nicht alle Ausgaben zur Speicherung serialisieren muss. Ihre Ausgabestreams werden dennoch im Job-Protokoll angezeigt.
Streams nutzen
Die Verwendung von Debug-, Warning- und Error-Streams kann helfen, zu reduzieren, was standardmäßig im Job angezeigt wird. Durch das Festlegen der Action Preference pro Stream können Sie bestimmte Streams für den regulären Betrieb deaktivieren, sie aber aktivieren, wenn der Job Probleme aufweist.
Wenn Sie zum Beispiel Write-Debug in Ihrem gesamten Skript verwenden, können Sie dies über die Variable $DebugActionPreference deaktivieren, indem Sie sie auf SilentlyContinue setzen. Sollte der Job Probleme aufweisen, könnten Sie sie auf Continue setzen, um die Ausgabe im Protokoll anzuzeigen.
Out-Null nutzen
Out-Null kann potenzielle Pipeline-Ausgaben erfassen und verwerfen. Wenn Sie nicht alle Pipeline-Ausgaben verwerfen möchten, können Sie einen Teil davon mit Out-Null verwerfen. Dies verbessert die Leistung und reduziert die Größe Ihrer Job-Daten.
Unwichtige Jobs aggressiv aufräumen
Einige Jobs, wie ein Trigger, der für Benachrichtigungen verwendet wird, werden möglicherweise nahezu nie überprüft. Erwägen Sie, den Job-Verlauf in diesem Fall sehr niedrig einzustellen.
Apps
Funktionen in Apps verwenden
Beim Erstellen komplexer Abschnitte einer App wird empfohlen, diese in eine Funktion einzuschließen, um diesen komplexen Abschnitt besser zu organisieren und zu isolieren. Stark verschachtelte Dashboards sind schwer zu debuggen und machen es leicht, Syntaxfehler einzuführen, die die gesamte App beeinträchtigen.
Wir empfehlen außerdem, Module zum Speichern Ihrer Funktionen zu verwenden, um die Größe und Komplexität Ihres Kern-App-Skripts weiter zu reduzieren. Zusätzlich können Module dann über Apps hinweg geteilt werden.
Ein Beispiel wäre, die Logik einer Tabelle in eine Funktion einzuschließen und die Funktion dann innerhalb der App zu verwenden.
Nutzung von Jobs in Erwägung ziehen
Jobs sind nützlich, da sie einen externen Prozess starten und zum Auditieren von Interaktionen mit der App verwendet werden können. Da Apps langlebig sind, können bestimmte Operationen und Module unter Last Speicher- oder andere Ressourcenprobleme verursachen. Das Starten von Jobs stellt sicher, dass die Umgebung nach jeder Ausführung zurückgewonnen wird.
Jobs sind sinnvoll für Operationen, die Änderungen vornehmen (z. B. das Erstellen einer VM oder eines Benutzers), aber ihre Leistungsmerkmale funktionieren nicht für jedes Szenario.
Ein Beispiel wäre der Aufruf eines Jobs aus einem Formular.
App-Neustarts planen
Wenn Sie Probleme mit App-Ressourcen haben, können Sie Apps mit einem geplanten Job neu starten, der außerhalb der Geschäftszeiten ausgeführt wird. Sie können die Cmdlets Get-PSUApp, Stop-PSUApp und Start-PSUApp verwenden, um die einzelnen Apps neu zu starten. Diese Technik ist nur gültig, wenn Apps in nicht-integrierten Umgebungen ausgeführt werden.
Beachten Sie die Leistung von -Render bei New-UDTable
Eine Funktion von New-UDTable und New-UDTableColumn ist die Möglichkeit, Spalten so zu rendern, dass sie jede Komponente enthalten, die Sie basierend auf der Datenzeile anzeigen möchten, die Sie der Tabelle bereitstellen. Dies ist üblicherweise nützlich, um das Aussehen und Verhalten anzupassen oder Aktionen für die Daten der Zeile bereitzustellen. Rendering kann zu einem Leistungsproblem werden, wenn es falsch verwendet wird. Das gleichzeitige Rendern vieler Zeilen oder die Verwendung des Render-ScriptBlocks zum Ausführen langlaufender Prozesse verursacht Probleme.
Zu viele Zeilen rendern
Wenn Sie den Parameter -Data von New-UDTable verwenden, wird der ScriptBlock -Render für jedes Element aufgerufen, das Sie an den Data-Parameter übergeben. Wenn Sie hunderte oder tausende Elemente haben, führt dies zu längeren Seitenladezeiten.
Erwägen Sie die Verwendung von -LoadData, um jeweils nur eine Seite von Daten zu laden und anzuzeigen. Dabei wird -Render nur für die angezeigten Elemente und nicht für den gesamten Datensatz aufgerufen.
Langlaufende Renders
Aufgrund der Implementierungsdetails von -Render wird nicht empfohlen, langlaufende Render-Operationen zu verwenden. Wenn Sie erwarten, dass Ihr -Render mehr als ein paar Millisekunden benötigt, erwägen Sie die Verwendung von New-UDDynamic, um das Rendern zurück auf den Server zu verlagern und ein Lade-Skeleton anzuzeigen. Der Server kann die Render-Operation in diesem Fall effizient über den Runspace-Pool planen.
Ein Beispiel dafür wird unten gezeigt.
Das Ergebnis ist eine Tabelle, die sofort geladen wird, aber in den langsam zu rendernden Spalten Lade-Skeletons anzeigt.

Portal
Aufrufe von Drittanbieter-Cmdlets in Widgets vermeiden
Vermeiden Sie es, wenn möglich, Drittanbieter-Cmdlets direkt in Widgets aufzurufen. Jedes Widget hat seinen eigenen Runspace, aber alle Widgets laufen im Prozess des PowerShell Universal-Servers. Das direkte Aufrufen von Cmdlets in Widgets führt dazu, dass .NET-Assemblys in den Server geladen werden. Dies kann zu Konflikten mit anderen Assembly-Ladevorgängen führen. Außerdem wird Speicher von Befehlen, die im Runspace aufgerufen werden, möglicherweise nicht zurückgewonnen.
Die Verwendung von Invoke-PSUScript und das Ausführen eines Skripts in einer externen Umgebung stellt sicher, dass alle Assembly-Ladevorgänge auf einen separaten Prozess beschränkt sind und der gesamte Speicher nach dem Beenden des Prozesses zurückgewonnen wird.
Für eine gute Benutzererfahrung ist es möglicherweise nicht immer sinnvoll, für jede Interaktion auf einer Seite einen Job zu starten. Erwägen Sie die Verwendung der PSUCache-Cmdlets, um Daten im Cache zu setzen und daraus abzurufen, um die Seitenladezeiten zu verbessern.
Nicht alle Module verursachen Probleme, daher ist diese Technik möglicherweise nicht immer erforderlich. Bei Skriptmodulen ist es sehr unwahrscheinlich, dass sie Probleme beim Laden von Assemblys verursachen.
Infrastruktur und Hosting
Dedizierter PowerShell Universal-Server
Erwägen Sie einen dedizierten PowerShell Universal-Server für das Hosting der Plattform. Vermeiden Sie die Installation neben anderen Plattformen, die zu Ressourcenkonflikten mit der Anwendung führen können. PowerShell Universal nutzt Standard-PowerShell-Funktionen wie Module, Ausführungsrichtlinien und Remoting-Konfiguration, und andere Plattformen konfigurieren diese Einstellungen möglicherweise so, dass PSU damit nicht gut funktioniert.
MS SQL oder PostgreSQL für die Produktion verwenden
Vermeiden Sie die Verwendung von SQLite für Produktions-Anwendungsfälle. Es bietet nicht die Möglichkeit zu skalieren, wenn die Arbeitslasten zunehmen. Es verhindert, dass mehrere PSU-Server denselben Datenspeicher verwenden. Es skaliert nicht, wenn Größen von über 2 GB erreicht werden.
Die Migration von einer SQLite-Datenbank zu einer SQL-Datenbank kann fehleranfällig und zeitaufwendig sein. Wenn Sie eine Bereitstellung für den Produktionseinsatz erwägen, empfehlen wir, mit einem zentralisierten SQL-Server zu beginnen.
Geplante Datenbank-Backups durchführen
Wir empfehlen, die Datenbank in regelmäßigen Abständen zu sichern. Während Konfigurationsdaten hauptsächlich im Repository gespeichert werden, enthält die Datenbank Ressourcen wie App-Tokens, lokale Identitäten, Auftragsverlauf und mehr. Regelmäßige Backups helfen außerdem bei der Wiederherstellung nach fehlgeschlagenen Schema-Upgrades und bieten die Möglichkeit, auf frühere Schema-Versionen zurückzusetzen, ohne ein Schema-Downgrade durchführen zu müssen.
Datenbank-Cluster für Redundanz
Wir empfehlen, wenn möglich einen Datenbank-Failover-Cluster zu verwenden. Dies ermöglicht eine schnelle Wiederherstellung und begrenzt die Ausfallzeit des PowerShell Universal-Servers, falls einer der SQL-Server offline gehen sollte.
Lastverteilung
Erwägen Sie den Einsatz eines Load Balancers vor Ihren PowerShell Universal-Instanzen. Benutzer werden an den am wenigsten belasteten Server geleitet oder von Offline-Servern per Failover umgeleitet. Dies bietet außerdem eine bessere Möglichkeit, Upgrades der PowerShell Universal-Anwendung zu staffeln.
PowerShell Universal unterstützt Load Balancer wie F5.
HTTPS verwenden
HTTPS bietet nicht nur Schutz vor Angreifern, die das Netzwerk abhören, sondern auch eine bessere Leistung bei der Verwendung der PowerShell Universal-Cmdlets. Diese nutzen bei der Kommunikation mit der Plattform Funktionen von HTTPS und greifen auf ältere Kommunikationstechnologien zurück, wenn diese nicht verfügbar sind.
Log Shipping
Systemprotokolldateien werden in den Ordner %ProgramData%\PowerShellUniversal\Logs geschrieben und nach 30 Tagen gelöscht. Standardmäßig wird jeden Tag eine neue Protokolldatei geschrieben. Erwägen Sie, Protokolle aus diesem Verzeichnis an Ihr SIEM zu übertragen, wenn Sie Protokolle länger als 30 Tage aufbewahren möchten.
Sie können auch Logging-Ziele konfigurieren, um Protokollmeldungen direkt an ein SIEM zu senden.
Zuletzt aktualisiert
War das hilfreich?