param( [int]$LookbackDays = 7, [int]$TopCount = 10, [string]$OutputPath = "..\reports\ocsentinel-summary.json", [string]$ConfigPath = "..\config\ocsentinel-settings.json", [string]$ClientConfigPath = "..\config\ocsentinel-client.json", [string]$SecretPath = "", [string]$VulnerabilityCsvPath = "", [string]$MirrorRoot = "", [ValidateSet("disabled", "auto", "required")] [string]$UploadMode = "auto", [switch]$FailOnAttacks, [switch]$FailOnThreshold ) $ErrorActionPreference = "Stop" $scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path $installRoot = Split-Path -Parent $scriptDir $appExe = Join-Path $installRoot "app\OCSentinelCli.exe" $outputFullPath = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $OutputPath)) function Resolve-PathLike { param( [Parameter(Mandatory)] [string]$PathValue, [Parameter(Mandatory)] [string]$BasePath ) if ([string]::IsNullOrWhiteSpace($PathValue)) { return $PathValue } if ([System.IO.Path]::IsPathRooted($PathValue) -or $PathValue.StartsWith("\\")) { return [System.IO.Path]::GetFullPath($PathValue) } return [System.IO.Path]::GetFullPath((Join-Path $BasePath $PathValue)) } function Restore-NinjaContextFromClientConfiguration { param([Parameter(Mandatory)][string]$Path) if (-not (Test-Path -LiteralPath $Path)) { return } try { $clientConfiguration = Get-Content -LiteralPath $Path -Raw | ConvertFrom-Json $mappings = @( @{ EnvironmentName = "NINJA_ORGANIZATION_ID"; PropertyName = "ninjaOrganizationId" }, @{ EnvironmentName = "NINJA_ORGANIZATION_NAME"; PropertyName = "ninjaOrganizationName" }, @{ EnvironmentName = "NINJA_AGENT_MACHINE_ID"; PropertyName = "ninjaMachineId" }, @{ EnvironmentName = "NINJA_AGENT_NODE_ID"; PropertyName = "ninjaNodeId" }, @{ EnvironmentName = "NINJA_LOCATION_ID"; PropertyName = "ninjaLocationId" }, @{ EnvironmentName = "NINJA_LOCATION_NAME"; PropertyName = "ninjaLocationName" } ) foreach ($mapping in $mappings) { if (-not [string]::IsNullOrWhiteSpace([Environment]::GetEnvironmentVariable($mapping.EnvironmentName, "Process"))) { continue } $value = [string]$clientConfiguration.($mapping.PropertyName) if (-not [string]::IsNullOrWhiteSpace($value)) { [Environment]::SetEnvironmentVariable($mapping.EnvironmentName, $value, "Process") } } } catch { Write-Warning "Could not restore stored NinjaOne context: $($_.Exception.Message)" } } if (-not (Test-Path $appExe)) { throw "Application executable not found: $appExe" } $arguments = @() $configFullPath = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $ConfigPath)) if ($UploadMode -eq "disabled") { $arguments += "scan" } else { $clientConfigFullPath = Resolve-PathLike -PathValue $ClientConfigPath -BasePath $scriptDir $secretFullPath = if ([string]::IsNullOrWhiteSpace($SecretPath)) { "" } else { Resolve-PathLike -PathValue $SecretPath -BasePath $scriptDir } $canUpload = (Test-Path $clientConfigFullPath) -and (-not [string]::IsNullOrWhiteSpace($secretFullPath)) -and (Test-Path $secretFullPath) Restore-NinjaContextFromClientConfiguration -Path $clientConfigFullPath if ($UploadMode -eq "required" -and -not $canUpload) { throw "UploadMode 'required' was set, but client config or protected secret is missing." } if ($canUpload) { $arguments += "scan-and-upload" $arguments += @("--client-config", $clientConfigFullPath, "--secret-path", $secretFullPath) } else { $arguments += "scan" } } $arguments += @( "--lookback-days", $LookbackDays, "--top", $TopCount, "--output", $outputFullPath, "--ninja-output" ) if (Test-Path $configFullPath) { $arguments += @("--config", $configFullPath) } if (-not [string]::IsNullOrWhiteSpace($VulnerabilityCsvPath)) { $vulnerabilityCsvFullPath = Resolve-PathLike -PathValue $VulnerabilityCsvPath -BasePath $scriptDir if (Test-Path $vulnerabilityCsvFullPath) { $arguments += @("--vulnerability-csv", $vulnerabilityCsvFullPath) } } if ($FailOnAttacks) { $arguments += "--fail-on-attacks" } if ($FailOnThreshold) { $arguments += "--fail-on-threshold" } & $appExe @arguments $exitCode = $LASTEXITCODE if (-not (Test-Path $outputFullPath)) { throw "Expected report file was not created: $outputFullPath" } $report = Get-Content $outputFullPath -Raw | ConvertFrom-Json if (-not [string]::IsNullOrWhiteSpace($MirrorRoot)) { Write-Host "Legacy mirror mode enabled." $mirrorRootPath = Resolve-PathLike -PathValue $MirrorRoot -BasePath $scriptDir if (-not (Test-Path $mirrorRootPath)) { New-Item -ItemType Directory -Force -Path $mirrorRootPath | Out-Null } $mirrorPath = Join-Path $mirrorRootPath "$($report.MachineName).json" Copy-Item -Path $outputFullPath -Destination $mirrorPath -Force Write-Host "Mirrored report: $mirrorPath" } Write-Host "" Write-Host "OfficeCom Sentinel runner summary" Write-Host "Machine: $($report.MachineName)" Write-Host "Events: $($report.TotalEvents)" Write-Host "Unique IPs: $($report.UniqueIpCount)" Write-Host "Status: $($report.AlertState)" Write-Host "Reason: $($report.AlertReason)" Write-Host "Base status: $($report.BaseAlertState)" Write-Host "CVE findings: $($report.VulnerabilityCorrelation.TotalCount)" Write-Host "Critical/High CVEs: $($report.VulnerabilityCorrelation.CriticalCount)" Write-Host "Upload mode: $UploadMode" Write-Host "Report: $outputFullPath" if ($report.Errors.Count -gt 0) { Write-Host "Warnings:" foreach ($warningEntry in $report.Errors) { Write-Host "- $warningEntry" } } exit $exitCode