MAIN MENU
Devolutions Blog

Ankündigungen, Aktualisierungen und Einsichten von Devolutions

PowerShell Universal custom PSScriptAnalyzer rules illustration for the Devolutions blog.

Benutzerdefinierte PSScriptAnalyzer-Regeln für PowerShell Universal erstellen

Dieser Beitrag führt durch die Standardregeln von PSScriptAnalyzer, Einstellungsdateien und eine benutzerdefinierte PowerShell Universal-Regel, die Zuweisungen an integrierte Variablen mit ScriptBlockAst und DiagnosticRecord erkennt.

Im Rahmen der PowerShell Universal v5-Version fügen wir der Plattform einige benutzerdefinierte PSScriptAnalyzer-Regeln hinzu, damit Probleme beim Erstellen von Skripten leichter auffallen. In diesem Beitrag zeigen wir, wie Sie benutzerdefinierte PSScriptAnalyzer-Regeln erstellen.

PSScriptAnalyzer

PSScriptAnalyzer ist ein Tool zur statischen Codeanalyse für PowerShell-Skripte. Es prüft die Codequalität anhand eines Regelwerks. Die integrierten Regeln decken unter anderem Aliasverwendung, Leerzeichen am Zeilenende, $null-Prüfungen und mehr ab. In Editoren wie VS Code läuft PSScriptAnalyzer im Hintergrund und liefert Echtzeit-Feedback zu Ihren Skripten.

Intern führt die PowerShell-Erweiterung Invoke-ScriptAnalyzer aus, um dieses Feedback zu liefern. Sie können diesen Befehl selbst ausführen, um die Analyseergebnisse zu sehen. Ein Aufruf nur mit dem Pfad wendet alle Standardregeln an.

Invoke-ScriptAnalyzer -Path .\MyScript.ps1

Sie können Regeln auch über Parameter des Cmdlets ausschließen.

Invoke-ScriptAnalyzer -Path .\MyScript.ps1 -ExcludeRule PSAvoidUsingCmdletAliases

Um das Verhalten von PSScriptAnalyzer ohne Änderung der Befehlszeile anzupassen, können Sie auch eine Konfigurationsdatei verwenden. Diese Datei deckt dieselben Optionen ab wie die verschiedenen Parameter von Invoke-ScriptAnalyzer.

# PSScriptAnalyzerSettings.psd1
@{
    Severity=@('Error','Warning')
    ExcludeRules=@('PSAvoidUsingCmdletAliases', 'PSAvoidUsingWriteHost')
}

Sie können Einstellungsdateien des Script Analyzers verwenden, indem Sie den Parameter -Settings an Invoke-ScriptAnalyzer übergeben.

Invoke-ScriptAnalyzer -Path MyScript.ps1 -Settings PSScriptAnalyzerSettings.psd1

Sie können diese Einstellungsdatei auch in VS Code nutzen, indem Sie PowerShell > Script Analysis: Settings Path auf PSScriptAnalyzerSettings.psd1 setzen.

VS Code PowerShell Script Analysis Settings Path pointing at PSScriptAnalyzerSettings.psd1.
PSScriptAnalyzer-Einstellungspfad in VS Code

Benutzerdefinierte Regeln

Benutzerdefinierte Regeln werden über PowerShell-Module definiert. Sie können eine Liste von Token oder einen abstrakten Syntaxbaum (AST) entgegennehmen und Diagnostic Records zurückgeben. In PowerShell Universal haben wir zum Beispiel eine Regel, die die Verwendung integrierter Variablen wie $PSUEnvironment oder $UniversalClient prüft. Das Zuweisen dieser Variablen kann undefiniertes Verhalten verursachen, daher sollen Benutzer sofort wissen, wenn sie versuchen, sie zu überschreiben.

Der erste Schritt besteht darin, eine neue .psm1-Moduldatei zu erstellen und eine Funktion zu definieren, die das Skript analysiert. In diesem Beispiel haben wir Universal.Rules.psm1 als Dateinamen gewählt und die Funktion Measure-PSUBuiltInVariables definiert. Kommentarbasierte Hilfe ist erforderlich, und einige besondere Details dieser Funktion sollten beachtet werden.

Zuerst müssen Sie das Attribut OutputType angeben, um den Objekttyp festzulegen, den die Funktion zurückgibt. In diesem Fall gibt sie ein Array von Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord-Objekten zurück. Sie müssen außerdem ein ScriptBlockAst-Objekt als Parameter akzeptieren. Dieses Objekt steht für den Skriptblock des analysierten Skripts.

<#
.SYNOPSIS
    Locates built-in PowerShell Universal variables
.DESCRIPTION
    Checks to make sure that built-in PowerShell Universal variables are not being used in the script.
.EXAMPLE
    Measure-PSUBuiltInVariables -ScriptBlockAst $ScriptBlockAst
.INPUTS
    [System.Management.Automation.Language.ScriptBlockAst]
.OUTPUTS
    [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
.NOTES
    None
#>
function Measure-PSUBuiltInVariables {
    [CmdletBinding()]
    [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
    Param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.Management.Automation.Language.ScriptBlockAst]
        $ScriptBlockAst
    )

Der Rumpf dieser Funktion übernimmt die eigentliche Analyse des Skriptblocks. In unserem Beispiel durchsuchen wir den AST nach Zuweisungsanweisungen. Wenn wir Zuweisungsanweisungen finden, prüfen wir anschließend, ob die linke Seite der Zuweisung eine Variable ist. Falls ja, verwenden wir dann eine statische Methode, um zu prüfen, ob es sich um eine der integrierten Variablen in PowerShell Universal handelt.

Wenn die Bedingungen erfüllt sind, erstellen wir neue DiagnosticRecord-Objekte und füllen die erforderlichen Informationen. $_.Extent ist wichtig, weil es Editoren wie VS Code oder Monaco mitteilt, welchen Teil des Skripts sie mit der Warnung oder dem Fehler hervorheben sollen.

    Process {
        $results = @()

        try {
            #region Define predicates to find ASTs.
            [ScriptBlock]$predicate1 = {
                param ([System.Management.Automation.Language.Ast]$Ast)

                if ($Ast -is [System.Management.Automation.Language.AssignmentStatementAst]) {
                    if ($Ast.Left -is [System.Management.Automation.Language.VariableExpressionAst]) {
                        return [PowerShellUniversal.BuiltInVariables]::IsBuiltInVariable($Ast.Left.VariablePath.UserPath)
                    }
                }

                return $false
            }

            #endregion

            #region Finds ASTs that match the predicate.

            [System.Management.Automation.Language.Ast[]]$methodAst = $ScriptBlockAst.FindAll($predicate1, $true)

            $methodAst | ForEach-Object {
                $result = New-Object `
                    -Typename "Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord" `
                    -ArgumentList "Overriding built in PowerShell Universal variables can cause undefined behavior.", $_.Extent, $PSCmdlet.MyInvocation.InvocationName, Warning, $null
                $results += $result
            }

            return $results

            #endregion
        }
        catch {
            $PSCmdlet.ThrowTerminatingError($PSItem)
        }
    }

Zum Schluss exportieren wir die Funktion aus unserem Modul.

Export-ModuleMember -Function Measure-PSUBuiltInVariables

In PowerShell Universal verwenden wir Invoke-ScriptAnalyzer für die Codeanalyse. Während Sie im Editor tippen, wird diese Funktion aufgerufen, um Echtzeit-Feedback zu liefern. Um unsere benutzerdefinierte Regel zu nutzen, übergeben wir den Parameter -CustomRulePath an Invoke-ScriptAnalyzer.

Invoke-ScriptAnalyzer -ScriptDefinition $code -CustomRulePath $InstallDir\Modules\Universal.Rules\Universal.Rules.psm1 -IncludeDefaultRules

Anschließend verarbeiten wir die Ausgabe von PSScriptAnalyzer, um dem Benutzer Feedback zu geben.

PowerShell Universal editor warning that overriding built-in variables causes undefined behavior.
Benutzerdefinierte PSScriptAnalyzer-Regel im PowerShell Universal-Editor

Haben Sie Ideen für benutzerdefinierte Regeln für PowerShell Universal? Lassen Sie es uns wissen.

Bereit zum Bauen? PowerShell Universal herunterladen.