modules/Devolutions.CIEM.Checks/Private/Invoke-CIEMCheck.ps1
|
function Invoke-CIEMCheck { <# .SYNOPSIS Executes a single CIEM check and emits findings to the pipeline. .DESCRIPTION Standardized entry point for running any CIEM check. Validates service caches, invokes the check function, counts findings, and handles errors. Emits [CIEMScanResult] objects to the pipeline. This is a private function called from Invoke-CIEMScan. .PARAMETER Check The CIEMCheck metadata object describing the check to run. .PARAMETER ServiceCache Pre-resolved array of service caches the check needs. The caller resolves these from Check.Service + Check.DependsOn. .PARAMETER FunctionName The resolved check function name (already validated to exist). .PARAMETER ProviderName Provider name used for log/warning messages. .OUTPUTS [CIEMScanResult[]] Finding objects emitted to the pipeline. #> [CmdletBinding()] [OutputType('CIEMScanResult')] param( [Parameter(Mandatory)] [CIEMCheck]$Check, [Parameter()] [CIEMServiceCache[]]$ServiceCache, [Parameter(Mandatory)] [string]$FunctionName, [Parameter()] [string]$ProviderName ) try { # Auto-skip if any required service failed to initialize if ($ServiceCache) { $failedServices = @($ServiceCache | Where-Object { -not $_.Success }) if ($failedServices) { $failedDetails = @($failedServices | ForEach-Object { $errorDetail = if ($_.Errors -and $_.Errors.Count -gt 0) { $_.Errors[0] } else { 'unknown error' } "$($_.ServiceName): $errorDetail" }) $failedMessage = "Required service(s) unavailable: $($failedDetails -join '; ')" Write-Verbose "[$ProviderName] Skipping check $($Check.Id) — service(s) failed: $failedMessage" [CIEMScanResult]::Create($Check, 'SKIPPED', $failedMessage, 'N/A', 'N/A') return } } # Build invocation parameters $invokeParams = @{ Check = $Check } if ($ServiceCache -and $ServiceCache.Count -gt 0) { $invokeParams.ServiceCache = $ServiceCache } # Invoke the check function and emit findings $checkFindingCount = 0 foreach ($finding in (& $FunctionName @invokeParams)) { $checkFindingCount++ $finding } # If zero findings, emit SKIPPED if ($checkFindingCount -eq 0) { Write-Verbose "[$ProviderName] Check $($Check.Id) produced no findings - marking as SKIPPED" [CIEMScanResult]::Create($Check, 'SKIPPED', 'Check produced no results - required data may be unavailable (e.g., no accessible subscriptions)', 'N/A', 'N/A') } } catch { $config = Get-CIEMConfig $continueOnError = if ($null -ne $config -and $null -ne $config.scan) { $config.scan.continueOnError } else { $true } if ($continueOnError) { Write-Warning "[$ProviderName] Check $($Check.Id) failed: $($_.Exception.Message)" [CIEMScanResult]::Create($Check, 'SKIPPED', "Check execution failed: $($_.Exception.Message)", 'N/A', 'N/A') } else { throw } } } |