Membuat aturan kustom

PSScriptAnalyzer menggunakan Kerangka Kerja Ekstensibilitas Terkelola (MEF) untuk mengimpor semua aturan yang ditentukan dalam rakitan. Itu juga dapat menggunakan aturan yang ditulis dalam skrip PowerShell.

Pengguna dapat menentukan aturan kustom menggunakan parameter CustomizedRulePath dari Invoke-ScriptAnalyzer cmdlet.

Artikel ini memberikan panduan dasar untuk membuat aturan khusus Anda sendiri.

Persyaratan dasar

Fungsi harus memiliki bantuan berbasis komentar

Sertakan .DESCRIPTION bidang. Bidang ini menjadi deskripsi untuk aturan yang disesuaikan.

<#
.SYNOPSIS
    Name of your rule.
.DESCRIPTION
    This would be the description of your rule. Please refer to Rule Documentation
    for consistent rule messages.
.EXAMPLE
.INPUTS
.OUTPUTS
.NOTES
#>

Jenis output harus berupa array objek DiagnosticRecord

[OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]

Setiap fungsi harus memiliki array Token atau parameter Ast

Nama nama parameter Ast harus diakhiri dengan Ast.

Param
(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [System.Management.Automation.Language.ScriptBlockAst]
    $testAst
)

Nama nama parameter Token harus diakhiri dengan Token.

Param
(
    [Parameter(Mandatory = $true)]
    [ValidateNotNullOrEmpty()]
    [System.Management.Automation.Language.Token[]]
    $testToken
)

DiagnosticRecord harus memiliki properti yang diperlukan

DiagnosticRecord harus memiliki setidaknya empat properti:

  • Pesan
  • Sejauh
  • RuleName
  • Severity
$result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{
    Message  = 'This is a sample rule'
    Extent   = $ast.Extent
    RuleName = $PSCmdlet.MyInvocation.InvocationName
    Severity = 'Warning'
}

Sejak versi 1.17.0, Anda dapat menyertakan properti SuggestedCorrections jenis IEnumerable<CorrectionExtent>. Pastikan untuk menentukan jenis yang benar. Contohnya:

$startLineNumber =  $ast.Extent.StartLineNumber
$endLineNumber = $ast.Extent.EndLineNumber
$startColumnNumber = $ast.Extent.StartColumnNumber
$endColumnNumber = $ast.Extent.EndColumnNumber
$correction = 'Correct text that replaces Extent text'
$file = $MyInvocation.MyCommand.Definition
$optionalDescription = 'Useful but optional description text'
$objParams = @{
  TypeName = 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent'
  ArgumentList = $startLineNumber, $endLineNumber, $startColumnNumber,
                 $endColumnNumber, $correction, $file, $optionalDescription
}
$correctionExtent = New-Object @objParams
$suggestedCorrections = New-Object System.Collections.ObjectModel.Collection[$($objParams.TypeName)]
$suggestedCorrections.add($correctionExtent) | Out-Null

[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord]@{
    Message              = 'This is a rule with a suggested correction'
    Extent               = $ast.Extent
    RuleName             = $PSCmdlet.MyInvocation.InvocationName
    Severity             = 'Warning'
    RuleSuppressionID    = 'MyRuleSuppressionID'
    SuggestedCorrections = $suggestedCorrections
}

Pastikan Anda mengekspor fungsi

Anda harus mengekspor fungsi yang Anda buat sehingga PSScriptAnalyzer dapat menemukannya.

Export-ModuleMember -Function (FunctionName)

Contoh fungsi aturan

<#
    .SYNOPSIS
    Uses #Requires -RunAsAdministrator instead of your own methods.
    .DESCRIPTION
    The #Requires statement prevents a script from running unless the Windows PowerShell
    version, modules, snap-ins, and module and snap-in version prerequisites are met.
    Since Windows PowerShell 4.0, the #Requires statement lets script developers require that
    sessions be run with elevated user rights (run as Administrator). Script developers do
    not need to write their own methods any more. To fix a violation of this rule, please
    consider using #Requires -RunAsAdministrator instead of your own methods.
    .EXAMPLE
    Measure-RequiresRunAsAdministrator -ScriptBlockAst $ScriptBlockAst
    .INPUTS
    [System.Management.Automation.Language.ScriptBlockAst]
    .OUTPUTS
    [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
    .NOTES
    None
#>
function Measure-RequiresRunAsAdministrator {
    [CmdletBinding()]
    [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
    param
    (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [System.Management.Automation.Language.ScriptBlockAst]
        $ScriptBlockAst
    )

    begin {
        $MeasureRequiresAdmin = @(
            'The #Requires statement prevents a script from running unless the PowerShell version,'
            'modules, snap-ins, and module and snap-in version prerequisites are met. Since'
            'Windows PowerShell 4.0, the #Requires statement lets script developers require that'
            'sessions be run with elevated user rights (run as Administrator). Script developers'
            'don''t need to write their own methods to test for elevated rights. To fix a violation'
            'of this rule, use #Requires -RunAsAdministrator instead of your own methods.'
        ) -join ' '

        # Finds specific method, IsInRole.
        [ScriptBlock]$predicate = {
            param($Ast)
            return $Ast.Member.Value -eq 'IsInRole'
        }
    }

    process {
        # Exit early if the script block has a #Requires -RunAsAdministrator statement.
        if ($ScriptBlockAst.ScriptRequirements.IsElevationRequired) {
          return
        }

        # Test for calls to IsInRole() method
        [System.Management.Automation.Language.Ast]$methodAst = $ScriptBlockAst.Find($predicate, $true)
        if ($methodAst) {
            [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{
                Message  = $MeasureRequiresAdmin
                Extent   = $methodAst.Extent
                RuleName = $PSCmdlet.MyInvocation.InvocationName
                Severity = 'Information'
            }
        }
    }
}

Contoh lainnya dapat ditemukan di folder CommunityAnalyzerRules di GitHub.