# Скрипт: check-ps-syntaxis.ps1 # Версия: 1.0.0 # Дата: 2026-07-16 # Описание: Проверка синтаксиса PowerShell-скриптов через AST-парсер (БЕЗ выполнения кода). # Принимает путь к файлу .ps1 или к папке (тогда проверяются все .ps1 рекурсивно). # Код возврата: 0 — всё чисто, 1 — есть синтаксические ошибки. # # Примеры: # .\check-ps-syntaxis.ps1 .\PS7-SETTINGS\01-setup-ps7.ps1 # .\check-ps-syntaxis.ps1 .\PS7-SETTINGS # вся папка # Get-ChildItem *.ps1 | .\check-ps-syntaxis.ps1 # по конвейеру [CmdletBinding()] param( [Parameter(Mandatory, Position = 0, ValueFromPipeline, ValueFromPipelineByPropertyName)] [Alias('FullName')] [string[]]$Path ) begin { [Console]::OutputEncoding = [System.Text.Encoding]::UTF8 $fFiles = New-Object System.Collections.Generic.List[string] # Развернуть путь в список .ps1 (файл → он сам, папка → все .ps1 рекурсивно) function Resolve-ScriptFiles { param([string]$InputPath) if (-not (Test-Path $InputPath)) { Write-Host "ПРЕДУПРЕЖДЕНИЕ: путь не найден: $InputPath" -ForegroundColor Yellow return } $item = Get-Item -LiteralPath $InputPath if ($item.PSIsContainer) { Get-ChildItem -LiteralPath $InputPath -Recurse -File -Filter '*.ps1' | ForEach-Object { $fFiles.Add($_.FullName) } } elseif ($item.Extension -eq '.ps1') { $fFiles.Add($item.FullName) } else { Write-Host "ПРЕДУПРЕЖДЕНИЕ: не .ps1 (пропущен): $($item.FullName)" -ForegroundColor Yellow } } } process { foreach ($p in $Path) { Resolve-ScriptFiles -InputPath $p } } end { if ($fFiles.Count -eq 0) { Write-Host "Нет .ps1 файлов для проверки." -ForegroundColor Yellow exit 1 } Write-Host "" Write-Host "Проверка синтаксиса | Файлов: $($fFiles.Count)" -ForegroundColor Cyan Write-Host ("-" * 70) -ForegroundColor DarkGray $fOk = 0 $fFail = 0 foreach ($file in ($fFiles | Sort-Object -Unique)) { $errs = $null # ParseFile НЕ исполняет код — только строит AST и собирает ошибки разбора $null = [System.Management.Automation.Language.Parser]::ParseFile($file, [ref]$null, [ref]$errs) $name = Split-Path $file -Leaf if ($errs -and $errs.Count -gt 0) { $fFail++ Write-Host ("[FAIL] {0} (ошибок: {1})" -f $name, $errs.Count) -ForegroundColor Red foreach ($e in $errs) { Write-Host (" L{0}:{1} {2}" -f $e.Extent.StartLineNumber, $e.Extent.StartColumnNumber, $e.Message) -ForegroundColor DarkYellow } } else { $fOk++ Write-Host ("[ OK ] {0}" -f $name) -ForegroundColor Green } } Write-Host ("-" * 70) -ForegroundColor DarkGray Write-Host ("Итого: проверено {0} | OK {1} | с ошибками {2}" -f $fFiles.Count, $fOk, $fFail) -ForegroundColor Cyan if ($fFail -gt 0) { exit 1 } else { exit 0 } }