Public/ps1/Configuration/Service/Install-ApprxrService.ps1

<#
.SYNOPSIS
    Installs Apprxr as a Windows service using NSSM (Non-Sucking Service Manager).
 
.DESCRIPTION
    Downloads and extracts NSSM to the Apprxr configuration folder if not already present. Configures a Windows service to run Apprxr as a background service using PowerShell and NSSM. The service name and entrypoint can be extended with a custom string using the NameExtension parameter. If NameExtension is provided, it is appended to the service name and Start-Apprxr command, and saved to configuration for consistent service management by other Apprxr service commands.
 
.PARAMETER NameExtension
    Optional. A string to append to the service name and Start-Apprxr entrypoint. If provided, the service will be named 'ApprxrService<NameExtension>' and will run 'Start-Apprxr<NameExtension>'. This value is also saved to configuration for use by other service management commands.
 
.EXAMPLE
    Install-ApprxrService
    # Installs the service as 'ApprxrService' running 'Start-Apprxr' from the Apprxr module.
 
.EXAMPLE
    Install-ApprxrService -NameExtension 'Test'
    # Installs the service as 'ApprxrServiceTest' running 'Start-ApprxrTest', and saves 'Test' as the ServiceNameExtension in configuration.
 
.EXAMPLE
    Install-ApprxrService -NameExtension 'Prod'
    # Installs the service as 'ApprxrServiceProd' running 'Start-ApprxrProd'.
 
.NOTES
    - Requires administrative privileges to install a Windows service.
    - NSSM is downloaded from https://nssm.cc/release/nssm-2.24.zip if not present.
    - The service will run PowerShell with the Apprxr module imported and execute the Start-Apprxr* command.
    - The NameExtension value is saved to configuration for use by Start/Stop/Remove/Restart-ApprxrService commands.
    - If NSSM extraction fails, the script will throw an error.
#>

function Install-ApprxrService {

    [CmdletBinding()]
    param(
        [string]$NameExtension
    )     
    
    # Check for administrative privileges
    $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
    if (-not $isAdmin) {
        throw 'Install-ApprxrService must be run as Administrator.'
    }
    $configFolder = Get-ApprxrConfigurationFolder
    $nssmExe = Join-Path $configFolder 'nssm.exe'
    if (-not (Test-Path $nssmExe)) {
        Write-Host "Downloading NSSM..." -ForegroundColor Yellow
        $nssmUrl = 'https://nssm.cc/release/nssm-2.24.zip'
        $zipPath = Join-Path $configFolder 'nssm.zip'
        Invoke-WebRequest -Uri $nssmUrl -OutFile $zipPath
        Add-Type -AssemblyName System.IO.Compression.FileSystem
        [System.IO.Compression.ZipFile]::ExtractToDirectory($zipPath, $configFolder)
        Remove-Item $zipPath
        $nssmExeFound = Get-ChildItem -Path $configFolder -Recurse -Filter nssm.exe | Select-Object -First 1
        if ($nssmExeFound) {
            Copy-Item $nssmExeFound.FullName $nssmExe -Force
        } else {
            throw "NSSM executable not found after extraction."
        }
    }
    $pwshPath = (Get-Command pwsh).Source
    $modulePath = Join-Path $PSScriptRoot '..'
    $modulePath = Join-Path $modulePath '..'
    $modulePath = Join-Path $modulePath '..'
    $modulePath = Join-Path $modulePath 'Apprxr.psm1'
    $modulePath = [System.IO.Path]::GetFullPath($modulePath)
    $serviceSuffix = if ($NameExtension) { "$NameExtension" } else { '' }
    $ServiceName = "ApprxrService$serviceSuffix"
    $startCommand = "Start-Apprxr$serviceSuffix"
    $arguments = "-NoProfile -Command 'Import-Module ''$modulePath''; $startCommand'"
    & $nssmExe install $ServiceName $pwshPath $arguments
    if ($NameExtension) {
        Set-ApprxrConfigurationValue -Key 'ServiceNameExtension' -Value $NameExtension
    }
    Log-Apprxr "Service '$ServiceName' installed to run $startCommand from module using NSSM."
}