214 lines
6.2 KiB
PowerShell
214 lines
6.2 KiB
PowerShell
param(
|
|
[int]$LookbackDays = 7,
|
|
[int]$TopCount = 10,
|
|
[string]$OutputPath = "..\reports\ocsentinel-summary.json",
|
|
[string]$ConfigPath = "..\config\ocsentinel-settings.json",
|
|
[string]$VulnerabilityCsvPath = "",
|
|
[string]$MirrorRoot = "",
|
|
[ValidateSet("status", "attack-only", "cve-critical", "attack-plus-cve")]
|
|
[string]$Mode = "status"
|
|
)
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
|
|
$runnerScript = Join-Path $scriptDir "run-ocsentinel.ps1"
|
|
$outputFullPath = [System.IO.Path]::GetFullPath((Join-Path $scriptDir $OutputPath))
|
|
|
|
$script:NinjaFieldBackend = $null
|
|
$script:NinjaCliPath = "C:\ProgramData\NinjaRMMAgent\ninjarmm-cli.exe"
|
|
|
|
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 Initialize-NinjaFieldWriter {
|
|
if ($null -ne $script:NinjaFieldBackend) {
|
|
return
|
|
}
|
|
|
|
if (Get-Command -Name "Ninja-Property-Set" -ErrorAction SilentlyContinue) {
|
|
$script:NinjaFieldBackend = "powershell"
|
|
return
|
|
}
|
|
|
|
if (Test-Path $script:NinjaCliPath) {
|
|
$script:NinjaFieldBackend = "cli"
|
|
return
|
|
}
|
|
|
|
$script:NinjaFieldBackend = "none"
|
|
}
|
|
|
|
function Set-NinjaCustomFieldValue {
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[string]$Name,
|
|
[AllowEmptyString()]
|
|
[string]$Value
|
|
)
|
|
|
|
Initialize-NinjaFieldWriter
|
|
|
|
switch ($script:NinjaFieldBackend) {
|
|
"powershell" {
|
|
Ninja-Property-Set $Name $Value | Out-Null
|
|
return $true
|
|
}
|
|
"cli" {
|
|
& $script:NinjaCliPath set $Name $Value | Out-Null
|
|
return $LASTEXITCODE -eq 0
|
|
}
|
|
default {
|
|
return $false
|
|
}
|
|
}
|
|
}
|
|
|
|
function Publish-NinjaCustomFields {
|
|
param(
|
|
[Parameter(Mandatory)]
|
|
[pscustomobject]$Report,
|
|
[Parameter(Mandatory)]
|
|
[string]$Mode,
|
|
[Parameter(Mandatory)]
|
|
[bool]$Triggered,
|
|
[Parameter(Mandatory)]
|
|
[string]$Reason
|
|
)
|
|
|
|
Initialize-NinjaFieldWriter
|
|
if ($script:NinjaFieldBackend -eq "none") {
|
|
Write-Host "Ninja custom fields: skipped (Ninja field writer not available)."
|
|
return
|
|
}
|
|
|
|
$generatedAtUtc = ""
|
|
if ($Report.GeneratedAtLocal) {
|
|
try {
|
|
$generatedAtUtc = ([DateTimeOffset]$Report.GeneratedAtLocal).ToUniversalTime().ToString("o")
|
|
}
|
|
catch {
|
|
$generatedAtUtc = [string]$Report.GeneratedAtLocal
|
|
}
|
|
}
|
|
|
|
$fieldValues = [ordered]@{
|
|
"ocsentinelstatus" = [string]$Report.AlertState
|
|
"ocsentinelreason" = $Reason
|
|
"ocsentinelbasestatus" = [string]$Report.BaseAlertState
|
|
"ocsentinelevents" = [string]([int]$Report.TotalEvents)
|
|
"ocsentineluniqueips" = [string]([int]$Report.UniqueIpCount)
|
|
"ocsentinelcvecritical" = [string]([int]$Report.VulnerabilityCorrelation.CriticalCount)
|
|
"ocsentinelcvetotal" = [string]([int]$Report.VulnerabilityCorrelation.TotalCount)
|
|
"ocsentinelmode" = $Mode
|
|
"ocsentineltriggered" = $Triggered.ToString().ToLowerInvariant()
|
|
"ocsentinellastscanutc" = $generatedAtUtc
|
|
}
|
|
|
|
$updated = 0
|
|
foreach ($entry in $fieldValues.GetEnumerator()) {
|
|
try {
|
|
if (Set-NinjaCustomFieldValue -Name $entry.Key -Value $entry.Value) {
|
|
$updated++
|
|
}
|
|
}
|
|
catch {
|
|
Write-Warning "Failed to set Ninja custom field '$($entry.Key)': $($_.Exception.Message)"
|
|
}
|
|
}
|
|
|
|
Write-Host "Ninja custom fields: updated $updated field(s) via $script:NinjaFieldBackend."
|
|
}
|
|
|
|
$runnerArgs = @(
|
|
"-ExecutionPolicy", "Bypass",
|
|
"-File", $runnerScript,
|
|
"-LookbackDays", $LookbackDays,
|
|
"-TopCount", $TopCount,
|
|
"-OutputPath", $OutputPath,
|
|
"-ConfigPath", $ConfigPath
|
|
)
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($VulnerabilityCsvPath)) {
|
|
$runnerArgs += @("-VulnerabilityCsvPath", $VulnerabilityCsvPath)
|
|
}
|
|
|
|
if (-not [string]::IsNullOrWhiteSpace($MirrorRoot)) {
|
|
$runnerArgs += @("-MirrorRoot", (Resolve-PathLike -PathValue $MirrorRoot -BasePath $scriptDir))
|
|
}
|
|
|
|
$null = & powershell @runnerArgs
|
|
$runnerExitCode = $LASTEXITCODE
|
|
|
|
if (-not (Test-Path $outputFullPath)) {
|
|
throw "Expected report file was not created: $outputFullPath"
|
|
}
|
|
|
|
$report = Get-Content $outputFullPath -Raw | ConvertFrom-Json
|
|
|
|
$status = [string]$report.AlertState
|
|
$baseStatus = [string]$report.BaseAlertState
|
|
$events = [int]$report.TotalEvents
|
|
$uniqueIps = [int]$report.UniqueIpCount
|
|
$criticalCves = [int]$report.VulnerabilityCorrelation.CriticalCount
|
|
$totalCves = [int]$report.VulnerabilityCorrelation.TotalCount
|
|
|
|
$monitorTriggered = $false
|
|
$monitorReason = ""
|
|
|
|
switch ($Mode) {
|
|
"status" {
|
|
$monitorTriggered = $status -ne "ok"
|
|
$monitorReason = "Final status is $status. $($report.AlertReason)"
|
|
}
|
|
"attack-only" {
|
|
$monitorTriggered = $baseStatus -ne "ok"
|
|
$monitorReason = "Base attack status is $baseStatus. $($report.BaseAlertReason)"
|
|
}
|
|
"cve-critical" {
|
|
$monitorTriggered = $criticalCves -gt 0
|
|
$monitorReason = "Critical/high CVE count is $criticalCves out of total CVEs $totalCves."
|
|
}
|
|
"attack-plus-cve" {
|
|
$monitorTriggered = ($events -gt 0 -and $criticalCves -gt 0)
|
|
$monitorReason = "Attack events=$events and critical/high CVEs=$criticalCves."
|
|
}
|
|
}
|
|
|
|
Publish-NinjaCustomFields -Report $report -Mode $Mode -Triggered $monitorTriggered -Reason $monitorReason
|
|
|
|
Write-Host ""
|
|
Write-Host "OfficeCom Sentinel monitor mode: $Mode"
|
|
Write-Host "Triggered: $monitorTriggered"
|
|
Write-Host "Reason: $monitorReason"
|
|
Write-Host "Status: $status"
|
|
Write-Host "Base status: $baseStatus"
|
|
Write-Host "Events: $events"
|
|
Write-Host "Unique IPs: $uniqueIps"
|
|
Write-Host "Critical/High CVEs: $criticalCves"
|
|
Write-Host "Total CVEs: $totalCves"
|
|
Write-Host "Report: $outputFullPath"
|
|
Write-Host "Runner exit code: $runnerExitCode"
|
|
|
|
if ($monitorTriggered) {
|
|
exit 1
|
|
}
|
|
|
|
exit 0
|