modules/Devolutions.CIEM.Checks/Public/New-CIEMScanRun.ps1
|
function New-CIEMScanRun { <# .SYNOPSIS Creates and executes a CIEM security scan, returning the completed ScanRun. .DESCRIPTION Single public entry point for running CIEM scans. Creates a ScanRun record, delegates check execution to the internal Invoke-CIEMScan, and returns the completed [CIEMScanRun] object with all results attached. When -Provider is omitted, all enabled providers are scanned. If one provider fails to connect, its checks are marked SKIPPED and scanning continues with remaining providers. .PARAMETER Provider One or more cloud providers to scan ('Azure', 'AWS'). Omit to scan all enabled providers. .PARAMETER CheckId Optional array of check IDs to run. If not specified, runs all checks. .PARAMETER Service Optional service filter. Only runs checks for specified service(s). Applied globally — providers that do not have the service are skipped silently. .PARAMETER IncludePassed Whether to include passed checks in results. Default is false. .OUTPUTS [CIEMScanRun] The completed scan run with all results attached. .EXAMPLE $scanRun = New-CIEMScanRun # Scans all enabled providers, returns completed ScanRun .EXAMPLE $scanRun = New-CIEMScanRun -Provider 'Azure' # Scans Azure only .EXAMPLE $scanRun = New-CIEMScanRun -Provider @('Azure', 'AWS') -Service 'Entra' # Scans the Entra service on Azure; AWS is skipped silently (no Entra service) #> [CmdletBinding()] [OutputType('CIEMScanRun')] param( [Parameter()] [string[]]$Provider, [Parameter()] [string[]]$CheckId, [Parameter()] [string[]]$Service, [Parameter()] [switch]$IncludePassed ) $ErrorActionPreference = 'Stop' # PSU doesn't pass -Parameters to module command scripts, so read from cache if (-not $Provider -and -not $CheckId -and -not $Service) { $scanConfig = Get-PSUCache -Key $script:ScanConfigCacheKey -Integrated -ErrorAction SilentlyContinue if ($scanConfig -and $scanConfig.Provider) { $Provider = $scanConfig.Provider $CheckId = $scanConfig.CheckId $Service = $scanConfig.Service $IncludePassed = [switch]([bool]$scanConfig.IncludePassed) Set-PSUCache -Key $script:ScanConfigCacheKey -Value @{} -Integrated -ErrorAction SilentlyContinue Write-CIEMLog -Message "Loaded scan config from cache: Provider=[$($Provider -join ',')], CheckId=[$($CheckId -join ',')], Service=[$($Service -join ',')]" -Severity INFO -Component 'ScanRun' } } Write-CIEMLog -Message "New-CIEMScanRun called: Provider=[$($Provider -join ',')], CheckId=[$($CheckId -join ',')], Service=[$($Service -join ',')], IncludePassed=$IncludePassed" -Severity INFO -Component 'ScanRun' # --- Resolve providers: default to all enabled when not specified --- if (-not $Provider -or $Provider.Count -eq 0) { $Provider = @(Get-CIEMProvider | Where-Object Enabled | Select-Object -ExpandProperty Name) if ($Provider.Count -eq 0) { throw "No enabled providers configured. Use New-CIEMProvider to add providers." } Write-Verbose "No -Provider specified; scanning all enabled providers: $($Provider -join ', ')" } # --- Determine the union of all services across requested providers --- $allProviderServices = @(foreach ($p in $Provider) { Get-CIEMProviderService -Provider $p | Select-Object -ExpandProperty Name }) # Validate -Service if specified: at least one provider must have each requested service if ($Service) { $invalidServices = $Service | Where-Object { $_ -notin $allProviderServices } if ($invalidServices) { throw "Requested service(s) not available in any specified provider: $($invalidServices -join ', '). Available: $($allProviderServices -join ', ')" } } # Services for the ScanRun record: the union of what will actually be scanned $scanServices = if ($Service) { $Service } else { $allProviderServices | Select-Object -Unique } # --- Create and persist ScanRun --- $scanRun = [CIEMScanRun]::new($Provider, $scanServices, $IncludePassed.IsPresent) $scanRun.Status = [CIEMScanRunStatus]::Running Save-CIEMScanRun -ScanRun $scanRun Write-Verbose "Started ScanRun: $($scanRun.Id) for providers: $($Provider -join ', ')" # --- Execute scan and collect results --- try { $invokeParams = @{ Provider = $Provider } if ($CheckId) { $invokeParams.CheckId = $CheckId } if ($Service) { $invokeParams.Service = $Service } if ($IncludePassed) { $invokeParams.IncludePassed = $true } $allFindings = @(Invoke-CIEMScan @invokeParams) $scanRun.ScanResults = $allFindings $scanRun.Complete() Save-CIEMScanRun -ScanRun $scanRun Write-Verbose "ScanRun completed: $($scanRun.Id) — $($scanRun.TotalResults) results" } catch { $scanRun.ScanResults = @() $scanRun.Fail($_.Exception.Message) Save-CIEMScanRun -ScanRun $scanRun Write-Verbose "ScanRun failed: $($scanRun.Id) — $($_.Exception.Message)" throw } return $scanRun } |