Skip to the main content.

ScriptRunner Blog

5 PowerShell Best Practices – so arbeitest du noch effizienter mit PowerShell

Inhaltsverzeichnis

 

 

Post Featured Image

Die Effektivität jedes Werkzeugs hängt von den angewandten Methoden ab – das trifft auch auf die PowerShell zu. Dieser Artikel stellt fünf weitere Best Practices für den Admin-Alltag vor. 

Ein sehr gutes Skript zeichnet sich nicht nur durch das Erreichen eines gewünschten Ergebnisses aus, sondern auch durch seine Zuverlässigkeit, Portabilität und Nachvollziehbarkeit. Dieser Artikel ist die Fortsetzung von 'Best Practices – vom lauffähigen zum professionellen Code' und wirft einen Blick auf fünf Best Practices, die man beachten sollte, um das Beste aus PowerShell herauszuholen und Skripte zu schreiben, die nicht nur funktionieren, sondern auch in verschiedenen Szenarien bestehen und angepasst werden können.

 

Idempotenz: Stelle sicher, dass deine Skripte wiederholt sicher ausgeführt werden 

Gerade bei der Automatisierung repetitiver Aufgaben ist Konsistenz entscheidend: Hier spielt das Prinzip der Idempotenz eine wichtige Rolle. Ein idempotentes Skript oder eine idempotente Funktion sorgt dafür, dass du sie mehrmals ausführen kannst und dabei jedes Mal dasselbe Ergebnis erhältst, ohne ungewünschte Nebeneffekte zu erzeugen.

Stell dir ein Skript vor, das eine Datei auf einem Server erstellen soll. Ein idempotentes Skript würde zunächst prüfen, ob die Datei bereits existiert. Wenn ja, würde es nichts tun oder die Datei aktualisieren. Es würde aber sicherlich keine zweite Datei mit demselben Namen erstellen oder eine Fehlermeldung ausgeben.

Wenn du Idempotenz in PowerShell beachtest, bedeutet das:

  • Überprüfe den aktuellen Zustand, bevor du Änderungen vornimmst.
  • Vermeide Aktionen, die bei wiederholter Ausführung unterschiedliche Ergebnisse oder unbeabsichtigte Nebenwirkungen haben könnten.
  • Nutze Cmdlets, die idempotent sind, wie z.B. Set-* anstelle von Add-*, wenn du sicherstellen möchtest, dass eine Ressource in einem bestimmten Zustand ist.

Indem du sicherstellst, dass deine Skripte idempotent sind, minimierst du nicht nur Fehler, sondern ermöglichst auch sicherere Automatisierungsszenarien, bei denen Skripte möglicherweise regelmäßig oder automatisch ausgeführt werden.

Als Beispiel möchtest du sicherstellen, dass ein Verzeichnis existiert, bevor du in diesem eine Datei anlegst:


$directoryPath = "C:\BeispielVerzeichnis"
if (-not (Test-Path $directoryPath)) {
    New-Item -Path $directoryPath -ItemType Directory
} else {
    Write-Output "Das Verzeichnis existiert bereits."
}

Indem du diese Überprüfungen in deine PowerShell-Skripte integrierst, sorgst du für eine konsistente Ausführung, unabhängig davon, wie oft das Skript ausgeführt wird.

 

Error Handling: Nutze konsequent Try-Catch-Finally 

Fehlerbehandlung nimmt eine zentrale Rolle in jedem Skript oder Programm ein. In PowerShell wird dir mit dem Try-Catch-Finally-Konstrukt eine robuste Methode an die Hand gegeben, um auf Fehler zu reagieren und zu gewährleisten, dass Aufräumarbeiten konsequent durchgeführt werden.

  • Try: In diesem Block wird der Code untergebracht, der potenziell Fehler verursachen könnte. Tritt im Try Block ein Fehler auf und hat dieser einen abbrechenden Charakter (z.B. durch den Parameter ErrorAction Stop), wird die Ausführung direkt an den dazugehörigen Catch Block weitergegeben.
  • Catch: Dieser Teil wird aktiv, sobald im Try Block ein Fehler auftritt. Hier hast du die Möglichkeit, den Fehler zu behandeln – beispielsweise durch Logging oder Benachrichtigungen.
  • Finally: Dieser Abschnitt wird stets ausgeführt, unabhängig vom Ergebnis des Try Blocks. Er dient Aufräumarbeiten oder anderen finalen Aktionen.

Ein gängiges Vorgehen ist das Anlegen von temporären Dateien während der Ausführung, welche anschließend wieder entfernt werden sollten, wie im Folgenden dargestellt:



$tempFile = "C:\Temp\meineTempDatei.txt"

try {
    # Temporäre Datei erstellen
    New-Item -Path $tempFile -ItemType File -Force

    # Dinge mit der temporären Datei machen
    # ...
}
catch {
    Write-Output "Es gab einen Fehler: $_"
}
finally {
    # Sicherstellen, dass die temporäre Datei am Ende gelöscht wird
    if (Test-Path $tempFile) {
        Remove-Item -Path $tempFile -Force
        Write-Output "Temporäre Datei wurde entfernt."
    }
}

 

Durch die Integration dieses Fehlerbehandlungs-Konstrukts in deine Skripte wird sichergestellt, dass du auf potentielle Fehler vorbereitet bist und in der Lage bist, diese adäquat zu adressieren.

 

Minimiere Abhängigkeiten: Schreibe portable Skripte

Oftmals ist es notwendig, dass Skripte auf unterschiedlichen Systemen ausgeführt werden können. Ein Hauptziel sollte es daher sein, Skripte so portabel wie möglich zu gestalten. Das bedeutet, Abhängigkeiten zu minimieren und sicherzustellen, dass das Skript unter verschiedenen Bedingungen konsistent funktioniert. Das Minimieren von Abhängigkeiten verhindert, dass Skripte in bestimmten Umgebungen nicht funktionieren, weil eine bestimmte Ressource oder ein spezifisches Tool fehlt. Je weniger spezifische Anforderungen an ein Skript gestellt werden, desto wahrscheinlicher ist es, dass es auf einer Vielzahl von Systemen problemlos funktioniert.

Ein häufiges Szenario in PowerShell ist die Verwendung von externen Tools oder Programmen. Oftmals bietet PowerShell jedoch eingebaute Cmdlets, die denselben Zweck erfüllen können, und die Verwendung dieser Cmdlets kann helfen, Abhängigkeiten zu reduzieren. Statt auf externe Programme wie systeminfo.exe zurückzugreifen, die auf einigen Systemen fehlen könnten oder unterschiedliche Ausgaben liefern, kann man auf integrierte PowerShell-Cmdlets setzen.


# Nicht empfohlen: Verwendung eines externen Programms
$output = & "systeminfo.exe"

# Empfohlen: Verwendung eines eingebauten PowerShell-Cmdlets
$systemInfo = Get-CimInstance -ClassName Win32_OperatingSystem

 

  • Im ersten Beispiel wird das externe Programm systeminfo.exe verwendet, um Informationen über das Betriebssystem zu sammeln. Während dieses Programm auf vielen Windows-Systemen vorhanden ist, könnte seine Ausgabe je nach Version oder Konfiguration variieren.
  • Das zweite Beispiel verwendet das Cmdlet Get-CimInstance mit der Klasse Win32_OperatingSystem, um detaillierte Informationen über das Betriebssystem zu erhalten. Da dieses Cmdlet direkt in PowerShell integriert ist und standardisierte CIM-Informationen abruft, ist die Ausgabe konsistenter und das Skript hat weniger externe Abhängigkeiten.

 

Zusätzliche Tipps:

  • Vermeide feste Pfade: Anstatt feste Pfade in deinem Skript zu verwenden, solltest du überlegen, relative Pfade oder Parameter zu verwenden.
  • Prüfe auf Vorhandensein von Ressourcen: Bevor du auf eine bestimmte Ressource zugreifst, überprüfe, ob sie tatsächlich vorhanden ist (z. B. mit Test-Path).
  • Dokumentiere Abhängigkeiten: Wenn dein Skript doch externe Tools oder spezifische Ressourcen benötigt, dokumentiere diese Abhängigkeiten am Anfang deines Skripts.

Indem Abhängigkeiten in PowerShell-Skripten minimiert werden, wird sichergestellt, dass sie auf einer größeren Anzahl von Systemen und in verschiedenen Umgebungen konsistent und zuverlässig funktionieren.

 

Interaktive Abfragen vermeiden: Behalte die Automatisierung im Fokus! 

Interaktive Eingabeaufforderungen können nützlich sein, wenn du direkt mit ihnen arbeitest. Doch in automatisierten IT-Umgebungen können sie zum Problem werden. Wenn während eines laufenden Skripts eine Abfrage erscheint, wird menschliche Interaktion nötig. Das unterbricht den Automatisierungsfluss und erhöht das Fehlerpotential.

Stell dir ein Szenario vor, in dem ein Skript Informationen eines Servers abfragen soll. Anstatt dich zur Laufzeit nach dem Servernamen zu fragen, sollte das Skript ihn als Parameter annehmen.


# Nicht empfohlen: Servernamen interaktiv abfragen
$serverName = Read-Host "Bitte gib den Servernamen ein"
$serverInfo = Get-ADComputer -Identity $serverName

# Empfohlen: Servernamen als Parameter annehmen
param($serverName)
$serverInfo = Get-ADComputer -Identity $serverName

 

  • Im ersten Beispiel wird Read-Host genutzt, um dich zur Laufzeit nach dem Servernamen zu fragen. Für automatisierte Umgebungen ist das nicht ideal, da es dich in den Prozess einbezieht.
  • Im zweiten Beispiel nimmt das Skript den Servernamen als Parameter. So kann das Skript automatisch für verschiedene Servernamen laufen, ohne dass du eingreifen musst.

Parameter zu nutzen fördert nicht nur die Automatisierung, sondern auch die Wiederverwendbarkeit des Skripts in unterschiedlichen Kontexten.

 

Konsistente Logging-Praktiken: Behalte immer den Überblick 

In komplexen IT-Umgebungen ist es unerlässlich, genaue Aufzeichnungen über die Aktionen und Ergebnisse von Skripten und Automatisierungstools zu haben. Ein konsistentes und detailliertes Logging ermöglicht es Administratoren, Probleme schnell zu identifizieren, zu diagnostizieren und zu beheben. Darüber hinaus bieten gute Logs eine Möglichkeit, die Ausführungshistorie zu verfolgen, was bei der Fehlerbehebung oder Analyse von Vorfällen sehr nützlich sein kann.

Das Cmdlet Write-Host gibt Informationen direkt auf der Konsole aus und sollte in Produktionsumgebungen vermieden werden. Eine besser strukturierte und produktionsgeeignete Methode wäre die Verwendung einer eigenen Logging-Funktion wie Write-Log


# Definieren der Write-Log Funktion
function Write-Log {
    param     (
      [Parameter(Mandatory=$true)]
      [string]$Message,
      [Parameter(Mandatory=$false)]
      [string]$LogPath = "C:\Logs\MyScript.log"
    )
    Add-Content -Path $LogPath -Value "$(Get-Date) - $Message"
}

# Nicht empfohlen: Verwenden von Write-Host für direkte Konsolenausgabe
Write-Host "Diese Aktion wurde abgeschlossen."

# Empfohlen: Verwenden von Write-Log für konsistente Logging-Praktiken
Write-Log -Message "Diese Aktion wurde abgeschlossen."

 

  • Im nicht empfohlenen Beispiel verwendet das Skript Write-Host, um eine Nachricht direkt auf der Konsole auszugeben. Während dies in Entwicklungsumgebungen nützlich sein kann, ist es nicht ideal für Produktionsumgebungen, da solche Nachrichten nicht protokolliert werden und bei der späteren Analyse nicht verfügbar sind.
  • Das empfohlene Beispiel definiert eine Write-Log Funktion, die jede Nachricht mit einem Zeitstempel in einer Log-Datei speichert. Dies gewährleistet, dass alle Aktivitäten und Ergebnisse für spätere Überprüfung und Analyse festgehalten werden.

Noch ein paar Tipps:


  • Log-Rotation: Überlege, wie du die Größe von Log-Dateien im Griff behältst, damit sie nicht zu groß werden und übermäßig Ressourcen verbrauchen.
  • Zentrales Logging: Vielleicht möchtest du zentrale Logging-Tools wie den ELK Stack oder Graylog nutzen, um Logs zentral zu sammeln und auszuwerten.
  • Nicht alles neu machen: Es gibt bereits viele Module, die das Logging in PowerShell erleichtern. Meine Empfehlung ist hier das Modul PSFramework von Friedrich Weinmann (hier auf GitHub). 

 

Fazit

PowerShell bietet uns zahlreiche Möglichkeiten zur Automatisierung und Verwaltung von IT-Umgebungen. Doch wie bei jedem Werkzeug liegt der Schlüssel zum Erfolg in der richtigen Anwendung. Jeder, der sich mit PowerShell beschäftigt, sollte diese Best Practices berücksichtigen, um robuste, zuverlässige und nachhaltige Lösungen zu schaffen.

 

Good2know

Dein ultimatives PowerShell Cheat Sheet

Entfalte das volle Potential von PowerShell mit unserem praktischen Poster. Egal ob Anfänger oder erfahrener Profi, dieses Cheat Sheet ist darauf ausgelegt, dein Anlaufpunkt für die wichtigsten und am häufigsten verwendeten Cmdlets zu sein.

Das Poster gibt es zum Download und in Papierform.

PowerShell Poster 2023

 

Hol dir hier dein Poster!

 

 

 

Weiterführende Links

Zusammenhängende Posts

Über den Autor: