Private/Get-METCheckMetadata.ps1
|
function Get-METCheckMetadata { [CmdletBinding()] [OutputType('MET.CheckInfo')] param( [Parameter(Mandatory)] [string] $Path ) $file = Get-Item -LiteralPath $Path $tokens = $null $parseErrors = $null $ast = [System.Management.Automation.Language.Parser]::ParseFile( $file.FullName, [ref] $tokens, [ref] $parseErrors) if ($parseErrors) { throw "Failed to parse check script '$($file.FullName)': $($parseErrors[0].Message)" } $parts = $file.BaseName -split '-', 3 $name = $null $severity = $null $description = $null $requiresModule = @() # Top-level only. A $METCheckInfo assigned inside a function or a nested scriptblock is # not the file's header, and treating it as one would let a check advertise metadata # that only exists down some branch. $assignment = @($ast.FindAll( { param($node) $node -is [System.Management.Automation.Language.AssignmentStatementAst] -and $node.Left -is [System.Management.Automation.Language.VariableExpressionAst] -and $node.Left.VariablePath.UserPath -eq 'METCheckInfo' }, $false)) | Select-Object -First 1 if ($assignment) { $hashtable = $assignment.Right.Find( { param($node) $node -is [System.Management.Automation.Language.HashtableAst] }, $false) if ($hashtable) { foreach ($pair in $hashtable.KeyValuePairs) { $key = $pair.Item1.Extent.Text.Trim(("'", '"')) # Every legal value shape here - 'x', @('x'), 'x','y', @('x','y') - reduces # to its string constants. Reading them off the subtree rather than matching # one AST class per shape means a new-but-equivalent literal shape does not # silently read as empty. $constants = @($pair.Item2.FindAll( { param($node) $node -is [System.Management.Automation.Language.StringConstantExpressionAst] }, $true) | ForEach-Object { $_.Value }) switch ($key) { 'Name' { $name = $constants | Select-Object -First 1 } 'Severity' { $severity = $constants | Select-Object -First 1 } 'Description' { $description = $constants | Select-Object -First 1 } 'RequiresModule' { $requiresModule = $constants } } } } } [PSCustomObject]@{ PSTypeName = 'MET.CheckInfo' CheckId = "$($parts[0])-$($parts[1])" Category = $file.Directory.Name Name = $name Severity = $severity Description = $description RequiresModule = $requiresModule Script = $file.Name Path = $file.FullName } } |