Som en del af udgivelsen af PowerShell Universal v5 tilføjer vi nogle tilpassede PSScriptAnalyzer-regler til platformen, så det bliver nemmere at opdage problemer, når du bygger scripts. I det her indlæg gennemgår vi, hvordan du opretter tilpassede PSScriptAnalyzer-regler.
PSScriptAnalyzer
PSScriptAnalyzer er et værktøj til statisk kodeanalyse af PowerShell-scripts. Det kontrollerer kodens kvalitet ud fra et sæt regler. De indbyggede regler tjekker alt fra brug af aliaser og mellemrum i slutningen af linjer til $null-kontroller og mere. Når du bruger editorer som VS Code, kører PSScriptAnalyzer i baggrunden og giver feedback på dine scripts i realtid.
Internt kører PowerShell-udvidelsen Invoke-ScriptAnalyzer for at give den feedback. Du kan selv køre kommandoen for at se resultatet af analysen. Hvis du kun angiver stien, køres alle standardreglerne.
Invoke-ScriptAnalyzer -Path .\MyScript.ps1
Du kan også udelade regler med parametre på cmdlet’en.
Invoke-ScriptAnalyzer -Path .\MyScript.ps1 -ExcludeRule PSAvoidUsingCmdletAliases
Hvis du vil tilpasse PSScriptAnalyzers adfærd uden at ændre kommandolinjen, kan du også bruge en konfigurationsfil. Filen dækker de samme muligheder som de forskellige parametre på Invoke-ScriptAnalyzer.
# PSScriptAnalyzerSettings.psd1
@{
Severity=@('Error','Warning')
ExcludeRules=@('PSAvoidUsingCmdletAliases', 'PSAvoidUsingWriteHost')
}
Du bruger indstillingsfiler til scriptanalyzer ved at sende parameteren -Settings til Invoke-ScriptAnalyzer.
Invoke-ScriptAnalyzer -Path MyScript.ps1 -Settings PSScriptAnalyzerSettings.psd1
Du kan også bruge indstillingsfilen med VS Code ved at sætte PowerShell > Script Analysis: Settings Path til PSScriptAnalyzerSettings.psd1.
Tilpassede regler
Tilpassede regler defineres med PowerShell-moduler. De kan tage imod en liste over tokens eller et abstrakt syntakstræ (AST) og returnere diagnoseposter. I PowerShell Universal har vi for eksempel en regel, der kontrollerer brugen af indbyggede variabler som $PSUEnvironment eller $UniversalClient. Hvis de variabler tildeles, kan det give udefineret adfærd, så vi vil have, at brugerne ved det med det samme, når de prøver at overskrive dem.
Første trin er at oprette en ny .psm1-modulfil og definere en funktion, der analyserer scriptet. I eksemplet har vi valgt Universal.Rules.psm1 som filnavn og defineret funktionen Measure-PSUBuiltInVariables. Kommentarbaseret hjælp er påkrævet, og der er nogle særlige detaljer ved funktionen, du skal lægge mærke til.
For det første skal du medtage attributten OutputType for at angive den type objekt, funktionen returnerer. I det her tilfælde returnerer den et array af objekter af typen Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord. Du skal også tage imod et ScriptBlockAst-objekt som parameter. Objektet repræsenterer scriptblokken i det script, der analyseres.
<#
.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
)
Selve funktionen står for det tunge analysearbejde af scriptblokken. I vores eksempel undersøger vi AST’en for at finde tildelinger. Finder vi tildelinger, kontrollerer vi, om venstre side af tildelingen er en variabel. Er det tilfældet, bruger vi en statisk metode til at afgøre, om det er en af de indbyggede variabler i PowerShell Universal.
Hvis betingelserne er opfyldt, opretter vi nye DiagnosticRecord-objekter og udfylder de nødvendige oplysninger. $_.Extent er vigtig, fordi den fortæller editorer som VS Code eller Monaco, hvilken del af scriptet der skal fremhæves med advarslen eller fejlen.
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)
}
}
Til sidst sørger vi for at eksportere funktionen fra modulet.
Export-ModuleMember -Function Measure-PSUBuiltInVariables
I PowerShell Universal bruger vi Invoke-ScriptAnalyzer til at køre kodeanalysen. Mens du skriver i editoren, kaldes funktionen for at give feedback i realtid. For at bruge vores tilpassede regel sender vi parameteren -CustomRulePath til Invoke-ScriptAnalyzer.
Invoke-ScriptAnalyzer -ScriptDefinition $code -CustomRulePath $InstallDir\Modules\Universal.Rules\Universal.Rules.psm1 -IncludeDefaultRules
Derefter behandler vi outputtet fra PSScriptAnalyzer for at give feedback til brugeren.
Har du idéer til tilpassede regler til PowerShell Universal? Sig endelig til.
Klar til at bygge? Hent PowerShell Universal.

Adam Driscoll