From 7555e92aac1e208e031bcc56d23295ec6f26654e Mon Sep 17 00:00:00 2001 From: OfficeCom Codex Date: Sat, 25 Jul 2026 21:01:02 +0200 Subject: [PATCH] Add one-time NinjaOne installation script --- scripts/install-ocsentinel-ninja-once.ps1 | 70 +++++++++++++++++++++++ 1 file changed, 70 insertions(+) create mode 100644 scripts/install-ocsentinel-ninja-once.ps1 diff --git a/scripts/install-ocsentinel-ninja-once.ps1 b/scripts/install-ocsentinel-ninja-once.ps1 new file mode 100644 index 0000000..cdb7980 --- /dev/null +++ b/scripts/install-ocsentinel-ninja-once.ps1 @@ -0,0 +1,70 @@ +[CmdletBinding()] +param( + [string]$ManifestUrl = "https://gitea.officecom.cloud/officecom/oc-sentinel/raw/main/release/stable/version.json", + [string]$WebhookUrl = "", + [string]$SecretValue = "" +) + +$ErrorActionPreference = "Stop" +$ProgressPreference = "SilentlyContinue" +[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 + +function Get-NinjaValue { + param([Parameter(Mandatory)][string]$Name) + + $value = [Environment]::GetEnvironmentVariable($Name, "Process") + return if ($null -eq $value) { "" } else { $value.Trim() } +} + +if ([string]::IsNullOrWhiteSpace($WebhookUrl)) { $WebhookUrl = Get-NinjaValue -Name "webhookurl" } +if ([string]::IsNullOrWhiteSpace($SecretValue)) { $SecretValue = Get-NinjaValue -Name "secretvalue" } +if ([string]::IsNullOrWhiteSpace($WebhookUrl) -or [string]::IsNullOrWhiteSpace($SecretValue)) { + throw "WebhookUrl and SecretValue must be set as NinjaOne script variables." +} + +$manifest = Invoke-RestMethod -Method Get -Uri $ManifestUrl -TimeoutSec 60 +if ([string]::IsNullOrWhiteSpace($manifest.artifactUrl) -or [string]::IsNullOrWhiteSpace($manifest.sha256)) { + throw "The release manifest is incomplete." +} + +$downloadRoot = Join-Path $env:ProgramData ("OCSentinel\\install-" + [Guid]::NewGuid().ToString("N")) +$zipPath = Join-Path $downloadRoot "OCSentinelClient.zip" +$extractPath = Join-Path $downloadRoot "payload" + +try { + New-Item -ItemType Directory -Force -Path $extractPath | Out-Null + Write-Host "Downloading OCSentinel $($manifest.version)." + Invoke-WebRequest -Uri $manifest.artifactUrl -OutFile $zipPath -TimeoutSec 300 + $actualHash = (Get-FileHash -LiteralPath $zipPath -Algorithm SHA256).Hash.ToLowerInvariant() + if ($actualHash -ne ([string]$manifest.sha256).ToLowerInvariant()) { + throw "Release package SHA-256 validation failed." + } + + Expand-Archive -LiteralPath $zipPath -DestinationPath $extractPath -Force + $installer = Get-ChildItem -Path $extractPath -Recurse -Filter "install-ocsentinel.ps1" | Select-Object -First 1 + if ($null -eq $installer) { throw "The release package does not contain the installer." } + + & powershell.exe -NoProfile -ExecutionPolicy Bypass -File $installer.FullName + if ($LASTEXITCODE -ne 0) { throw "Installer failed with code $LASTEXITCODE" } +} +finally { + if (Test-Path -LiteralPath $downloadRoot) { Remove-Item -LiteralPath $downloadRoot -Recurse -Force } +} + +$installRoot = Join-Path $env:ProgramFiles "OCSentinel" +$configPath = Join-Path $installRoot "config\ocsentinel-client.json" +$secretScript = Join-Path $installRoot "scripts\protect-ocsentinel-secret.ps1" +$monitorScript = Join-Path $installRoot "scripts\run-ocsentinel-monitor.ps1" +$secretPath = "C:\ProgramData\OCSentinel\secrets\ocsentinel-upload-secret.dat" + +$config = Get-Content -LiteralPath $configPath -Raw | ConvertFrom-Json +$config.n8nWebhookUrl = $WebhookUrl +$config.environment = "production" +$config | ConvertTo-Json -Depth 10 | Set-Content -LiteralPath $configPath -Encoding UTF8 + +& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $secretScript -SecretValue $SecretValue +if ($LASTEXITCODE -ne 0) { throw "Writing the protected upload secret failed with code $LASTEXITCODE" } + +Write-Host "Running initial signed scan and upload." +& powershell.exe -NoProfile -ExecutionPolicy Bypass -File $monitorScript -Mode status -ClientConfigPath $configPath -SecretPath $secretPath -UploadMode required +exit $LASTEXITCODE