<# .SYNOPSIS 对全仓跑 PSScriptAnalyzer(默认规则集 + 格式规则集),按规则汇总。 .DESCRIPTION 为什么要有这个入口,而不是直接敲 Invoke-ScriptAnalyzer: * 分析器装在**仓库内**(.tools\modules),不能指望机器上全局有一份; * 格式规则默认是 Disabled —— 不带 -Settings 的调用会静默漏掉全部排版问题, 那会让"按微软规范检查过了"变成一句空话; * 结果要能一眼看出"哪条规则、几个文件、几行",而不是几百行原始输出; * 路径过滤要与验收门槛一致:.tools\ / Backups\ / logs\ / dist\ 不进分析范围。 与测试的分工:这是**独立的门禁**,不塞进 Pester 用例。那个套件跑一次二十多秒, 把静态分析混进去会让"测试红了"这句话失去分辨力。 .PARAMETER Severity 只报这些级别,默认 Error 与 Warning。 .PARAMETER Quiet 只打印按规则汇总的计数,不逐条列出。 .EXAMPLE .\tools\Invoke-Analyzer.ps1 .EXAMPLE .\tools\Invoke-Analyzer.ps1 -Quiet #> [CmdletBinding()] param( [string[]]$Severity = @('Error', 'Warning'), [switch]$Quiet ) $ErrorActionPreference = 'Stop' $projectRoot = Split-Path -Parent $PSScriptRoot $localModules = Join-Path $projectRoot '.tools\modules' if (Test-Path -LiteralPath (Join-Path $localModules 'PSScriptAnalyzer')) { $env:PSModulePath = $localModules + [System.IO.Path]::PathSeparator + $env:PSModulePath } $analyzer = Get-Module -ListAvailable PSScriptAnalyzer | Sort-Object { [version]$_.Version } -Descending | Select-Object -First 1 if (-not $analyzer) { Write-Host '' Write-Host '找不到 PSScriptAnalyzer。把它装进仓库(不动机器上的全局模块):' -ForegroundColor Red Write-Host ' .\tools\Install-TestDependencies.ps1' -ForegroundColor Cyan Write-Host '' exit 2 } Import-Module $analyzer.Path -Force # 分析范围与验收门槛的 Encode / Parse 两层保持一致:只分析仓库自己的源码 $excluded = '\\(\.git|\.tools|\.scratch|Backups|logs|dist|snapshots)\\' $targets = @(Get-ChildItem -LiteralPath $projectRoot -Recurse -File | Where-Object { $_.Extension -in '.ps1', '.psm1', '.psd1' } | Where-Object { $_.FullName -notmatch $excluded } | Select-Object -ExpandProperty FullName) $settings = Join-Path $projectRoot 'PSScriptAnalyzerSettings.psd1' Write-Host '' Write-Host ("PSScriptAnalyzer {0}({1})" -f $analyzer.Version, $analyzer.ModuleBase) -ForegroundColor DarkGray Write-Host ("分析 {0} 个文件,配置 {1}" -f $targets.Count, $settings) -ForegroundColor DarkGray Write-Host '' # 逐个文件调用:-Path 在这个版本上只接受单个路径(传数组会报 Cannot convert # 'System.Object[]' to the type 'System.String'),而我们要的正是「只分析仓库自己的 # 源码」这个范围 —— 自己枚举文件反而更准。 $results = @(foreach ($file in $targets) { Invoke-ScriptAnalyzer -Path $file -Settings $settings -Severity $Severity }) if ($results.Count -eq 0) { Write-Host ("没有 {0} 级别的告警。" -f ($Severity -join '/')) -ForegroundColor Green Write-Host '' exit 0 } $byRule = $results | Group-Object RuleName | Sort-Object Count -Descending Write-Host ("共 {0} 条,按规则汇总:" -f $results.Count) -ForegroundColor Yellow foreach ($group in $byRule) { Write-Host (" {0,4} {1}" -f $group.Count, $group.Name) } if (-not $Quiet) { Write-Host '' Write-Host '逐条:' -ForegroundColor Yellow foreach ($item in ($results | Sort-Object ScriptName, Line)) { $relative = $item.ScriptName.Replace($projectRoot, '').TrimStart('\') Write-Host (" {0}:{1} [{2}] {3}" -f $relative, $item.Line, $item.RuleName, $item.Message) } } Write-Host '' exit 1