Die Qualität von PowerShell-Skripten mit PSScriptAnalyzer schützen — Regelauswahl und CI-Integration

· · PowerShell, Statische Analyse, CI/CD, GitHub Actions, Qualitätsmanagement, Wartbarkeit, Betriebsoptimierung, Skripterstellung

Sobald die Zahl der PowerShell-Skripte innerhalb eines Unternehmens zu wachsen beginnt, stößt man unweigerlich auf das Problem uneinheitlicher Qualität. Skripte, die so voller Aliase sind, dass man sie nicht lesen kann. Skripte mit Klartext-Passwörtern darin. Skripte, in denen ein falsch geschriebener Variablenname niemandem aufgefallen ist. Das Problem tritt in einer bestimmten Form zutage: sobald derjenige, der es geschrieben hat, gegangen ist, gerät derjenige in Schwierigkeiten, der es lesen muss.

Ein erheblicher Teil dieser Probleme lässt sich mechanisch von einem statischen Analysewerkzeug erkennen. PowerShell besitzt ein offizielles statisches Analysemodul, PSScriptAnalyzer, das eine Sammlung von Skripten mit einem einzigen Befehl analysiert. Der größte Vorteil ist, dass es bereits am ersten Tag Ergebnisse liefert, ohne dass Sie eine einzige Zeile Testcode schreiben.

Dieser Artikel legt die praktischen Schritte zur Einführung von PSScriptAnalyzer bei internen Skriptbeständen dar, in der Reihenfolge „die zuerst zu aktivierenden Regeln“, „stufenweise Einführung bei bestehenden Beständen“ und „automatisierte Prüfung in CI“. Für die Qualitätssicherung durch Tests siehe begleitend „PowerShell mit Pester testen“.

1. Das Wichtigste zuerst

  • PSScriptAnalyzer ist PowerShells offizielles statisches Analysemodul. Invoke-ScriptAnalyzer analysiert Skripte und Module und meldet Regelverstöße.1
  • Befunde besitzen einen Schweregrad. Es gibt drei Stufen — Error / Warning / Information —, und allein Error auf null zu bringen, ist der realistische Ausgangspunkt.1
  • Bündeln Sie die Konfiguration in PSScriptAnalyzerSettings.psd1. Legen Sie Severity, IncludeRules, ExcludeRules und Rules im Repository ab, damit alle gegen dieselbe Basis analysieren.2
  • Individuelle Unterdrückung bedeutet SuppressMessageAttribute plus geschriebenen Grund. Erwägen Sie, bevor Sie eine ganze Regel ausschließen, ob eine eng begrenzte Unterdrückung ausreicht.3
  • Manche Befunde lassen sich mit -Fix automatisch korrigieren. Die Formatierung übernimmt Invoke-Formatter.14
  • Die PowerShell-Erweiterung für VS Code hat PSScriptAnalyzer eingebaut. Warnungen erscheinen bereits während der Bearbeitung und wirken daher früher als CI.5
  • Machen Sie die CI-Fehlbedingung zu „Schweregrad Error plus namentlich genannte kritische Regeln“. Der Schweregrad ist je Regel fest vorgegeben, und die Erkennung von Klartext-Passwörtern (PSAvoidUsingPlainTextForPassword) ist eine Warning. Machen Sie die Bedingung nur von Error abhängig, rutscht dies unmittelbar durch.6
  • Führen Sie es bei bestehenden Beständen stufenweise ein. Die Reihenfolge lautet „Error auf null bringen“ → „nur bei geänderten Dateien streng“ → „den Umfang erweitern“.

2. Erste Schritte — mit einem Befehl beginnen

Install-Module -Name PSScriptAnalyzer -Scope CurrentUser

# Alles unterhalb eines Ordners auf einmal analysieren
Invoke-ScriptAnalyzer -Path 'D:\Scripts' -Recurse |
    Sort-Object Severity, RuleName |
    Format-Table Severity, RuleName, ScriptName, Line, Message -AutoSize

# Die Anzahl je Schweregrad ermitteln (der erste Schritt einer Bestandsaufnahme)
Invoke-ScriptAnalyzer -Path 'D:\Scripts' -Recurse |
    Group-Object Severity | Select-Object Name, Count

Führen Sie zunächst diese beiden aus und verschaffen Sie sich ein zahlenmäßiges Bild vom Zustand Ihrer eigenen Bestände. Es besteht kein Grund zur Beunruhigung, wenn Hunderte von Befunden zurückkommen. So beginnt es an den meisten Standorten.

Die Liste der verfügbaren Regeln und ihre Beschreibungen lassen sich mit Get-ScriptAnalyzerRule einsehen.1

Get-ScriptAnalyzerRule | Select-Object Severity, RuleName, CommonName | Sort-Object Severity
Get-ScriptAnalyzerRule -Name PSAvoidUsingWriteHost | Format-List *   # Beschreibung einer einzelnen Regel

3. Die Befunde, die sich zuerst auszahlen — praktische Prioritäten

Von den Dutzenden verfügbaren Regeln hier diejenigen, die am unmittelbarsten die Qualität interner Skripte betreffen, in Prioritätsreihenfolge.

Regel Was sie erkennt Warum sie wichtig ist
PSAvoidUsingPlainTextForPassword Ein Parameter, der ein Klartext-Passwort entgegennimmt Anmeldeinformationen im Klartext zu halten wird auch bei Audits bemängelt (Schweregrad ist Warning)6
PSAvoidUsingConvertToSecureStringWithPlainText Ein SecureString wird aus Klartext gebildet Dieselbe Grundursache wie oben. Sie zunichtemacht den Sinn der Verschlüsselung
PSUseDeclaredVarsMoreThanAssignments Variablen, die zugewiesen, aber nie verwendet werden Erkennt Tippfehler in Variablennamen. Faktisch Fehlererkennung
PSAvoidUsingInvokeExpression Verwendung von Invoke-Expression Eine Zeichenkette als Code auszuführen ist ein Nährboden für Injection
PSUseShouldProcessForStateChangingFunctions Zustandsändernde Funktionen ohne -WhatIf Erkennt Designs, bei denen gefährliche Vorgänge nicht vorab geprüft werden können
PSAvoidUsingCmdletAliases Aliase wie ls, %, ? Interaktiv praktisch, aber der Lesbarkeit in einem Skript abträglich
PSUseApprovedVerbs Funktionsnamen mit nicht genehmigten Verben Folgt es nicht Konventionen wie Get-/Set-, ist es schwer zu entdecken
PSAvoidGlobalVars Verwendung globaler Variablen Nebenwirkungen werden unlesbar. Man kann auch keine Tests schreiben
PSUseSingularNouns Substantive im Plural (Get-Users und Ähnliches) PowerShells Namenskonvention. Geben Sie Dingen Namen, die andere erraten können

Insbesondere PSUseDeclaredVarsMoreThanAssignments bietet ein sehr gutes Kosten-Nutzen-Verhältnis. Wenn Sie $fileName zuweisen wollten, weiter unten aber $fileNmae referenzieren, greift es dies als „eine Variable, die zugewiesen, aber nie verwendet wurde“ auf, sodass es tatsächlich Fehler fängt, die nur die statische Analyse findet (beachten Sie, dass PowerShell-Variablennamen nicht zwischen Groß- und Kleinschreibung unterscheiden, sodass $fileName und $filename dieselbe Variable sind. Was diese Art der Erkennung erfasst, sind Fälle, in denen sich die Schreibweise selbst unterscheidet).

4. Die Team-Basis in einer Konfigurationsdatei festlegen

Es hat keinen Sinn, wenn jeder gegen eine andere Basis analysiert. Legen Sie PSScriptAnalyzerSettings.psd1 im Repository ab, damit jede Person und CI dieselben Einstellungen verwenden.2

# PSScriptAnalyzerSettings.psd1
@{
    # Das Standard-Regelwerk verwenden
    IncludeDefaultRules = $true

    # In der ersten Phase der Einführung auf Error und Warning beschränken
    Severity = @('Error', 'Warning')

    # Regeln, die wir als Unternehmensrichtlinie vorerst zurückstellen (den Grund in einem Kommentar festhalten)
    ExcludeRules = @(
        'PSAvoidUsingWriteHost'          # wir haben viele interaktive Werkzeuge; vorerst toleriert
        'PSUseSingularNouns'             # wir können nicht alle bestehenden Funktionsnamen auf einmal umbenennen
    )

    # Detaillierte Einstellungen je Regel
    Rules = @{
        PSUseCompatibleSyntax = @{
            # Die Skriptmenge prüfen, die sowohl unter 5.1 als auch 7 laufen muss.
            # TargetVersions akzeptiert nur Versionen, für die die Regel eine
            # Syntaxdefinition besitzt (mit Get-ScriptAnalyzerRule prüfbar). Das Schreiben
            # eines nicht unterstützten Werts verursacht beim Laden der Einstellungen einen
            # Fehler, seien Sie also vorsichtig
            Enable         = $true
            TargetVersions = @('5.1', '7.0')
        }
        PSPlaceOpenBrace = @{
            Enable             = $true
            OnSameLine         = $true
            NewLineAfter       = $true
            IgnoreOneLineBlock = $true
        }
        PSUseConsistentIndentation = @{
            Enable          = $true
            IndentationSize = 4
            Kind            = 'space'
        }
    }
}
Invoke-ScriptAnalyzer -Path . -Recurse -Settings .\PSScriptAnalyzerSettings.psd1

PSUseCompatibleSyntax ist besonders nützlich in Umgebungen, in denen 5.1 und 7 nebeneinander bestehen. Es erkennt vor der Ausführung den Unfall, 7-exklusive Syntax (den ternären Operator, Pipeline-Verkettungsoperatoren usw.) in ein für 5.1 gedachtes Skript zu schreiben. Zur Migrationsstrategie selbst siehe „Die Unterschiede zwischen Windows PowerShell 5.1 und PowerShell 7“.

5. Ausnahmen mit Begründung stehen lassen

Wo Sie einem Befund tatsächlich nicht nachkommen können, unterdrücken Sie ihn nur an dieser einen Stelle, statt die ganze Regel zu deaktivieren.3

function Show-KsBanner {
    # Write-Host wird bewusst verwendet, für eine dekorative Anzeige in einem interaktiven Werkzeug
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute(
        'PSAvoidUsingWriteHost', '',
        Justification = 'Display function for interactive use only; by design it returns no value')]
    [CmdletBinding()]
    param([string] $Title)

    Write-Host ('=' * 60) -ForegroundColor Cyan
    Write-Host $Title -ForegroundColor Cyan
}

Der entscheidende Punkt ist, immer die Justification zu schreiben. Eine Unterdrückung ohne Begründung ist für den nächsten Leser nicht davon zu unterscheiden, dass jemand einfach eine Warnung zum Schweigen gebracht hat. Dies ist eine Art im Code eingebettetes ADR (Entscheidungsprotokoll), und der Gedanke knüpft an „ADRs (Architecture Decision Records) in einem kleinen Team einsetzen“ an.

6. Stufenweise Einführung bei bestehenden Beständen

Stehen Sie vor Hunderten von Warnungen und entscheiden „alles korrigieren und dann einführen“, geraten Sie ins Stocken, bevor Sie angefangen haben. Teilen Sie es in Phasen.

Phase 1: die Blutung stoppen (ein Tag) Nehmen Sie nur Severity = 'Error' in CI auf und bringen Sie das auf null. Vorsicht ist hier geboten, weil der Schweregrad je Regel fest vorgegeben ist und nicht immer mit der Intuition übereinstimmt. Der Schweregrad von PSAvoidUsingPlainTextForPassword ist beispielsweise Warning, sodass es nicht erfasst wird, wenn Sie Error zur einzigen Fehlbedingung machen.6 Für Regeln, bei denen Sie unabhängig vom Schweregrad scheitern lassen möchten, etwa rund um Anmeldeinformationen, fügen Sie sie wie folgt namentlich zur Fehlbedingung hinzu.

# Die CI-Fehlbedingung auf Schweregrad Error + einzeln benannte kritische Regeln setzen
$mustFix = @(
    'PSAvoidUsingPlainTextForPassword'
    'PSAvoidUsingConvertToSecureStringWithPlainText'
    'PSAvoidUsingUsernameAndPasswordParams'
)
$blocking = $issues | Where-Object { $_.Severity -eq 'Error' -or $_.RuleName -in $mustFix }

Phase 2: neuen und geänderten Code schützen (eine Woche) Analysieren Sie nur die Dateien, die sich geändert haben. Die bestehenden Altlasten können bleiben, wie sie sind, und Sie verhindern, dass sich neue Probleme ansammeln.

Führen Sie dies in CI aus, muss der Commit, mit dem Sie vergleichen, bereits abgerufen worden sein. actions/checkout ruft standardmäßig nur einen einzelnen Commit ab, geben Sie also fetch-depth: 0 an oder rufen Sie den Basiszweig explizit ab (ohne das erhalten Sie einen Fehlschlag mit unknown revision).

Ein weiterer Punkt: Legen Sie main nicht fest als Vergleichsziel. git diff A...HEAD bedeutet „die Differenz vom gemeinsamen Vorfahren von A und HEAD“, sodass Sie, wenn Sie bei einem PR gegen develop oder einen Release-Zweig origin/main...HEAD verwenden, Änderungen erfassen, die dieser PR nie berührt hat, und CI bei bereits bestehenden Befunden in nicht betroffenen Dateien fehlschlägt. In GitHub Actions steht der Zielzweig des PR in GITHUB_BASE_REF zur Verfügung, verwenden Sie also diesen.7

Achten Sie außerdem darauf, einen Fehlschlag von git stets zu erkennen. PowerShell macht standardmäßig aus einem von null verschiedenen Exit-Code eines externen Befehls keinen abbrechenden Fehler.8 Dadurch schlägt git diff fehl, wenn der Basis-Ref nicht abgerufen wurde, und erzeugt lediglich eine leere Ausgabe; der nachfolgende Code interpretiert dies als „keine geänderten Dateien“, und CI wird grün, ohne auch nur eine Datei analysiert zu haben. Das ist die gefährlichste Art, wie eine diff-basierte Prüfung brechen kann. Prüfen Sie unmittelbar nach dem Aufruf $LASTEXITCODE und lassen Sie es explizit scheitern (ab PowerShell 7.3 können Sie auch $PSNativeCommandUseErrorActionPreference = $true setzen).8

      - uses: actions/checkout@v4
        with:
          fetch-depth: 0        # für die Differenzbildung ist die Historie erforderlich
# Nur die geänderten ps1/psm1-Dateien analysieren (diff-basierte Prüfung in CI)
# main nicht als Vergleichsziel festlegen. Bei einem PR gegen develop oder einen
# Release-Zweig enthält die Differenz zu main auch nicht betroffene Änderungen,
# und man scheitert an Dateien, die man nie berührt hat.
# Der Zielzweig des PR ist über GITHUB_BASE_REF verfügbar (bei push leer)
$base = if ($env:GITHUB_BASE_REF) { "origin/$($env:GITHUB_BASE_REF)" } else { 'origin/main' }

# Ohne -c core.quotePath=false kommen Pfade mit Nicht-ASCII-Zeichen in Anführungszeichen
# mit oktalen Escapes zurück, wie "scripts/\346...", und rutschen durch die Endungsprüfung
$diff = git -c core.quotePath=false diff --name-only "$base...HEAD"

# Ein Fehlschlag eines nativen Befehls ist standardmäßig kein abbrechender Fehler. Wurde der
# Basis-Ref nicht abgerufen, schlägt git fehl, die Ausgabe wird leer, und es rutscht als
# "keine Änderungen = nichts zu analysieren = bestanden" durch.
# Unmittelbar danach $LASTEXITCODE prüfen und explizit scheitern lassen
if ($LASTEXITCODE -ne 0) {
    throw "git diff failed (exit $LASTEXITCODE). The base branch $base may not have been fetched"
}

$changed = $diff |
    Where-Object { $_ -match '\.ps(m|d)?1$' } |   # .ps1 / .psm1 / .psd1 als Ziel
    Where-Object { Test-Path $_ }

# -Path ist ein Parameter, der einen einzelnen Pfad entgegennimmt, daher schlägt die direkte
# Übergabe eines Arrays bei der Parameterbindung fehl. Eine Datei nach der anderen
# analysieren und die Ergebnisse aggregieren
$issues = foreach ($file in $changed) {
    Invoke-ScriptAnalyzer -Path $file -Settings .\PSScriptAnalyzerSettings.psd1
}

Phase 3: den Umfang erweitern (fortlaufend) Entfernen Sie Einträge aus ExcludeRules einen nach dem anderen und straffen Sie so weit, wie Sie es bereits behandelt haben. Korrigieren Sie bestehende Dateien bei Gelegenheiten für Refactoring und bauen Sie die Altlasten ab.

Befunde, die sich automatisch korrigieren lassen, können mit -Fix in großer Zahl behandelt werden (überprüfen Sie vor der Anwendung immer die Differenz).1 Allein für die Formatierung steht Invoke-Formatter zur Verfügung.4

Invoke-ScriptAnalyzer -Path .\Scripts -Recurse -Fix -Settings .\PSScriptAnalyzerSettings.psd1
git diff        # immer mit eigenen Augen prüfen, was sich geändert hat

7. In CI automatisieren

Mit GitHub Actions sind es auf einem Windows-Runner wenige Zeilen. Der Schlüssel ist, bei Error scheitern zu lassen und Warnings nur anzuzeigen.

name: powershell-lint

on:
  pull_request:
    paths: ['**/*.ps1', '**/*.psm1', '**/*.psd1']

jobs:
  analyze:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0        # erforderlich, wenn Sie auf diff-basierte Analyse umsteigen (Abschnitt 6)

      - name: Install PSScriptAnalyzer
        shell: pwsh
        run: |
          Set-PSRepository -Name PSGallery -InstallationPolicy Trusted
          Install-Module PSScriptAnalyzer -Scope CurrentUser -Force

      - name: Analyze
        shell: pwsh
        run: |
          $issues = Invoke-ScriptAnalyzer -Path . -Recurse `
                    -Settings ./PSScriptAnalyzerSettings.psd1

          # Alles protokollieren (damit die Warnungen ebenfalls sichtbar sind)
          $issues | Sort-Object Severity, ScriptName, Line |
              Format-Table Severity, RuleName, ScriptName, Line, Message -AutoSize |
              Out-String -Width 200 | Write-Host

          # Fehlbedingung = Schweregrad Error + Regeln, die wir bei keinem Schweregrad tolerieren
          $mustFix = @(
              'PSAvoidUsingPlainTextForPassword'
              'PSAvoidUsingConvertToSecureStringWithPlainText'
              'PSAvoidUsingUsernameAndPasswordParams'
          )
          $blocking = @($issues | Where-Object { $_.Severity -eq 'Error' -or $_.RuleName -in $mustFix })
          $warns    = @($issues | Where-Object Severity -eq 'Warning')
          Write-Host "Blocking: $($blocking.Count) / Warning: $($warns.Count)"

          # Sobald die Einführung fortgeschritten ist, auch Warning in die Bedingung aufnehmen
          if ($blocking.Count -gt 0) {
              throw "$($blocking.Count) finding(s) must be fixed"
          }

Legen Sie dies in denselben Workflow wie Ihre Pester-Tests, erhalten Sie den Ablauf „Lint besteht → Tests bestehen → es kann zusammengeführt werden“. Wie man CI/CD für Windows-Anwendungen allgemein aufbaut, wird in „CI/CD für WinForms-/WPF-Apps in der Praxis“ behandelt.

Auch in Umgebungen ohne CI genügt es, Invoke-ScriptAnalyzer monatlich auszuführen und die Ergebnisse in einer CSV zu behalten, um den Zustand Ihrer Bestände ausreichend sichtbar zu machen.

Invoke-ScriptAnalyzer -Path '\\fileserver\scripts' -Recurse |
    Select-Object Severity, RuleName, ScriptName, Line, Message |
    Export-Csv "D:\Inventory\lint_$(Get-Date -f yyyyMM).csv" -Encoding utf8BOM -NoTypeInformation

8. Praktische Faustregeln (Entscheidungstabelle)

Frage Optionen Richtlinie
Einführungsreihenfolge Erst Pester / Erst PSScriptAnalyzer Statische Analyse wirkt bereits am ersten Tag, ohne Tests zu schreiben
Anfänglicher Umfang Alle Regeln / Severity=Error + Anmeldeinformationsregeln namentlich genannt Setzen Sie die Bedingung auf alles, besteht niemand. Beachten Sie, dass der Schweregrad je Regel fest vorgegeben ist6
Ein großer Rückstand bestehender Warnungen Alle korrigieren / Nur bei geänderten Dateien streng Zuerst das Wachstum stoppen, dann bei Gelegenheit reduzieren
Individuelle Ausnahmen ExcludeRules / SuppressMessageAttribute + Justification Die Reichweite minimieren. Immer den Grund hinterlassen3
Konfiguration teilen Jeder seine eigenen Einstellungen / Eine .psd1 im Repository Die Basis zwischen CI und Entwicklern angleichen2
Mischung aus 5.1 und 7 Ausführen und beobachten / PSUseCompatibleSyntax Syntaxebene-Inkompatibilität vor der Ausführung erkennen
Automatische Korrekturen Von Hand / -Fix + Differenz prüfen Nach der Anwendung immer git diff ansehen1
Rückmeldung beim Bearbeiten Nur CI / Die VS-Code-Erweiterung Vor Ort korrigieren zu können, ist die günstigste Option5

9. Zusammenfassung

  • PSScriptAnalyzer ist das offizielle statische Analysemodul. Sie können es einführen, ohne Tests zu schreiben, und es liefert bereits am ersten Tag Ergebnisse.
  • Die realistische Einführung erfolgt stufenweise: zunächst Error auf null bringen, dann nur geänderte Dateien streng prüfen. Da der Schweregrad je Regel fest vorgegeben ist, müssen Regeln, bei denen Sie scheitern lassen möchten — wie Klartext-Passwörter (Warning) — namentlich zur Fehlbedingung hinzugefügt werden.
  • Manche Regeln, wie PSUseDeclaredVarsMoreThanAssignments, fangen echte Fehler in Form von falsch geschriebenen Variablennamen ab.
  • Bündeln Sie die Konfiguration in PSScriptAnalyzerSettings.psd1 und behalten Sie sie im Repository, damit Entwickler und CI eine gemeinsame Basis teilen.
  • Halten Sie Ausnahmen mit einem in SuppressMessageAttribute geschriebenen Grund fest. Eine ganze Regel auszuschließen, ist das letzte Mittel.
  • Lassen Sie CI bei Error scheitern und machen Sie Warnings sichtbar. Legen Sie es in denselben Workflow wie Pester, und das Qualitätstor liegt an einem einzigen Ort.

Beispielcode zum Download

Der in diesem Artikel behandelte Code wird als direkt ausführbares Paket verteilt. Er enthält die Konfigurationsdatei, das CI-Bestehen-/Scheitern-Skript und das GitHub-Actions-Beispiel.

Beispielcode herunterladen (zip)

Die Beispiele dieses Artikels wurden tatsächlich unter PowerShell 7.6 ausgeführt und verifiziert (14 Pester-Tests). Führen Sie das im zip enthaltene Invoke-SampleTests.ps1 aus, um dieselbe Verifikation auf Ihrer eigenen Maschine zu reproduzieren.

# Syntaxprüfung + statische Analyse + Pester-Tests
./Invoke-SampleTests.ps1

Die Konfigurationswerte (Pfade, Servernamen, Mandanten-IDs usw.) sind Beispiele. Führen Sie sie nicht unverändert in einer Produktivumgebung aus — passen Sie sie an Ihre eigene Umgebung an.

Verwandte Artikel

Verwandte Beratungsbereiche

Die KomuraSoft LLC übernimmt die Bestandsaufnahme interner Skript-Ressourcen und die Festlegung von Qualitätsstandards, die Einführung von statischer Analyse und Tests in CI sowie die Verbesserung der Wartbarkeit von Betriebsskripten, die von einer einzelnen Person abhängig geworden sind.

  1. Microsoft Learn, PSScriptAnalyzer module overview. Dazu, dass PSScriptAnalyzer ein statisches Analysewerkzeug für PowerShell-Skripte und -Module ist; zur Analyse über Invoke-ScriptAnalyzer und Parameter wie -Path / -Recurse / -Settings / -Fix / -ExcludeRule; zum Abruf der Regelliste mit Get-ScriptAnalyzerRule; und dazu, dass Diagnoseergebnisse einen Schweregrad (Error / Warning / Information) besitzen.  2 3 4 5 6

  2. Microsoft Learn, PSScriptAnalyzer settings file. Dazu, dass sich Severity, IncludeRules, ExcludeRules, IncludeDefaultRules und Rules in einer Konfigurationsdatei (.psd1) angeben lassen; zur Übergabe einer Konfigurationsdatei mit dem Parameter -Settings; sowie zu detaillierten Einstellungen je Regel (TargetVersions bei PSUseCompatibleSyntax, und Optionen der Formatierungsregeln).  2 3

  3. Microsoft Learn, Suppressing rules in PSScriptAnalyzer. Dazu, dass sich Diagnosen mit System.Diagnostics.CodeAnalysis.SuppressMessageAttribute je Regel und je Ziel unterdrücken lassen, sowie zu den Argumenten RuleName, Target und Justification.  2 3

  4. Microsoft Learn, Invoke-Formatter. Zur Formatierung von Skripttext gemäß Einstellungen, und dazu, dass sich die Formatierungsregeln (Einrückung, Position der öffnenden geschweiften Klammer, Umgang mit Leerraum usw.) in einer Konfigurationsdatei angeben lassen.  2

  5. Microsoft Learn, Using Visual Studio Code for PowerShell development. Dazu, dass die PowerShell-Erweiterung PSScriptAnalyzer verwendet, um während der Bearbeitung Warnungen anzuzeigen, und dass sie Formatierungsfunktionen bereitstellt.  2

  6. Microsoft Learn, AvoidUsingPlainTextForPassword. Dazu, dass Passwörter und Geheimnisse nicht über Klartext-String-Parameter, sondern über SecureString oder PSCredential entgegengenommen werden sollten, sowie dazu, dass der Schweregrad dieser Regel Warning ist und sie stets aktiviert ist. Siehe auch die verwandte Regel AvoidUsingConvertToSecureStringWithPlainText (dazu, dass Geheimnisse nicht geschützt werden, wenn ein SecureString aus Klartext erzeugt wird).  2 3 4

  7. GitHub Docs, Variables reference — Default environment variables. Dazu, dass GITHUB_BASE_REF bei pull_request-Ereignissen den Namen des Zielzweigs des PR enthält (bei anderen Ereignissen leer ist). Zur Bedeutung der Drei-Punkt-Notation (die Differenz vom Merge-Base der beiden benannten Refs) siehe Gits offizielles git diff

  8. Microsoft Learn, about_Preference_Variables — $PSNativeCommandUseErrorActionPreference. Dazu, dass von null verschiedene Exit-Codes nativer Befehle standardmäßig nicht zu abbrechenden Fehlern werden; dazu, dass das Setzen dieser in PowerShell 7.3 eingeführten Präferenz auf $true bewirkt, dass sie gemäß $ErrorActionPreference zu abbrechenden Fehlern werden; sowie zum Abruf des Exit-Codes des letzten externen Befehls über $LASTEXITCODE.  2

Aktuelle Artikel mit denselben Schlagwörtern führen zu verwandten Themen weiter.

Diese Seiten ordnen den Artikel in einen größeren Leistungs- und Entscheidungskontext ein.

Häufige Fragen

Fragen, die in Beratungen zu diesem Artikelthema häufig gestellt werden.

Ich habe PSScriptAnalyzer gegen unsere bestehenden Skripte laufen lassen und Hunderte von Warnungen erhalten. Wo sollte ich anfangen?
Versuchen Sie nicht, alles auf einmal zu korrigieren. Der praktische Ansatz ist, zunächst nur die Befunde mit dem Schweregrad Error anzugehen und diese auf null zu bringen. Beachten Sie, dass der Schweregrad je Regel fest vorgegeben ist — PSAvoidUsingPlainTextForPassword, das Klartext-Passwörter erkennt, ist zum Beispiel eine Warning. Gibt es Regeln, bei denen der Build unabhängig vom Schweregrad fehlschlagen soll, etwa die anmeldeinformationsbezogenen, fügen Sie sie explizit nach Regelname zur CI-Fehlbedingung hinzu. Fügen Sie als Nächstes CI eine Regel hinzu, die nur die Dateien analysiert, die Sie gerade ändern — das verhindert, dass neue Probleme entstehen. Für die bestehenden Warnungen entscheiden Sie, sie vorerst zu tolerieren, schließen Sie sie in der Konfigurationsdatei aus, und reduzieren Sie sie eine nach der anderen im Zuge von Refactorings. Das ist der realistische Weg.
Ich möchte eine Warnung nur an einer bestimmten Stelle unterdrücken. Wie mache ich das?
Fügen Sie dieser Funktion oder diesem Skript ein SuppressMessageAttribute hinzu. Geben Sie den Regelnamen bei System.Diagnostics.CodeAnalysis.SuppressMessageAttribute an und schreiben Sie den Grund in Justification. Das Schreiben des Grundes ist wichtig, denn es ermöglicht demjenigen, der den Code später liest, zu beurteilen, warum dies eine Ausnahme ist. Möchten Sie eine Regel vollständig deaktivieren, tragen Sie sie in ExcludeRules in der Konfigurationsdatei ein, das hat jedoch eine deutlich größere Reichweite, überlegen Sie also zuerst, ob eine gezielte Unterdrückung ausreicht.
Bei der Verwendung von Write-Host erhalte ich eine Warnung. Darf ich es nicht verwenden?
PSAvoidUsingWriteHost ist eine Beobachtung auf Designebene: Verwenden Sie Write-Host dort, wo Sie eigentlich einen Wert zurückgeben sollten, lässt sich die Ausgabe nicht erfassen. Ist der Zweck eine dekorative Anzeige in einem interaktiven Werkzeug, ist es durchaus vertretbar, dies mit einem SuppressMessageAttribute und einem geschriebenen Grund zu unterdrücken. Verwendet ein unbeaufsichtigtes Skript andererseits ausschließlich Write-Host, lohnt es sich, der Warnung nachzugehen. Folgen Sie Regeln nicht mechanisch — verstehen Sie die Absicht hinter dem Befund und entscheiden Sie.
Was sollten wir zuerst einführen, Pester oder PSScriptAnalyzer?
PSScriptAnalyzer zuerst einzuführen bringt mehr Ertrag für den Aufwand. Sie können jedes Skript mit einem einzigen Befehl analysieren, ohne eine einzige Zeile Testcode zu schreiben, und sehen bereits am ersten Tag Ergebnisse. Pester braucht länger, um in Gang zu kommen, da Sie die Tests schreiben müssen, aber Tests sind das Einzige, was die Korrektheit Ihrer Logik schützt. Als Reihenfolge empfehlen wir, zunächst statische Analyse in CI einzubauen, um die offensichtlichen Probleme zu stoppen, und dann Pester-Tests hinzuzufügen, beginnend mit der Verarbeitung, deren Bruch Sie am meisten bereuen würden.
Lohnt sich die Einführung auch in einem kleinen Team ohne CI-Server?
Ja. Auch ohne Git oder CI kommt allein das Ausführen von Invoke-ScriptAnalyzer -Path . -Recurse gegen die Skriptsammlung in Ihrem freigegebenen Ordner einer Bestandsaufnahme gleich. Die Ergebnisse als CSV zu exportieren und monatlich zu prüfen, wie viele Befunde mit Schweregrad Error vorliegen, genügt bereits, um den Zustand Ihrer Bestände sichtbar zu machen. Zusätzlich hat die PowerShell-Erweiterung für VS Code PSScriptAnalyzer eingebaut, sodass Warnungen bereits während der Bearbeitung erscheinen. Allein das verbessert die Schreibgewohnheiten kontinuierlich.

Autorenprofil

Profilseite des Artikelautors.

Go Komura

Geschäftsführer von KomuraSoft LLC

Spezialisiert auf Windows-Softwareentwicklung, technische Beratung und Fehleranalyse, insbesondere bei bestehenden Systemen und schwer reproduzierbaren Störungen.

Zurück zum Blog