<# .SYNOPSIS Runs every SecurityInsight Container Apps job of an install ONCE, in schedule order, and reports each run. .DESCRIPTION Reads the install's config (config/SecurityInsight.custom.ps1, without running it) for its subscription and resource group, lists the Container Apps jobs there and runs them the way the daily schedule would: jobs that start at the same time of day run together (in parallel), and each group waits for the one before it -- profilers before Risk Analysis, Risk Analysis before the trend. Each execution's outcome and duration is reported; exit code 1 when any run did not succeed (or did not finish within -TimeoutMinutes), 0 otherwise. Left out: the updater job (it changes the install; -IncludeUpdater runs it) and event-triggered jobs (they run when work arrives). -PlanOnly prints the order and starts nothing. Changes nothing but starting the jobs. Needs no PowerShell module (plain REST); signs in as the install's own identity from its config, or as the service principal certificate named in SI_DIAGNOSTICS_APPID / SI_DIAGNOSTICS_TENANTID / SI_DIAGNOSTICS_CERTTHUMBPRINT (-SignIn). The identity needs to start jobs in the resource group (Contributor there). .EXAMPLE ./diagnostics/Invoke-SIJobsOnce.ps1 -PlanOnly .EXAMPLE ./diagnostics/Invoke-SIJobsOnce.ps1 -TimeoutMinutes 180 .LINK https://invardia.com/docs/si/scripts/Invoke-SIJobsOnce/ .NOTES Requirements: PowerShell 7 (pwsh). Windows PowerShell 5.1 is refused at once (#Requires -Version 7.0). Role: Container Apps Jobs Operator (or Contributor) -- on the install's resource group Hosts: *.blob.core.windows.net, *.queue.core.windows.net, *.table.core.windows.net, *.vault.azure.net, 169.254.169.254, api.loganalytics.io, graph.microsoft.com, invardia.com, login.microsoftonline.com, management.azure.com, monitor.azure.com, storage.azure.com, vault.azure.net #> [CmdletBinding(SupportsShouldProcess)] param( [string]$ConfigPath, [string]$ResourceGroup, [string]$SubscriptionId, [string[]]$Only = @(), [string[]]$Exclude = @(), [switch]$IncludeUpdater, [switch]$PlanOnly, [int]$TimeoutMinutes = 120, [int]$PollSeconds = 30, [ValidateSet('Auto', 'AzContext', 'Config')][string]$SignIn = 'Auto', [switch]$PassThru, # Tests only: replacements for the calls that leave this process (Arm, LaQuery, Graph, Now, Sleep, Print). [Parameter(DontShow)][System.Collections.IDictionary]$Seams ) #Requires -Version 7.0 # SecurityInsight 3.0.79 -- Invoke-SIJobsOnce.ps1, standalone (Community edition). Built 2026-11-09T20:28:39Z from commit c1472e2f4c240c971c9559f07eef7e794b322001, source SOLUTIONS/SecurityInsight/diagnostics/Invoke-SIJobsOnce.ps1, # by release/Build-SISupportScripts.ps1 (framework SUPPORT-DL-1). Download: Invoke-WebRequest https://invardia.com/support/si/Invoke-SIJobsOnce.ps1 -OutFile Invoke-SIJobsOnce.ps1 # It carries the 20 SecurityInsight file(s) the script loads (listed in $__siSupportFiles below, readable, each line # prefixed with "|"); at run time it writes them to a private temporary folder, checks each SHA-256, runs the original # script from there with your parameters, and removes the folder. No PowerShell modules are needed. $script:SIScriptVersion = '3.0.79' # SI #547: the version this copy reports first (stamped into its embedded setup/_shared/SI-ScriptRun.ps1 too) $__siSupportVersion = '3.0.79' $__siSupportEntry = 'diagnostics/Invoke-SIJobsOnce.ps1' $__siSupportFiles = [ordered]@{} $__siSupportFiles['diagnostics/Invoke-SIJobsOnce.ps1'] = @{ Sha256 = '6c51e61512a460266f53ed5b9222d27a1f0d283ded148805a9c37a2646d2be5a'; Text = @' |<# |.SYNOPSIS | Runs every SecurityInsight Container Apps job of an install ONCE, in schedule order, and reports each run. | |.DESCRIPTION | Reads the install's config (config/SecurityInsight.custom.ps1, without running it) for its subscription and resource | group, lists the Container Apps jobs there and runs them the way the daily schedule would: jobs that start at the | same time of day run together (in parallel), and each group waits for the one before it -- profilers before Risk | Analysis, Risk Analysis before the trend. Each execution's outcome and duration is reported; exit code 1 when any | run did not succeed (or did not finish within -TimeoutMinutes), 0 otherwise. | | Left out: the updater job (it changes the install; -IncludeUpdater runs it) and event-triggered jobs (they run when | work arrives). -PlanOnly prints the order and starts nothing. | | Changes nothing but starting the jobs. Needs no PowerShell module (plain REST); signs in as the install's own | identity from its config, or as the service principal certificate named in SI_DIAGNOSTICS_APPID / | SI_DIAGNOSTICS_TENANTID / SI_DIAGNOSTICS_CERTTHUMBPRINT (-SignIn). The identity needs to start jobs in the | resource group (Contributor there). | |.EXAMPLE | ./diagnostics/Invoke-SIJobsOnce.ps1 -PlanOnly |.EXAMPLE | ./diagnostics/Invoke-SIJobsOnce.ps1 -TimeoutMinutes 180 | |.LINK | https://invardia.com/docs/si/scripts/Invoke-SIJobsOnce/ |#> |[CmdletBinding(SupportsShouldProcess)] |param( | [string]$ConfigPath, | [string]$ResourceGroup, | [string]$SubscriptionId, | [string[]]$Only = @(), | [string[]]$Exclude = @(), | [switch]$IncludeUpdater, | [switch]$PlanOnly, | [int]$TimeoutMinutes = 120, | [int]$PollSeconds = 30, | [ValidateSet('Auto', 'AzContext', 'Config')][string]$SignIn = 'Auto', | [switch]$PassThru, | # Tests only: replacements for the calls that leave this process (Arm, LaQuery, Graph, Now, Sleep, Print). | [Parameter(DontShow)][System.Collections.IDictionary]$Seams |) | |#Requires -Version 7.0 # after the help and the param block: before the help, it hides the help from Get-Help |# framework section 12.7 / 12.10: the documentation link first, a transcript of the run, -WhatIf writes nothing |. ([IO.Path]::Combine((Split-Path -Parent $PSScriptRoot), 'setup', '_shared', 'SI-ScriptRun.ps1')) |$siRun = Start-SIScriptRun -Script 'Invoke-SIJobsOnce' -Quiet:([bool]$PSBoundParameters.ContainsKey('Seams')) |if ($WhatIfPreference) { $PlanOnly = $true } # -WhatIf = the plan: no job is started |try { |$ErrorActionPreference = 'Stop' |. ([IO.Path]::Combine($PSScriptRoot, '_SIInstallDiagnostics.ps1')) |if (-not $ConfigPath) { $ConfigPath = [IO.Path]::Combine((Split-Path -Parent $PSScriptRoot), 'config', 'SecurityInsight.custom.ps1') } | |$values = @{} |if ((-not $ResourceGroup -or -not $SubscriptionId) -or (Test-Path -LiteralPath $ConfigPath)) { $values = Read-SIInstallConfigValues -Path $ConfigPath } |$target = Get-SIInstallTargetFromConfig -Values $values |if ($SubscriptionId) { $target.SubscriptionId = $SubscriptionId } |if ($ResourceGroup) { $target.ResourceGroup = $ResourceGroup } |if (-not $target.SubscriptionId -or -not $target.ResourceGroup) { throw 'The subscription and resource group of the install are not known: give -ConfigPath, or -SubscriptionId and -ResourceGroup.' } |$rgId = '/subscriptions/{0}/resourceGroups/{1}' -f $target.SubscriptionId, $target.ResourceGroup | |if (-not $Seams) { $null = Initialize-SIDiagnosticsSignIn -SignIn $SignIn -Values $values } |$s = Merge-SIDiagnosticsSeams -Seams $Seams |$jobs = @(& $s.Arm 'GET' ($rgId + '/providers/Microsoft.App/jobs') $script:SIDiagJobApi -List:$true $null | Where-Object { $_ }) |$plan = Get-SIJobRunPlan -Jobs $jobs -IncludeUpdater:$IncludeUpdater -Only $Only -Exclude $Exclude | |& $s.Print ('== SecurityInsight jobs in {0}: {1} to run in {2} group(s)' -f $target.ResourceGroup, @($plan.Groups | ForEach-Object { $_.Jobs }).Count, @($plan.Groups).Count) 'Cyan' |$i = 0 |foreach ($g in @($plan.Groups)) { $i++; & $s.Print (' {0,2}. {1,-6} {2}' -f $i, $g.At, (@($g.Jobs | ForEach-Object Name) -join ', ')) '' } |foreach ($k in @($plan.Skipped)) { & $s.Print (' left out: {0} ({1})' -f $k.Name, $k.Why) 'DarkGray' } |if (-not @($plan.Groups).Count) { & $s.Print ' no job to run.' 'Red'; exit 1 } |if ($PlanOnly) { if ($PassThru) { $plan }; exit 0 } | |$r = Invoke-SIJobRunOnce -Plan $plan -Seams $s -PollSeconds $PollSeconds -TimeoutMinutes $TimeoutMinutes |if ($PassThru) { $r } |exit $(if ($r.Ok) { 0 } else { 1 }) |} finally { Stop-SIScriptRun -Run $siRun } '@ } $__siSupportFiles['setup/_shared/SI-ScriptRun.ps1'] = @{ Sha256 = 'a5c4d788d516521639611af43e1b88458216ce58bdb455885cac8e2a568afbd2'; Text = @' |#Requires -Version 5.1 |<# | EVERY SCRIPT A PERSON RUNS (framework DOCS/REQUIREMENTS.md section 12.7 SCRIPT-DOC-1 + section 12.10 SECURITY-PACK-1; SI #481 / #484). | One helper, called first by each such script: | | $siRun = Start-SIScriptRun -Script '