param( [int]$LookbackDays = 7, [int]$TopCount = 10, [string]$OutputPath = ".\reports\ocsentinel-summary.json", [string]$ConfigPath = ".\config\ocsentinel-settings.example.json", [string]$ClientConfigPath = ".\config\ocsentinel-client.example.json", [string]$SecretPath = "", [string]$VulnerabilityCsvPath = "", [string]$MirrorRoot = "", [ValidateSet("disabled", "auto", "required")] [string]$UploadMode = "auto", [switch]$FailOnAttacks, [switch]$FailOnThreshold ) $ErrorActionPreference = "Stop" $repoRoot = Split-Path -Parent $PSScriptRoot $projectPath = Join-Path $repoRoot "src\AttackTracerNinjaCli\AttackTracerNinjaCli.csproj" $outputFullPath = [System.IO.Path]::GetFullPath((Join-Path $repoRoot $OutputPath)) $buildOutputDir = Join-Path $repoRoot "src\AttackTracerNinjaCli\bin\Debug\net10.0" $dllPath = Join-Path $buildOutputDir "OCSentinelCli.dll" 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)) } $arguments = @( $dllPath ) $configFullPath = [System.IO.Path]::GetFullPath((Join-Path $repoRoot $ConfigPath)) if ($UploadMode -eq "disabled") { $arguments += "scan" } else { $clientConfigFullPath = Resolve-PathLike -PathValue $ClientConfigPath -BasePath $repoRoot $secretFullPath = if ([string]::IsNullOrWhiteSpace($SecretPath)) { "" } else { Resolve-PathLike -PathValue $SecretPath -BasePath $repoRoot } $canUpload = (Test-Path $clientConfigFullPath) -and (-not [string]::IsNullOrWhiteSpace($secretFullPath)) -and (Test-Path $secretFullPath) 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 = [System.IO.Path]::GetFullPath((Join-Path $repoRoot $VulnerabilityCsvPath)) if (Test-Path $vulnerabilityCsvFullPath) { $arguments += @("--vulnerability-csv", $vulnerabilityCsvFullPath) } } if ($FailOnAttacks) { $arguments += "--fail-on-attacks" } if ($FailOnThreshold) { $arguments += "--fail-on-threshold" } $null = & dotnet build $projectPath if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } if (-not (Test-Path $dllPath)) { throw "Expected compiled DLL was not created: $dllPath" } & dotnet @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 $repoRoot 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 wrapper 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