MAIN MENU
Blog di Devolutions

Annunci, aggiornamenti e approfondimenti di Devolutions.

PowerShell Universal custom PSScriptAnalyzer rules illustration for the Devolutions blog.

Creare regole PSScriptAnalyzer personalizzate per PowerShell Universal

Questa guida illustra le regole predefinite di PSScriptAnalyzer, i file di impostazioni e una regola personalizzata di PowerShell Universal che segnala le assegnazioni alle variabili integrate con ScriptBlockAst e DiagnosticRecord.

Nell’ambito del rilascio di PowerShell Universal v5, stiamo aggiungendo alcune regole PSScriptAnalyzer personalizzate alla piattaforma per individuare più facilmente i problemi durante la creazione degli script. In questo articolo vedremo come creare regole PSScriptAnalyzer personalizzate.

PSScriptAnalyzer

PSScriptAnalyzer è uno strumento di analisi statica del codice per gli script PowerShell. Controlla la qualità del codice in base a un insieme di regole. Le regole integrate verificano ogni tipo di aspetto, come l’uso degli alias, gli spazi a fine riga, i controlli $null e altro ancora. Negli editor come VS Code, PSScriptAnalyzer viene eseguito in background per fornire un feedback in tempo reale sui propri script.

Internamente, l’estensione PowerShell esegue Invoke-ScriptAnalyzer per fornire questo feedback. Può eseguire questo comando da solo per vedere i risultati dell’analisi. Eseguirlo solo con il percorso applica tutte le regole predefinite.

Invoke-ScriptAnalyzer -Path .\MyScript.ps1

Può anche escludere regole usando i parametri del cmdlet.

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

Per personalizzare il comportamento di PSScriptAnalyzer senza modificare la riga di comando, può anche usare un file di configurazione. Questo file copre le stesse opzioni dei diversi parametri di Invoke-ScriptAnalyzer.

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

Può usare i file di impostazioni dello script analyzer passando il parametro -Settings a Invoke-ScriptAnalyzer.

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

Può anche usare questo file di impostazioni con VS Code impostando PowerShell > Script Analysis: Settings Path su PSScriptAnalyzerSettings.psd1.

VS Code PowerShell Script Analysis Settings Path pointing at PSScriptAnalyzerSettings.psd1.
Percorso delle impostazioni PSScriptAnalyzer in VS Code

Regole personalizzate

Le regole personalizzate sono definite tramite moduli PowerShell. Possono accettare un elenco di token o un albero della sintassi astratta (AST) e restituire record di diagnostica. Ad esempio, in PowerShell Universal abbiamo una regola che verifica l’uso di variabili integrate come $PSUEnvironment o $UniversalClient. Assegnare tali variabili può causare un comportamento indefinito, quindi vogliamo che gli utenti lo sappiano subito quando tentano di sovrascriverle.

Il primo passo è creare un nuovo file di modulo .psm1 e definire una funzione che analizzerà lo script. In questo esempio abbiamo scelto Universal.Rules.psm1 come nome del file e definito la funzione Measure-PSUBuiltInVariables. La guida basata sui commenti è obbligatoria e ci sono alcuni dettagli specifici di questa funzione da tenere presenti.

Per prima cosa, deve includere l’attributo OutputType per specificare il tipo di oggetto che la funzione restituirà. In questo caso restituirà un array di oggetti Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord. Deve anche accettare un oggetto ScriptBlockAst come parametro. Questo oggetto rappresenta il blocco di script dello script in fase di analisi.

<#
.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
    )

Il corpo di questa funzione svolge il lavoro principale di analisi del blocco di script. Nel nostro esempio controlliamo l’AST per trovare le istruzioni di assegnazione. Se troviamo istruzioni di assegnazione, controlliamo poi se il lato sinistro dell’assegnazione è una variabile. In tal caso, usiamo poi un metodo statico per verificare se si tratta di una delle variabili integrate di PowerShell Universal.

Se le condizioni sono soddisfatte, creiamo nuovi oggetti DiagnosticRecord e popoliamo le informazioni necessarie. $_.Extent è importante perché indica agli editor, come VS Code o Monaco, quale parte dello script evidenziare con l’avviso o l’errore.

    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)
        }
    }

Infine, ci assicuriamo di esportare la funzione dal nostro modulo.

Export-ModuleMember -Function Measure-PSUBuiltInVariables

All’interno di PowerShell Universal usiamo Invoke-ScriptAnalyzer per eseguire l’analisi del codice. Mentre digita nell’editor, questa funzione viene chiamata per fornire un feedback in tempo reale. Per usare la nostra regola personalizzata, passiamo il parametro -CustomRulePath a Invoke-ScriptAnalyzer.

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

Elaboriamo poi l’output di PSScriptAnalyzer per fornire un feedback all’utente.

PowerShell Universal editor warning that overriding built-in variables causes undefined behavior.
Regola PSScriptAnalyzer personalizzata nell'editor di PowerShell Universal

Ha idee per regole personalizzate per PowerShell Universal? Ce lo faccia sapere.

Pronto a iniziare a creare? Scarichi PowerShell Universal.