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.
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.
Haben Sie Ideen für benutzerdefinierte Regeln für PowerShell Universal? Lassen Sie es uns wissen.
Bereit zum Bauen? PowerShell Universal herunterladen.

Adam Driscoll