187 lines
5.8 KiB
PowerShell
187 lines
5.8 KiB
PowerShell
#Requires -RunAsAdministrator
|
|
|
|
$ErrorActionPreference = "Stop"
|
|
|
|
# Verify running as Administrator
|
|
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
|
$principal = [Security.Principal.WindowsPrincipal]$identity
|
|
if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)) {
|
|
Write-Error "This script must be run as a machine Administrator."
|
|
exit 1
|
|
}
|
|
|
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
|
$InstallDir = "C:\Program Files\Nebula"
|
|
$ConfigPath = "$InstallDir\config.yml"
|
|
$ExpectedBinPath = "`"$InstallDir\nebula.exe`" -service run -config `"$ConfigPath`""
|
|
|
|
# --- Validate all required files before making any changes ---
|
|
|
|
$missing = @()
|
|
|
|
# Per-host files expected in the working directory
|
|
$HostFiles = @("config.yml", "host.crt", "host.key")
|
|
foreach ($file in $HostFiles) {
|
|
if (-not (Test-Path (Join-Path $PWD $file))) {
|
|
$missing += "$file (expected in working directory: $PWD)"
|
|
}
|
|
}
|
|
|
|
# Package files expected alongside the script
|
|
$PackageFiles = @("ca.crt", "nebula.exe")
|
|
foreach ($file in $PackageFiles) {
|
|
if (-not (Test-Path (Join-Path $ScriptDir $file))) {
|
|
$missing += "$file (expected in script directory: $ScriptDir)"
|
|
}
|
|
}
|
|
|
|
if (-not (Test-Path (Join-Path $ScriptDir "dist"))) {
|
|
$missing += "dist\ (expected in script directory: $ScriptDir)"
|
|
}
|
|
|
|
if ($missing.Count -gt 0) {
|
|
Write-Error "Missing required files:`n - $($missing -join "`n - ")"
|
|
exit 1
|
|
}
|
|
|
|
# --- Check if already installed and running correctly ---
|
|
|
|
$existing = Get-Service -Name "nebula" -ErrorAction SilentlyContinue
|
|
if ($existing) {
|
|
$svcConfig = sc.exe qc nebula 2>&1 | Out-String
|
|
$correctBinary = $svcConfig -match [regex]::Escape($ExpectedBinPath)
|
|
|
|
if ($existing.Status -eq "Running" -and $correctBinary) {
|
|
# Compare all source files against installed files by hash
|
|
$allMatch = $true
|
|
foreach ($file in $PackageFiles) {
|
|
$src = (Get-FileHash (Join-Path $ScriptDir $file)).Hash
|
|
$dst = (Get-FileHash (Join-Path $InstallDir $file) -ErrorAction SilentlyContinue).Hash
|
|
if ($src -ne $dst) { $allMatch = $false; break }
|
|
}
|
|
if ($allMatch) {
|
|
foreach ($file in $HostFiles) {
|
|
$src = (Get-FileHash (Join-Path $PWD $file)).Hash
|
|
$dst = (Get-FileHash (Join-Path $InstallDir $file) -ErrorAction SilentlyContinue).Hash
|
|
if ($src -ne $dst) { $allMatch = $false; break }
|
|
}
|
|
}
|
|
|
|
if ($allMatch) {
|
|
Write-Host "Nebula is already installed and running with matching files. No changes needed."
|
|
exit 0
|
|
}
|
|
|
|
Write-Host "Nebula is running but files have changed. Reinstalling..."
|
|
}
|
|
|
|
Write-Host "Stopping existing Nebula service..."
|
|
if ($existing.Status -eq "Running") {
|
|
sc.exe stop nebula | Out-Null
|
|
# Wait for the service to fully stop
|
|
$timeout = 10
|
|
while ($timeout -gt 0) {
|
|
$svc = Get-Service -Name "nebula" -ErrorAction SilentlyContinue
|
|
if ($svc.Status -eq "Stopped") { break }
|
|
Start-Sleep -Seconds 1
|
|
$timeout--
|
|
}
|
|
if ($timeout -eq 0) {
|
|
Write-Error "Timed out waiting for Nebula service to stop."
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
sc.exe delete nebula | Out-Null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "Failed to remove existing Nebula service. A reboot may be required if it is marked for deletion."
|
|
exit 1
|
|
}
|
|
Start-Sleep -Seconds 1
|
|
}
|
|
|
|
# --- Create install directory ---
|
|
|
|
if (-not (Test-Path $InstallDir)) {
|
|
try {
|
|
New-Item -ItemType Directory -Path $InstallDir | Out-Null
|
|
} catch {
|
|
Write-Error "Failed to create install directory: $_"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
# --- Copy files ---
|
|
|
|
try {
|
|
Write-Host "Copying package files..."
|
|
Copy-Item (Join-Path $ScriptDir "ca.crt") $InstallDir -Force
|
|
Copy-Item (Join-Path $ScriptDir "nebula.exe") $InstallDir -Force
|
|
Copy-Item (Join-Path $ScriptDir "dist") $InstallDir -Recurse -Force
|
|
|
|
Write-Host "Copying host files..."
|
|
foreach ($file in $HostFiles) {
|
|
Copy-Item (Join-Path $PWD $file) $InstallDir -Force
|
|
}
|
|
} catch {
|
|
Write-Error "Failed to copy files: $_"
|
|
exit 1
|
|
}
|
|
|
|
# --- Verify files landed in install directory ---
|
|
|
|
$AllFiles = $PackageFiles + $HostFiles
|
|
foreach ($file in $AllFiles) {
|
|
if (-not (Test-Path (Join-Path $InstallDir $file))) {
|
|
Write-Error "File copy verification failed: $file not found in $InstallDir"
|
|
exit 1
|
|
}
|
|
}
|
|
|
|
if (-not (Test-Path (Join-Path $InstallDir "dist"))) {
|
|
Write-Error "File copy verification failed: dist\ not found in $InstallDir"
|
|
exit 1
|
|
}
|
|
|
|
# --- Install and configure service ---
|
|
|
|
Write-Host "Installing Nebula service..."
|
|
& "$InstallDir\nebula.exe" -service install -config "$ConfigPath"
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "Failed to install Nebula service."
|
|
exit 1
|
|
}
|
|
|
|
# Wait for real network connectivity before starting, not just the TCP/IP stack
|
|
sc.exe config nebula depend= Tcpip/NlaSvc | Out-Null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "Failed to set service dependencies."
|
|
exit 1
|
|
}
|
|
|
|
# Delayed start gives Wi-Fi/Ethernet time to fully associate and get an IP
|
|
sc.exe config nebula start= delayed-auto | Out-Null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "Failed to set delayed-auto start."
|
|
exit 1
|
|
}
|
|
|
|
# --- Start and verify ---
|
|
|
|
Write-Host "Starting Nebula service..."
|
|
sc.exe start nebula | Out-Null
|
|
if ($LASTEXITCODE -ne 0) {
|
|
Write-Error "Failed to start Nebula service. Check Event Viewer (Application log, source 'nebula')."
|
|
exit 1
|
|
}
|
|
|
|
Start-Sleep -Seconds 3
|
|
|
|
$svc = Get-Service -Name "nebula"
|
|
if ($svc.Status -eq "Running") {
|
|
Write-Host "Nebula service is running."
|
|
} else {
|
|
Write-Error "Nebula service failed to start. Check Event Viewer (Application log, source 'nebula')."
|
|
exit 1
|
|
}
|