104 lines
6.6 KiB
PowerShell
104 lines
6.6 KiB
PowerShell
param()
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
$scriptPath = $MyInvocation.MyCommand.Path
|
|
$scriptDirectory = Split-Path -Parent $scriptPath
|
|
$packageRoot = if ((Split-Path -Leaf $scriptDirectory) -ieq "scripts") { Split-Path -Parent $scriptDirectory } else { $scriptDirectory }
|
|
$installRoot = Join-Path ${env:ProgramFiles} "OCSentinel"
|
|
$appRoot = Join-Path $installRoot "app"
|
|
$configRoot = Join-Path $installRoot "config"
|
|
$reportsRoot = Join-Path $installRoot "reports"
|
|
$samplesRoot = Join-Path $installRoot "samples"
|
|
$scriptRoot = Join-Path $installRoot "scripts"
|
|
$versionFile = Join-Path $packageRoot "VERSION.txt"
|
|
$version = if (Test-Path $versionFile) { (Get-Content $versionFile -Raw).Trim() } else { "1.0.0" }
|
|
|
|
Write-Host "Installing OfficeCom Sentinel $version to $installRoot"
|
|
|
|
New-Item -ItemType Directory -Force -Path $appRoot, $configRoot, $reportsRoot, $samplesRoot, $scriptRoot | Out-Null
|
|
|
|
Copy-Item -Path (Join-Path $packageRoot "app\OCSentinelCli.exe") -Destination $appRoot -Force
|
|
if (Test-Path (Join-Path $packageRoot "app\OCSentinelCli.pdb")) {
|
|
Copy-Item -Path (Join-Path $packageRoot "app\OCSentinelCli.pdb") -Destination $appRoot -Force
|
|
}
|
|
Copy-Item -Path (Join-Path $packageRoot "config\ocsentinel-settings.example.json") -Destination (Join-Path $configRoot "ocsentinel-settings.example.json") -Force
|
|
if (Test-Path (Join-Path $packageRoot "config\ocsentinel-client.example.json")) {
|
|
Copy-Item -Path (Join-Path $packageRoot "config\ocsentinel-client.example.json") -Destination (Join-Path $configRoot "ocsentinel-client.example.json") -Force
|
|
}
|
|
if (Test-Path (Join-Path $packageRoot "config\ocsentinel-client.dev.example.json")) {
|
|
Copy-Item -Path (Join-Path $packageRoot "config\ocsentinel-client.dev.example.json") -Destination (Join-Path $configRoot "ocsentinel-client.dev.example.json") -Force
|
|
}
|
|
Copy-Item -Path (Join-Path $packageRoot "samples\ninja-vulnerability-export.example.csv") -Destination (Join-Path $samplesRoot "ninja-vulnerability-export.example.csv") -Force
|
|
Copy-Item -Path (Join-Path $packageRoot "scripts\run-ocsentinel.ps1") -Destination $scriptRoot -Force
|
|
Copy-Item -Path (Join-Path $packageRoot "scripts\run-ocsentinel-monitor.ps1") -Destination $scriptRoot -Force
|
|
Copy-Item -Path (Join-Path $packageRoot "scripts\run-ocsentinel-scheduled.ps1") -Destination $scriptRoot -Force
|
|
if (Test-Path (Join-Path $packageRoot "scripts\protect-ocsentinel-secret.ps1")) {
|
|
Copy-Item -Path (Join-Path $packageRoot "scripts\protect-ocsentinel-secret.ps1") -Destination $scriptRoot -Force
|
|
}
|
|
if (Test-Path (Join-Path $packageRoot "scripts\update-ocsentinel.ps1")) {
|
|
Copy-Item -Path (Join-Path $packageRoot "scripts\update-ocsentinel.ps1") -Destination $scriptRoot -Force
|
|
}
|
|
Copy-Item -Path (Join-Path $packageRoot "scripts\uninstall-ocsentinel.ps1") -Destination $scriptRoot -Force
|
|
|
|
$mainConfig = Join-Path $configRoot "ocsentinel-settings.json"
|
|
$exampleConfig = Join-Path $configRoot "ocsentinel-settings.example.json"
|
|
if (-not (Test-Path $mainConfig) -and (Test-Path $exampleConfig)) {
|
|
Copy-Item $exampleConfig $mainConfig -Force
|
|
}
|
|
|
|
$clientMainConfig = Join-Path $configRoot "ocsentinel-client.json"
|
|
$clientExampleConfig = Join-Path $configRoot "ocsentinel-client.example.json"
|
|
if (-not (Test-Path $clientMainConfig) -and (Test-Path $clientExampleConfig)) {
|
|
Copy-Item $clientExampleConfig $clientMainConfig -Force
|
|
}
|
|
|
|
$uninstallScript = Join-Path $scriptRoot "uninstall-ocsentinel.ps1"
|
|
$uninstallCommand = "powershell.exe -ExecutionPolicy Bypass -File `"$uninstallScript`""
|
|
$uninstallKey = "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\OCSentinel"
|
|
|
|
if (-not (Test-Path $uninstallKey)) {
|
|
New-Item -Path $uninstallKey -Force | Out-Null
|
|
}
|
|
|
|
Set-ItemProperty -Path $uninstallKey -Name "DisplayName" -Value "OfficeCom Sentinel"
|
|
Set-ItemProperty -Path $uninstallKey -Name "DisplayVersion" -Value $version
|
|
Set-ItemProperty -Path $uninstallKey -Name "Publisher" -Value "OfficeCom"
|
|
Set-ItemProperty -Path $uninstallKey -Name "InstallLocation" -Value $installRoot
|
|
Set-ItemProperty -Path $uninstallKey -Name "UninstallString" -Value $uninstallCommand
|
|
Set-ItemProperty -Path $uninstallKey -Name "QuietUninstallString" -Value $uninstallCommand
|
|
Set-ItemProperty -Path $uninstallKey -Name "NoModify" -Value 1 -Type DWord
|
|
Set-ItemProperty -Path $uninstallKey -Name "NoRepair" -Value 1 -Type DWord
|
|
|
|
$scheduledScript = Join-Path $scriptRoot "run-ocsentinel-scheduled.ps1"
|
|
$taskPrincipal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -LogonType ServiceAccount -RunLevel Highest
|
|
$taskSettings = New-ScheduledTaskSettingsSet -StartWhenAvailable -ExecutionTimeLimit (New-TimeSpan -Minutes 30) -MultipleInstances IgnoreNew
|
|
|
|
# Spread fleet uploads across the early-morning window while keeping each device's slot stable.
|
|
$machineGuid = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Cryptography" -Name "MachineGuid").MachineGuid
|
|
$guidBytes = [Text.Encoding]::UTF8.GetBytes([string]$machineGuid)
|
|
$sha256 = [Security.Cryptography.SHA256]::Create()
|
|
try {
|
|
$slotHash = $sha256.ComputeHash($guidBytes)
|
|
}
|
|
finally {
|
|
$sha256.Dispose()
|
|
}
|
|
$dailySlotMinutes = [BitConverter]::ToUInt32($slotHash, 0) % 180
|
|
$dailyRunAt = (Get-Date -Hour 4 -Minute 0 -Second 0).AddMinutes($dailySlotMinutes)
|
|
|
|
$dailyAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scheduledScript`" -Kind daily" -WorkingDirectory $scriptRoot
|
|
$dailyTrigger = New-ScheduledTaskTrigger -Daily -At $dailyRunAt
|
|
Register-ScheduledTask -TaskName "OCSentinel Daily Scan" -Action $dailyAction -Trigger $dailyTrigger -Principal $taskPrincipal -Settings $taskSettings -Description "OfficeCom Sentinel daily signed scan and upload." -Force | Out-Null
|
|
|
|
$burstAction = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -ExecutionPolicy Bypass -File `"$scheduledScript`" -Kind burst" -WorkingDirectory $scriptRoot
|
|
$burstTrigger = New-ScheduledTaskTrigger -Once -At (Get-Date).AddMinutes(2) -RepetitionInterval (New-TimeSpan -Minutes 5) -RepetitionDuration (New-TimeSpan -Days 3650)
|
|
Register-ScheduledTask -TaskName "OCSentinel Burst Check" -Action $burstAction -Trigger $burstTrigger -Principal $taskPrincipal -Settings $taskSettings -Description "OfficeCom Sentinel burst check; scans only when Ninja field ocsentinelburst is enabled." -Force | Out-Null
|
|
|
|
Write-Host "Installation complete."
|
|
Write-Host "Main path: $installRoot"
|
|
Write-Host "Runner: $(Join-Path $scriptRoot 'run-ocsentinel.ps1')"
|
|
Write-Host "Monitor: $(Join-Path $scriptRoot 'run-ocsentinel-monitor.ps1')"
|
|
Write-Host "Updater: $(Join-Path $scriptRoot 'update-ocsentinel.ps1')"
|
|
Write-Host "Schedule: Daily scan at $($dailyRunAt.ToString('HH:mm')) (deterministic 04:00-06:59 slot); burst check every 5 minutes."
|