nebula-domain-join/install-nebula.ps1
2026-02-12 13:55:38 -08:00

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
}