src/assess/engine/Resolve-JsonPath.ps1
|
#Requires -Version 7.0 Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' <# .SYNOPSIS Resolve a JSONPath expression against an object using the Newtonsoft engine that ships with PowerShell 7. .NOTES Tracks ADO Story AB#5029. #> function New-ScoutQueryContext { param([Parameter(Mandatory)] $InputObject) # Owned by one immutable assessment snapshot, never a module/global cache. Parse lazily # so manual-only assessments do not pay for a JSON conversion (AB#9303). [pscustomobject]@{ InputObject = $InputObject; Token = $null; ParseCount = 0 } } function Resolve-JsonPath { param( [Parameter(Mandatory)] $InputObject, [Parameter(Mandatory)] [AllowEmptyString()] [AllowNull()] [string] $Path, [AllowNull()] $QueryContext ) # A null/blank path is a legitimate "no query" (e.g. manual rules) -> empty set. # NOTE: `return @()` collapses to $null once it crosses the function-return # pipeline (a well-known PowerShell empty-array-unwrapping gotcha), which then # blows up every `.Count` caller under Set-StrictMode. Write-Output -NoEnumerate # preserves the (possibly empty) array identity across the return boundary. if ([string]::IsNullOrWhiteSpace($Path)) { Write-Output -InputObject @() -NoEnumerate return } if ($null -eq $QueryContext) { $QueryContext = New-ScoutQueryContext -InputObject $InputObject } if (-not [object]::ReferenceEquals($QueryContext.InputObject, $InputObject)) { throw 'The query context belongs to a different assessment input snapshot.' } if ($null -eq $QueryContext.Token) { $timer = [Diagnostics.Stopwatch]::StartNew() if (Get-Command Write-AZSCLog -ErrorAction SilentlyContinue) { Write-AZSCLog -Level DEBUG -Message 'Assessment query index build started.' } $json = $InputObject | ConvertTo-Json -Depth 100 $QueryContext.Token = [Newtonsoft.Json.Linq.JToken]::Parse($json) $QueryContext.ParseCount++ if (Get-Command Write-AZSCLog -ErrorAction SilentlyContinue) { Write-AZSCLog -Level DEBUG -Message ('Assessment query index built: elapsed={0}; characters={1}' -f $timer.Elapsed, $json.Length) } } $token = $QueryContext.Token # A query that THROWS (unsupported/invalid JSONPath) must NOT collapse into an # empty result set — that would let a broken query score as a Pass on # countEquals:0 asserts (AB#5083). Rethrow so Invoke-Rule can mark it Error. $results = $token.SelectTokens($Path, $false) Write-Output -InputObject @($results) -NoEnumerate } |