Private/Get-TLRuleDefinition.ps1
|
function Get-TLRuleDefinition { <# .SYNOPSIS Loads rule definitions (PSD1 files containing a Test scriptblock). .DESCRIPTION Rule files are executable PowerShell data files - loading a custom rule path executes code, exactly like importing a module. Duplicate rule ids are rejected (first one wins). #> [CmdletBinding()] param( [string[]]$Path, [switch]$IncludeDefault ) $validSeverities = @('Critical', 'High', 'Medium', 'Low', 'Info') $searchPaths = [System.Collections.Generic.List[string]]::new() if ($IncludeDefault) { $searchPaths.Add((Join-Path -Path $script:TLModuleRoot -ChildPath 'Rules')) } foreach ($extraPath in @($Path | Where-Object { $_ })) { $searchPaths.Add($extraPath) } $seenIds = @{} foreach ($rulePath in $searchPaths) { if (-not (Test-Path -Path $rulePath)) { Write-Warning ("Rule path '{0}' does not exist." -f $rulePath) continue } foreach ($file in (Get-ChildItem -Path $rulePath -Filter '*.psd1' -File | Sort-Object -Property Name)) { $rule = $null try { $rule = & ([scriptblock]::Create((Get-Content -Path $file.FullName -Raw))) } catch { Write-Warning ("Rule '{0}' could not be parsed: {1}" -f $file.Name, $_.Exception.Message) continue } if ($rule -isnot [hashtable]) { Write-Warning ("Rule '{0}' does not evaluate to a hashtable - ignored." -f $file.Name) continue } $missingKeys = @(@('Id', 'Title', 'Area', 'Severity', 'Test') | Where-Object { -not $rule[$_] }) if ($missingKeys.Count -gt 0) { Write-Warning ("Rule '{0}' is missing mandatory keys: {1}" -f $file.Name, ($missingKeys -join ', ')) continue } if ($validSeverities -notcontains [string]$rule['Severity']) { Write-Warning ("Rule '{0}' has invalid severity '{1}'." -f $file.Name, $rule['Severity']) continue } if ($seenIds.ContainsKey([string]$rule['Id'])) { Write-Warning ("Duplicate rule id '{0}' in '{1}' - first definition wins." -f $rule['Id'], $file.Name) continue } $seenIds[[string]$rule['Id']] = $true [pscustomobject]@{ Id = [string]$rule['Id'] Title = [string]$rule['Title'] Area = [string]$rule['Area'] Severity = [string]$rule['Severity'] References = @($rule['References'] | Where-Object { $_ }) Rationale = [string]$rule['Rationale'] Remediation = [string]$rule['Remediation'] Test = [scriptblock]$rule['Test'] Source = $file.FullName } } } } |