From 3a97edd0d5da2e38e16b8bd4856a74522eb49a18 Mon Sep 17 00:00:00 2001 From: henrygd Date: Thu, 1 May 2025 17:40:20 -0400 Subject: [PATCH] add winget support to windows install script --- supplemental/scripts/install-agent.ps1 | 324 +++++++++++++++++++------ 1 file changed, 253 insertions(+), 71 deletions(-) diff --git a/supplemental/scripts/install-agent.ps1 b/supplemental/scripts/install-agent.ps1 index a33ffe2..8a70a29 100644 --- a/supplemental/scripts/install-agent.ps1 +++ b/supplemental/scripts/install-agent.ps1 @@ -2,7 +2,8 @@ param ( [switch]$Elevated, [Parameter(Mandatory=$true)] [string]$Key, - [int]$Port = 45876 + [int]$Port = 45876, + [string]$AgentPath = "" ) # Check if key is provided or empty @@ -15,60 +16,147 @@ if ([string]::IsNullOrWhiteSpace($Key)) { # Stop on first error $ErrorActionPreference = "Stop" +#region Utility Functions + # Function to check if running as admin function Test-Admin { return ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) } -# Non-admin tasks - install Scoop and Scoop apps - Only run if we're not in elevated mode -if (-not $Elevated) { +# Function to check if a command exists +function Test-CommandExists { + param ( + [Parameter(Mandatory=$true)] + [string]$Command + ) + return (Get-Command $Command -ErrorAction SilentlyContinue) +} + +#endregion + +#region Installation Methods + +# Function to install Scoop +function Install-Scoop { + Write-Host "Installing Scoop..." try { - # Check if Scoop is already installed - if (Get-Command scoop -ErrorAction SilentlyContinue) { + Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression + + if (-not (Test-CommandExists "scoop")) { + throw "Failed to install Scoop" + } + Write-Host "Scoop installed successfully." + } + catch { + throw "Failed to install Scoop: $($_.Exception.Message)" + } +} + +# Function to install Git via Scoop +function Install-Git { + if (Test-CommandExists "git") { + Write-Host "Git is already installed." + return + } + + Write-Host "Installing Git..." + scoop install git + + if (-not (Test-CommandExists "git")) { + throw "Failed to install Git" + } +} + +# Function to install NSSM +function Install-NSSM { + param ( + [string]$Method = "Scoop" # Default to Scoop method + ) + + if (Test-CommandExists "nssm") { + Write-Host "NSSM is already installed." + return + } + + Write-Host "Installing NSSM..." + if ($Method -eq "Scoop") { + scoop install nssm + } + elseif ($Method -eq "WinGet") { + winget install -e --id NSSM.NSSM --accept-source-agreements --accept-package-agreements + + # Refresh PATH environment variable to make NSSM available in current session + $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") + } + else { + throw "Unsupported installation method: $Method" + } + + if (-not (Test-CommandExists "nssm")) { + throw "Failed to install NSSM" + } +} + +# Function to install beszel-agent with Scoop +function Install-BeszelAgentWithScoop { + Write-Host "Adding beszel bucket..." + scoop bucket add beszel https://github.com/henrygd/beszel-scoops | Out-Null + + Write-Host "Installing beszel-agent..." + scoop install beszel-agent | Out-Null + + if (-not (Test-CommandExists "beszel-agent")) { + throw "Failed to install beszel-agent" + } + + return $(Join-Path -Path $(scoop prefix beszel-agent) -ChildPath "beszel-agent.exe") +} + +# Function to install beszel-agent with WinGet +function Install-BeszelAgentWithWinGet { + Write-Host "Installing beszel-agent..." + winget install --exact --id henrygd.beszel-agent --accept-source-agreements --accept-package-agreements | Out-Null + + # Refresh PATH environment variable to make beszel-agent available in current session + $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") + + # Find the path to the beszel-agent executable + $agentPath = (Get-Command beszel-agent -ErrorAction SilentlyContinue).Source + + + if (-not $agentPath) { + throw "Could not find beszel-agent executable path after installation" + } + + return $agentPath +} + +# Function to install using Scoop +function Install-WithScoop { + param ( + [string]$Key, + [int]$Port + ) + + try { + # Ensure Scoop is installed + if (-not (Test-CommandExists "scoop")) { + Install-Scoop | Out-Null + } + else { Write-Host "Scoop is already installed." - } else { - Write-Host "Installing Scoop..." - Invoke-RestMethod -Uri https://get.scoop.sh | Invoke-Expression - - if (-not (Get-Command scoop -ErrorAction SilentlyContinue)) { - throw "Failed to install Scoop" - } - } - - # Check if git is already installed - if (Get-Command git -ErrorAction SilentlyContinue) { - Write-Host "Git is already installed." - } else { - Write-Host "Installing Git..." - scoop install git - - if (-not (Get-Command git -ErrorAction SilentlyContinue)) { - throw "Failed to install Git" - } - } - - # Check if nssm is already installed - if (Get-Command nssm -ErrorAction SilentlyContinue) { - Write-Host "NSSM is already installed." - } else { - Write-Host "Installing NSSM..." - scoop install nssm - - if (-not (Get-Command nssm -ErrorAction SilentlyContinue)) { - throw "Failed to install NSSM" - } } - # Add bucket and install agent - Write-Host "Adding beszel bucket..." - scoop bucket add beszel https://github.com/henrygd/beszel-scoops + # Install Git (required for Scoop buckets) + Install-Git | Out-Null - Write-Host "Installing beszel-agent..." - scoop install beszel-agent + # Install NSSM + Install-NSSM -Method "Scoop" | Out-Null - if (-not (Get-Command beszel-agent -ErrorAction SilentlyContinue)) { - throw "Failed to install beszel-agent" - } + # Install beszel-agent + $agentPath = Install-BeszelAgentWithScoop + + return $agentPath } catch { Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red @@ -77,27 +165,48 @@ if (-not $Elevated) { $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") exit 1 } +} - # Check if we need admin privileges for the NSSM part - if (-not (Test-Admin)) { - Write-Host "Admin privileges required for NSSM. Relaunching as admin..." -ForegroundColor Yellow - Write-Host "Check service status with 'nssm status beszel-agent'" - Write-Host "Edit service configuration with 'nssm edit beszel-agent'" +# Function to install using WinGet +function Install-WithWinGet { + param ( + [string]$Key, + [int]$Port + ) + + try { + # Install NSSM + Install-NSSM -Method "WinGet" | Out-Null - # Relaunch the script with the -Elevated switch and pass parameters - Start-Process powershell.exe -Verb RunAs -ArgumentList "-File `"$PSCommandPath`" -Elevated -Key `"$Key`" -Port $Port" - exit + # Install beszel-agent + $agentPath = Install-BeszelAgentWithWinGet + + return $agentPath + } + catch { + Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red + Write-Host "Installation failed. Please check the error message above." -ForegroundColor Red + Write-Host "Press any key to exit..." -ForegroundColor Red + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 1 } } -# Admin tasks - service installation and firewall rules -try { - $agentPath = Join-Path -Path $(scoop prefix beszel-agent) -ChildPath "beszel-agent.exe" - if (-not $agentPath) { - throw "Could not find beszel-agent executable. Make sure it was properly installed." - } +#endregion + +#region Service Configuration + +# Function to install and configure the NSSM service +function Install-NSSMService { + param ( + [Parameter(Mandatory=$true)] + [string]$AgentPath, + [Parameter(Mandatory=$true)] + [string]$Key, + [Parameter(Mandatory=$true)] + [int]$Port + ) - # Install and configure the service Write-Host "Installing beszel-agent service..." # Check if service already exists @@ -112,7 +221,7 @@ try { } } - nssm install beszel-agent $agentPath + nssm install beszel-agent $AgentPath if ($LASTEXITCODE -ne 0) { throw "Failed to install beszel-agent service" } @@ -129,6 +238,14 @@ try { $logFile = "$logDir\beszel-agent.log" nssm set beszel-agent AppStdout $logFile nssm set beszel-agent AppStderr $logFile +} + +# Function to configure firewall rules +function Configure-Firewall { + param ( + [Parameter(Mandatory=$true)] + [int]$Port + ) # Create a firewall rule if it doesn't exist $ruleName = "Allow beszel-agent" @@ -154,7 +271,10 @@ try { Write-Host "Warning: Failed to create firewall rule: $($_.Exception.Message)" -ForegroundColor Yellow Write-Host "You may need to manually create a firewall rule for port $Port." -ForegroundColor Yellow } - +} + +# Function to start and monitor the service +function Start-BeszelAgentService { Write-Host "Starting beszel-agent service..." nssm start beszel-agent $startResult = $LASTEXITCODE @@ -164,22 +284,23 @@ try { Write-Host "NSSM start command returned error code: $startResult" -ForegroundColor Yellow Write-Host "This could be due to 'SERVICE_START_PENDING' state. Checking service status..." - # Allow up to 20 seconds for the service to start, checking every 2 seconds - $maxWaitTime = 20 # seconds + # Allow up to 10 seconds for the service to start, checking every second + $maxWaitTime = 10 # seconds $elapsedTime = 0 $serviceStarted = $false while (-not $serviceStarted -and $elapsedTime -lt $maxWaitTime) { + Start-Sleep -Seconds 1 + $elapsedTime += 1 + $serviceStatus = nssm status beszel-agent if ($serviceStatus -eq "SERVICE_RUNNING") { $serviceStarted = $true - Write-Host "Success! The beszel-agent service is now running properly." -ForegroundColor Green + Write-Host "Success! The beszel-agent service is now running." -ForegroundColor Green } elseif ($serviceStatus -like "*PENDING*") { Write-Host "Service is still starting (status: $serviceStatus)... waiting" -ForegroundColor Yellow - Start-Sleep -Seconds 2 - $elapsedTime += 2 } else { Write-Host "Warning: The service status is '$serviceStatus' instead of 'SERVICE_RUNNING'." -ForegroundColor Yellow @@ -189,7 +310,7 @@ try { } if (-not $serviceStarted) { - Write-Host "Service did not reach running state within $maxWaitTime seconds." -ForegroundColor Yellow + Write-Host "Service did not reach running state." -ForegroundColor Yellow Write-Host "You can check status manually with 'nssm status beszel-agent'" -ForegroundColor Yellow } } else { @@ -197,13 +318,74 @@ try { Write-Host "Success! The beszel-agent service is running properly." -ForegroundColor Green } } -catch { - Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red - Write-Host "Installation failed. Please check the error message above." -ForegroundColor Red + +#endregion + +#region Main Script Execution + +# Non-admin tasks - Only run if we're not in elevated mode +if (-not $Elevated) { + try { + # Determine installation method + $AgentPath = "" + + if (Test-CommandExists "scoop") { + Write-Host "Using Scoop for installation..." + $AgentPath = Install-WithScoop -Key $Key -Port $Port + } + elseif (Test-CommandExists "winget") { + Write-Host "Using WinGet for installation..." + $AgentPath = Install-WithWinGet -Key $Key -Port $Port + } + else { + Write-Host "Neither Scoop nor WinGet is installed. Installing Scoop..." + $AgentPath = Install-WithScoop -Key $Key -Port $Port + } + + # Check if we need admin privileges for the NSSM part + if (-not (Test-Admin)) { + Write-Host "Admin privileges required for NSSM. Relaunching as admin..." -ForegroundColor Yellow + Write-Host "Check service status with 'nssm status beszel-agent'" + Write-Host "Edit service configuration with 'nssm edit beszel-agent'" + + # Relaunch the script with the -Elevated switch and pass parameters + Start-Process powershell.exe -Verb RunAs -ArgumentList "-File `"$PSCommandPath`" -Elevated -Key `"$Key`" -Port $Port -AgentPath `"$AgentPath`"" + exit + } + } + catch { + Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red + Write-Host "Installation failed. Please check the error message above." -ForegroundColor Red + Write-Host "Press any key to exit..." -ForegroundColor Red + $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") + exit 1 + } } -# Pause to see results before exit if this is an elevated window +# Admin tasks - service installation and firewall rules if ($Elevated) { + try { + if (-not $AgentPath) { + throw "Could not find beszel-agent executable. Make sure it was properly installed." + } + + # Install the service + Install-NSSMService -AgentPath $AgentPath -Key $Key -Port $Port + + # Configure firewall + Configure-Firewall -Port $Port + + # Start the service + Start-BeszelAgentService + } + catch { + Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red + Write-Host "Installation failed. Please check the error message above." -ForegroundColor Red + } + + # Pause to see results before exit if this is an elevated window Write-Host "Press any key to exit..." -ForegroundColor Cyan $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown") } + +#endregion