使用 PSScriptAnalyzer

本文介绍 PSScriptAnalyzer 的各种功能以及如何使用它们。

解析器错误

从版本 1.18.0 开始, PSScriptAnalyzer 在输出流中将分析器错误作为诊断记录发出。

Invoke-ScriptAnalyzer -ScriptDefinition '"b" = "b"; function eliminate-file () { }'
RuleName            Severity   ScriptName Line Message
--------            --------   ---------- ---- -------
InvalidLeftHandSide ParseError            1    The assignment expression isn't
                                               valid. The input to an
                                               assignment operator must be an
                                               object that's able to accept
                                               assignments, such as a variable
                                               or a property.
PSUseApprovedVerbs  Warning               1    The cmdlet 'eliminate-file' uses an
                                               unapproved verb.

RuleName 设置为解析器错误的 ErrorId

若要禁止显示 ParseErrors,请勿将其作为值包含在 Severity 参数中。

$invokeScriptAnalyzerSplat = @{
    ScriptDefinition = '"b" = "b"; function eliminate-file () { }'
    Severity = 'Warning'
}
Invoke-ScriptAnalyzer @invokeScriptAnalyzerSplat
RuleName           Severity ScriptName Line Message
--------           -------- ---------- ---- -------
PSUseApprovedVerbs Warning             1    The cmdlet 'eliminate-file' uses an
                                            unapproved verb.

抑制规则

您可以通过使用 修饰脚本、函数或参数来禁止规则。NET 的 SuppressMessageAttributeSuppressMessageAttribute 的构造函数采用两个参数:类别和检查 ID。 将 categoryID 参数设置为要禁止的规则的名称,并将 checkID 参数设置为空或空字符串。 您可以选择添加第三个命名参数,其中包含禁止显示消息的理由:

function SuppressMe()
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideCommentHelp', '',
        Justification='Just an example')]
    param()

    Write-Verbose -Message "I'm making a difference!"

}

在您修饰的脚本、函数或参数的范围内,将禁止显示所有规则违规。

若要禁止显示特定参数上的消息,请将 SuppressMessageAttributeCheckId 参数设置为参数的名称:

function SuppressTwoVariables()
{
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideDefaultParameterValue', 'b')]
    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideDefaultParameterValue', 'a')]
    param([string]$a, [int]$b)
    {
    }
}

使用 SuppressMessageAttributeScope 属性将规则抑制限制为属性范围内的函数或类。

使用值 Function 来抑制属性范围内所有函数的冲突。 使用值 Class 禁止对属性范围内所有类的冲突:

[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideCommentHelp', '', Scope='Function')]
param()

function InternalFunction
{
    param()

    Write-Verbose -Message "I am invincible!"
}

你可以通过将 SuppressMessageAttributeTarget 属性设置为正则表达式或万用符模式,进一步限制基于函数、参数、类、变量或对象名称的抑制。

例如,若要禁止 和 start-barstart-baz 规则冲突,但不禁止 和 start-foostart-bam

[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '',
    Scope='Function', Target='start-ba[rz]')]
param()
function start-foo {
    write-host "start-foo"
}

function start-bar {
    write-host "start-bar"
}

function start-baz {
    write-host "start-baz"
}

function start-bam {
    write-host "start-bam"
}

要禁止所有功能中的违规行为:

[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '',
    Scope='Function', Target='*')]
Param()

要抑制 中的start-barstart-baz违规行为,但不start-bam禁止 中的违规start-foo行为:

[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '',
    Scope='Function', Target='start-b*')]
Param()

注释

无法使用 SuppressMessageAttribute 抑制分析器错误。

ScriptAnalyzer 中的设置支持

可以创建描述要根据 严重性包含或排除的 ScriptAnalyzer 规则的设置。 使用 的 设置Invoke-ScriptAnalyzer 参数指定配置。 设置参数允许你为特定环境创建自定义配置。 ScriptAnalyzer 支持以下模式来指定设置文件:

内置预设

ScriptAnalyzer 附带了一组内置预设,可用于分析脚本。 例如,如果要在模块上运行 PowerShell 库 规则,请使用以下命令:

Invoke-ScriptAnalyzer -Path /path/to/module/ -Settings PSGallery -Recurse

此外,您还可以使用其他内置预设,包括 DSCCodeFormatting。 这些预设可以针对 “设置 ”参数进行制表符完成。

Explicit

以下示例从默认规则集中排除两个规则,以及严重性不是 “错误”“警告”的任何规则。

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

然后,您可以使用以下命令调用 Invoke-ScriptAnalyzer该设置文件:

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

下一个示例选择要执行的几个规则,而不是所有默认规则。

# PSScriptAnalyzerSettings.psd1
@{
    IncludeRules=@('PSAvoidUsingPlainTextForPassword',
                'PSAvoidUsingConvertToSecureStringWithPlainText')
}

然后,您可以调用该设置文件:

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

隐式

如果将名为 PSScriptAnalyzerSettings.psd1 的设置文件放置在项目根目录中,则 PSScriptAnalyzer 会在将项目根目录作为 Path 参数传递时发现该文件。

Invoke-ScriptAnalyzer -Path "C:\path\to\project" -Recurse

明确提供设置优先于这种隐式模式。 你可以在SettingsPSScriptAnalyzer模块的文件夹中找到示例设置文件。

检查 PowerShell 版本兼容性

PSScriptAnalyzer 可以检查 PowerShell 脚本是否与其他 PowerShell 版本和环境不兼容。 PSScriptAnalyzer 包括四个用于检查兼容性问题的规则:

有关如何使用这些规则的详细信息,请参阅 PowerShell 团队博客上的使用 PSScriptAnalyzer 检查 PowerShell 版本兼容性

自定义规则

可以在设置文件中提供自定义规则的一个或多个路径。 重要的是,这些路径指向模块的文件夹(隐式使用模块清单)或模块的脚本文件 ()。.psm1 模块必须导出 Export-ModuleMember 自定义规则函数,以便它们可供 PSScriptAnalyzer 使用。

在这个例子中, CustomRulePath 属性指向两个不同的模块。 这两个模块都导出带有谓词 Measure 的规则函数,因此 Measure-* 用于属性 IncludeRules

@{
    CustomRulePath      = @(
        '.\output\RequiredModules\DscResource.AnalyzerRules'
        '.\tests\QA\AnalyzerRules\SqlServerDsc.AnalyzerRules.psm1'
    )

    IncludeRules        = @(
        'Measure-*'
    )
}

还可以通过在 IncludeRules 属性中列出规则来添加默认规则。 在包含默认规则时,请务必将 属性 IncludeDefaultRules 设置为 $true;否则将使用默认规则。

@{
    CustomRulePath      = @(
        '.\output\RequiredModules\DscResource.AnalyzerRules'
        '.\tests\QA\AnalyzerRules\SqlServerDsc.AnalyzerRules.psm1'
    )

    IncludeDefaultRules = $true

    IncludeRules        = @(
        # Default rules
        'PSAvoidDefaultValueForMandatoryParameter'
        'PSAvoidDefaultValueSwitchParameter'

        # Custom rules
        'Measure-*'
    )
}

在Visual Studio Code中使用自定义规则(VS Code)

你也可以使用VS Code设置文件里提供的自定义规则。 添加一个VS Code工作区设置文件(),.vscode/settings.json内容如下。

{
    "powershell.scriptAnalysis.settingsPath": ".vscode/analyzersettings.psd1",
    "powershell.scriptAnalysis.enable": true,
}

ScriptAnalyzer 作为 .NET 库

您可以直接将 ScriptAnalyzer 的引擎和功能用作库。

以下是公共接口:

using Microsoft.Windows.PowerShell.ScriptAnalyzer;

public void Initialize(System.Management.Automation.Runspaces.Runspace runspace,
Microsoft.Windows.PowerShell.ScriptAnalyzer.IOutputWriter outputWriter,
[string[] customizedRulePath = null],
[string[] includeRuleNames = null],
[string[] excludeRuleNames = null],
[string[] severity = null],
[bool suppressedOnly = false],
[string profile = null])

public System.Collections.Generic.IEnumerable<DiagnosticRecord> AnalyzePath(string path,
    [bool searchRecursively = false])

public System.Collections.Generic.IEnumerable<IRule> GetRule(string[] moduleNames,
    string[] ruleNames)

违规纠正

您可以使用 修复 开关自动替换违规内容,使用建议的替代方案。 此外,由于实现了 Invoke-ScriptAnalyzer,因此可以使用 WhatIfConfirm 来找出将应用哪些更正。 应用修正时应使用源码控制,因为某些更改,比如 AvoidUsingPlainTextForPassword,可能需要其他脚本修改,无法自动完成。 当你自动应用建议时,初始编码并不总能保持。 如果你的脚本依赖某种特定的编码,你应该检查文件编码。

错误记录的 SuggestedCorrections 属性使得在 VS Code 等编辑器中实现快速修复场景。 我们为以下规则提供有效的 SuggestedCorrection

  • 避免别名
  • 避免使用PlainTextForPassword
  • 误导性反引号
  • MissingModuleManifestField
  • UseToExportFieldsInManifest