NetTrace-ServiceRunner.ps1

#Requires -Version 5.1
#Requires -RunAsAdministrator

<#
.SYNOPSIS
    NetTrace Service Runner and Management Script
 
.DESCRIPTION
    This script provides management functionality for the NetTrace Windows Service using NSSM (Non-Sucking Service Manager).
    It handles service installation, configuration, starting, stopping, and status monitoring for true Windows Service persistence.
     
    Version 1.3.7 includes comprehensive documentation enhancements:
    - Fixed NSSM installation to use persistent location instead of temp directory
    - Simplified service configuration using batch file wrapper
    - Enhanced service validation and error handling
    - Improved parameter passing to avoid complex escaping issues
    - FIXED: NSSM path handling issue that was causing service installation failures
 
.PARAMETER Install
    Installs the NetTrace Windows Service using NSSM
 
.PARAMETER Uninstall
    Uninstalls the NetTrace Windows Service
 
.PARAMETER Start
    Starts the NetTrace Windows Service with specified parameters
 
.PARAMETER Stop
    Stops the NetTrace Windows Service
 
.PARAMETER Status
    Shows the current status of the NetTrace Windows Service
 
.PARAMETER Path
    Directory path where trace files will be stored (required for Start)
 
.PARAMETER MaxFiles
    Maximum number of trace files to maintain (required for Start)
 
.PARAMETER MaxSizeMB
    Maximum size of each trace file in MB (required for Start)
 
.PARAMETER LogOutput
    Enable netsh output logging (optional)
 
.PARAMETER EnableLogging
    Enable detailed activity logging (optional)
 
.NOTES
    File Name : NetTrace-ServiceRunner.ps1
    Version : 1.3.7
    Author : Naveed Khan
    Company : Hogwarts
    Copyright : (c) 2025 Naveed Khan. All rights reserved.
    License : MIT License
    Prerequisite : Windows 10/11 with Administrator privileges
    Requires : PowerShell 5.1 or PowerShell 7+
    Dependencies : NSSM (Non-Sucking Service Manager) - automatically downloaded
 
.EXAMPLE
    .\NetTrace-ServiceRunner.ps1 -Install
    Installs the NetTrace Windows Service using NSSM
 
.EXAMPLE
    .\NetTrace-ServiceRunner.ps1 -Start -Path "C:\Traces" -MaxFiles 3 -MaxSizeMB 10 -EnableLogging
    Starts the service with specified parameters and logging enabled
 
.EXAMPLE
    .\NetTrace-ServiceRunner.ps1 -Stop
    Stops the NetTrace Windows Service
 
.EXAMPLE
    .\NetTrace-ServiceRunner.ps1 -Status
    Shows current service status
 
.EXAMPLE
    .\NetTrace-ServiceRunner.ps1 -Uninstall
    Uninstalls the NetTrace Windows Service
 
.LINK
    https://github.com/khannaveed2020/NetTrace
#>


[CmdletBinding(DefaultParameterSetName = 'Status')]
param(
    [Parameter(ParameterSetName = 'Install', Mandatory = $true)]
    [switch]$Install,

    [Parameter(ParameterSetName = 'Uninstall', Mandatory = $true)]
    [switch]$Uninstall,

    [Parameter(ParameterSetName = 'Start', Mandatory = $true)]
    [switch]$Start,

    [Parameter(ParameterSetName = 'Stop', Mandatory = $true)]
    [switch]$Stop,

    [Parameter(ParameterSetName = 'Start', Mandatory = $true)]
    [string]$Path,

    [Parameter(ParameterSetName = 'Start', Mandatory = $true)]
    [int]$MaxFiles,

    [Parameter(ParameterSetName = 'Start', Mandatory = $true)]
    [int]$MaxSizeMB,

    [Parameter(ParameterSetName = 'Start', Mandatory = $false)]
    [switch]$LogOutput,

    [Parameter(ParameterSetName = 'Start', Mandatory = $false)]
    [switch]$EnableLogging
)

# Service configuration
$ServiceName = "NetTraceService"
$ServiceDisplayName = "NetTrace Network Monitoring Service"
$ServiceDescription = "Provides persistent network trace monitoring with automatic file rotation and circular management"

# Get script directory
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$ServiceScript = Join-Path $ScriptDir "NetTrace-Service.ps1"

# Check if service script exists
if (!(Test-Path $ServiceScript)) {
    Write-Error "NetTrace-Service.ps1 not found in script directory: $ScriptDir"
    exit 1
}

# Import service functions
. $ServiceScript

# NSSM management functions - FIXED VERSION
function Get-NSSM {
    <#
    .SYNOPSIS
        Gets NSSM for service management with persistent storage
    .DESCRIPTION
        Checks if NSSM is available in system PATH first, then downloads to persistent location if needed
    #>


    # First check if NSSM is available in system PATH (user may have installed it)
    $systemNssm = Get-Command nssm -ErrorAction SilentlyContinue
    if ($systemNssm) {
        Write-Information "NSSM found in system PATH: $($systemNssm.Source)" -InformationAction Continue
        return $systemNssm.Source
    }

    # FIXED: Use persistent location instead of temp directory
    $nssmDir = "$env:ProgramData\NetTrace\NSSM"
    $nssmPath = "$nssmDir\nssm.exe"

    # Check if NSSM is already available in persistent location
    if (Test-Path $nssmPath) {
        if ($VerbosePreference -eq 'Continue') {
            Write-Information "NSSM found at: $nssmPath" -InformationAction Continue
        }
        return $nssmPath
    }

    if ($VerbosePreference -eq 'Continue') {
        Write-Information "Downloading NSSM (Non-Sucking Service Manager) to persistent location..." -InformationAction Continue
    }

    try {
        # Create directory if it doesn't exist
        if (!(Test-Path $nssmDir)) {
            New-Item -Path $nssmDir -ItemType Directory -Force | Out-Null
        }

        # Download NSSM
        $nssmUrl = "https://nssm.cc/release/nssm-2.24.zip"
        $nssmZip = "$nssmDir\nssm.zip"

        # Use System.Net.WebClient for reliable download
        $webClient = New-Object System.Net.WebClient
        $webClient.DownloadFile($nssmUrl, $nssmZip)

        # Extract NSSM
        Add-Type -AssemblyName System.IO.Compression.FileSystem
        $zip = [System.IO.Compression.ZipFile]::OpenRead($nssmZip)

        # Find the correct nssm.exe for current architecture
        $architecture = if ([Environment]::Is64BitOperatingSystem) { "win64" } else { "win32" }
        $nssmEntry = $zip.Entries | Where-Object { $_.FullName -like "*/$architecture/nssm.exe" }

        if ($nssmEntry) {
            $stream = $nssmEntry.Open()
            $fileStream = [System.IO.File]::Create($nssmPath)
            $stream.CopyTo($fileStream)
            $fileStream.Close()
            $stream.Close()
        } else {
            throw "Could not find nssm.exe for architecture: $architecture"
        }

        $zip.Dispose()

        # Clean up zip file
        Remove-Item $nssmZip -Force -ErrorAction SilentlyContinue

        if (Test-Path $nssmPath) {
            if ($VerbosePreference -eq 'Continue') {
                Write-Information "NSSM downloaded successfully to persistent location: $nssmPath" -InformationAction Continue
            }
            return $nssmPath
        } else {
            throw "NSSM download failed - file not found after extraction"
        }

    } catch {
        Write-Error "Failed to download NSSM: $($_.Exception.Message)"
        if ($VerbosePreference -eq 'Continue') {
            Write-Information "Manual installation: Download NSSM from https://nssm.cc/ and place nssm.exe in $nssmDir" -InformationAction Continue
        }
        return $null
    }
}

# FIXED: Add NSSM execution helper function
function Invoke-NSSM {
    <#
    .SYNOPSIS
        Safely executes NSSM commands with proper path handling
    .DESCRIPTION
        Ensures NSSM path is properly quoted and executed in the correct context
    #>

    param(
        [string]$NssmPath,
        [string[]]$Arguments
    )
    
    if (-not $NssmPath -or -not (Test-Path $NssmPath)) {
        throw "NSSM path is invalid or not found: $NssmPath"
    }
    
    # Ensure path is properly quoted
# $quotedPath = "`"$NssmPath`""
    
    # Execute NSSM with proper path handling
   # $result = & $quotedPath $Arguments 2>&1
   $result = & $NssmPath @Arguments 2>&1
    return $result
}

function New-ServiceWrapper {
    <#
    .SYNOPSIS
        Creates a batch file wrapper for the PowerShell service script
    .DESCRIPTION
        Creates a simple batch file to avoid complex PowerShell parameter escaping issues with NSSM
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param(
        [string]$ServiceScriptPath,
        [string]$WrapperPath
    )

    if ($PSCmdlet.ShouldProcess($WrapperPath, "Create service wrapper batch file")) {
        try {
            $batchContent = @"
@echo off
REM NetTrace Service Wrapper
REM This batch file starts the NetTrace PowerShell service script
REM Created automatically by NetTrace-ServiceRunner.ps1
 
REM Change to script directory to ensure proper module loading
cd /d "$ScriptDir"
 
REM Start PowerShell with the service script
powershell.exe -ExecutionPolicy Bypass -NoProfile -WindowStyle Hidden -File "$ServiceScriptPath" -ServiceMode
 
REM Exit with the same code as PowerShell
exit /b %ERRORLEVEL%
"@


            $batchContent | Out-File -FilePath $WrapperPath -Encoding ASCII -Force
            
            if (Test-Path $WrapperPath) {
                if ($VerbosePreference -eq 'Continue') {
                    Write-Information "Service wrapper created: $WrapperPath" -InformationAction Continue
                }
                return $true
            } else {
                throw "Failed to create wrapper file"
            }
        } catch {
            Write-Error "Failed to create service wrapper: $($_.Exception.Message)"
            return $false
        }
    }
    return $false
}

function Install-NetTraceWindowsService {
    <#
    .SYNOPSIS
        Installs NetTrace as a Windows Service using NSSM with simplified configuration
    .DESCRIPTION
        Uses NSSM to install NetTrace as a proper Windows Service with batch file wrapper for reliability
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param()

    if ($PSCmdlet.ShouldProcess("NetTrace Windows Service", "Install")) {
        Write-Information "Installing NetTrace as Windows Service using NSSM..." -InformationAction Continue

        try {
            # Get NSSM
            $nssm = Get-NSSM
            if (-not $nssm) {
                throw "NSSM is required for service installation"
            }

            # Check if service already exists - force reconfiguration if it does
            $existingService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if ($existingService) {
                Write-Information "Service '$ServiceName' already exists. Forcing reconfiguration with current module version..." -InformationAction Continue

                # Stop and remove the existing service to ensure clean reinstall
                if ($existingService.Status -eq 'Running') {
                    Invoke-NSSM -NssmPath $nssm -Arguments @("stop", $ServiceName) | Out-Null
                    Start-Sleep -Seconds 2
                }

                # Remove the service completely
                Invoke-NSSM -NssmPath $nssm -Arguments @("remove", $ServiceName, "confirm") | Out-Null
                Start-Sleep -Seconds 2

                # Clean up service state
                $ServiceStateDir = "$env:ProgramData\NetTrace"
                if (Test-Path $ServiceStateDir) {
                    Remove-Item $ServiceStateDir -Recurse -Force -ErrorAction SilentlyContinue
                }
            }

            # FIXED: Create simplified batch file wrapper instead of complex parameter escaping
            $ServiceStateDir = "$env:ProgramData\NetTrace"
            if (!(Test-Path $ServiceStateDir)) {
                New-Item -Path $ServiceStateDir -ItemType Directory -Force | Out-Null
            }

            $wrapperBatch = "$ServiceStateDir\NetTrace-Service.bat"
            $serviceScriptPath = (Get-Item $ServiceScript).FullName
            
            Write-Information "Creating service wrapper batch file..." -InformationAction Continue
            $wrapperSuccess = New-ServiceWrapper -ServiceScriptPath $serviceScriptPath -WrapperPath $wrapperBatch
            if (-not $wrapperSuccess) {
                throw "Failed to create service wrapper"
            }

            # Install service with NSSM using the batch file wrapper
            Write-Information "Installing service with wrapper: $wrapperBatch" -InformationAction Continue

            $installResult = Invoke-NSSM -NssmPath $nssm -Arguments @("install", $ServiceName, $wrapperBatch)
            if ($LASTEXITCODE -ne 0) {
                throw "NSSM install failed: $installResult"
            }

            # Configure basic service settings
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppDirectory", $ScriptDir) | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "DisplayName", $ServiceDisplayName) | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "Description", $ServiceDescription) | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "Start", "SERVICE_AUTO_START") | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "Type", "SERVICE_WIN32_OWN_PROCESS") | Out-Null

            # Ensure the service runs as LocalSystem for persistence
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "ObjectName", "LocalSystem") | Out-Null
            Write-Information "Service will run as LocalSystem for persistence across logoff/reboot." -InformationAction Continue

            # Configure service recovery
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppStopMethodSkip", "0") | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppStopMethodConsole", "1500") | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppStopMethodWindow", "1500") | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppStopMethodThreads", "1500") | Out-Null

            # Set service to restart on failure
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppExit", "Default", "Restart") | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppRestartDelay", "60000") | Out-Null

            # Configure logging
            $logDir = "$env:ProgramData\NetTrace\service_logs"
            if (!(Test-Path $logDir)) {
                New-Item -Path $logDir -ItemType Directory -Force | Out-Null
            }

            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppStdout", "$logDir\service_stdout.log") | Out-Null
            Invoke-NSSM -NssmPath $nssm -Arguments @("set", $ServiceName, "AppStderr", "$logDir\service_stderr.log") | Out-Null

            # ENHANCED: Validate service installation
            Write-Information "Validating service installation..." -InformationAction Continue
            $installedService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if (-not $installedService) {
                throw "Service installation validation failed - service not found"
            }

            # Validate wrapper file exists and is accessible
            if (-not (Test-Path $wrapperBatch)) {
                throw "Service wrapper validation failed - wrapper file not found"
            }

            # Validate service script exists and is accessible
            if (-not (Test-Path $serviceScriptPath)) {
                throw "Service script validation failed - script file not found"
            }

            Write-Information "NetTrace Windows Service installed successfully" -InformationAction Continue
            Write-Information " Service Name: $ServiceName" -InformationAction Continue
            Write-Information " Display Name: $ServiceDisplayName" -InformationAction Continue
            Write-Information " Startup Type: Automatic" -InformationAction Continue
            Write-Information " Service Type: Windows Service (NSSM)" -InformationAction Continue
            Write-Information " Wrapper: $wrapperBatch" -InformationAction Continue
            Write-Information " Script: $serviceScriptPath" -InformationAction Continue
            Write-Information "" -InformationAction Continue
            Write-Information "Service is ready to use. Use 'NetTrace-ServiceRunner.ps1 -Start' to start the service." -InformationAction Continue

            return $true

        } catch {
            Write-Error "Failed to install NetTrace Windows Service: $($_.Exception.Message)"
            return $false
        }
    }
}

function Uninstall-NetTraceWindowsService {
    <#
    .SYNOPSIS
        Uninstalls the NetTrace Windows Service
    .DESCRIPTION
        Removes the NetTrace Windows Service using NSSM and cleans up all related files
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param()

    if ($PSCmdlet.ShouldProcess("NetTrace Windows Service", "Uninstall")) {
        Write-Information "Uninstalling NetTrace Windows Service..." -InformationAction Continue

        try {
            # Get NSSM
            $nssm = Get-NSSM
            if (-not $nssm) {
                Write-Warning "NSSM not available. Attempting standard service removal..."
            }

            # Stop service if running
            $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if ($service) {
                if ($service.Status -eq 'Running') {
                    Write-Information "Stopping service..." -InformationAction Continue
                    if ($nssm) {
                        Invoke-NSSM -NssmPath $nssm -Arguments @("stop", $ServiceName)
                    } else {
                        Stop-Service -Name $ServiceName -Force -ErrorAction SilentlyContinue
                    }
                    Start-Sleep -Seconds 3
                }

                # Remove service
                if ($nssm) {
                    $removeResult = Invoke-NSSM -NssmPath $nssm -Arguments @("remove", $ServiceName, "confirm")
                    if ($LASTEXITCODE -eq 0) {
                        Write-Information "NetTrace Windows Service uninstalled successfully" -InformationAction Continue
                    } else {
                        throw "NSSM remove failed: $removeResult"
                    }
                } else {
                    # Fallback to standard removal
                    Remove-Service -Name $ServiceName -ErrorAction Stop
                    Write-Information "NetTrace Windows Service uninstalled successfully (standard removal)" -InformationAction Continue
                }
            } else {
                Write-Information "NetTrace Windows Service is not installed" -InformationAction Continue
            }

            # Clean up service state directory and wrapper
            $ServiceStateDir = "$env:ProgramData\NetTrace"
            if (Test-Path $ServiceStateDir) {
                Write-Information "Cleaning up service state directory..." -InformationAction Continue
                Remove-Item $ServiceStateDir -Recurse -Force -ErrorAction SilentlyContinue
            }

            return $true

        } catch {
            Write-Error "Failed to uninstall NetTrace Windows Service: $($_.Exception.Message)"
            return $false
        }
    }
}

function Start-WindowsService {
    <#
    .SYNOPSIS
        Starts the NetTrace Windows Service with enhanced monitoring
    .DESCRIPTION
        Starts the Windows Service using NSSM or standard service controls with detailed status monitoring
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param()

    if ($PSCmdlet.ShouldProcess("NetTrace Windows Service", "Start")) {
        try {
            # Get NSSM
            $nssm = Get-NSSM

            # Check if service exists
            $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if (-not $service) {
                throw "NetTrace Windows Service is not installed. Use -Install first."
            }

            # ENHANCED: Pre-start validation
            if ($VerbosePreference -eq 'Continue') {
                Write-Information "Performing pre-start validation..." -InformationAction Continue
            }
            
            # Check if wrapper file exists
            $wrapperBatch = "$env:ProgramData\NetTrace\NetTrace-Service.bat"
            if (-not (Test-Path $wrapperBatch)) {
                Write-Warning "Service wrapper not found at: $wrapperBatch"
                if ($VerbosePreference -eq 'Continue') {
                    Write-Information "Attempting to recreate wrapper..." -InformationAction Continue
                }
                $serviceScriptPath = (Get-Item $ServiceScript).FullName
                $wrapperSuccess = New-ServiceWrapper -ServiceScriptPath $serviceScriptPath -WrapperPath $wrapperBatch
                if (-not $wrapperSuccess) {
                    throw "Failed to recreate service wrapper"
                }
            }

            # Check if service script exists
            if (-not (Test-Path $ServiceScript)) {
                throw "Service script not found: $ServiceScript"
            }

            # ENHANCED: Robust service state management
            $currentStatus = Invoke-NSSM -NssmPath $nssm -Arguments @("status", $ServiceName)
            if ($VerbosePreference -eq 'Continue') {
                Write-Information "Current service status: $currentStatus" -InformationAction Continue
            }

            if ($currentStatus -eq "SERVICE_RUNNING") {
                if ($VerbosePreference -eq 'Continue') {
                    Write-Information "Service is already running successfully" -InformationAction Continue
                }
                return $true
            } elseif ($currentStatus -eq "SERVICE_PAUSED") {
                if ($VerbosePreference -eq 'Continue') {
                    Write-Information "Service is paused, stopping and restarting..." -InformationAction Continue
                }
                Invoke-NSSM -NssmPath $nssm -Arguments @("stop", $ServiceName) | Out-Null
                Start-Sleep -Seconds 2
            } elseif ($currentStatus -eq "SERVICE_STOPPED") {
                if ($VerbosePreference -eq 'Continue') {
                    Write-Information "Service is stopped, ready to start..." -InformationAction Continue
                }
            } else {
                Write-Warning "Service in unexpected state: $currentStatus. Attempting to stop first..."
                Invoke-NSSM -NssmPath $nssm -Arguments @("stop", $ServiceName) | Out-Null
                Start-Sleep -Seconds 2
            }

            # Start the service
            if ($VerbosePreference -eq 'Continue') {
                Write-Information "Starting service with NSSM..." -InformationAction Continue
            }

            $startResult = Invoke-NSSM -NssmPath $nssm -Arguments @("start", $ServiceName)
            if ($LASTEXITCODE -ne 0) {
                throw "NSSM start failed: $startResult"
            }

            if ($VerbosePreference -eq 'Continue') {
                Write-Information "Waiting for service to start..." -InformationAction Continue
            }

            # Wait for service to start with timeout
            $maxWaitTime = 30
            $waitTime = 0
            $checkInterval = 2

            while ($waitTime -lt $maxWaitTime) {
                Start-Sleep -Seconds $checkInterval
                $waitTime += $checkInterval

                $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
                if ($service) {
                    if ($VerbosePreference -eq 'Continue') {
                        Write-Information "Service status after $waitTime seconds: $($service.Status)" -InformationAction Continue
                    }
                    
                    if ($service.Status -eq 'Running') {
                        if ($VerbosePreference -eq 'Continue') {
                            Write-Information "NetTrace Windows Service started successfully" -InformationAction Continue
                        }
                        
                        # Additional validation - check if service is actually working
                        Start-Sleep -Seconds 3
                        $serviceStatus = Get-ServiceStatus
                        if ($serviceStatus.IsRunning) {
                            if ($VerbosePreference -eq 'Continue') {
                                Write-Information "Service validation successful - NetTrace monitoring is active" -InformationAction Continue
                            }
                        } else {
                            Write-Warning "Service started but NetTrace monitoring may not be active yet. Check logs if issues persist."
                        }
                        
                        return $true
                    }
                    elseif ($service.Status -eq 'Paused') {
                        # Service is paused - this usually indicates a script execution issue
                        Write-Warning "Service is in PAUSED state - this typically indicates a PowerShell script execution issue"
                        Write-Warning "Check Windows Event Logs and service logs for more details"
                        
                        # Try to get more details from NSSM
                        if ($nssm) {
                            $nssmStatus = Invoke-NSSM -NssmPath $nssm -Arguments @("status", $ServiceName)
                            if ($VerbosePreference -eq 'Continue') {
                                Write-Information "NSSM status: $nssmStatus" -InformationAction Continue
                            }
                        }

                        # ENHANCED: Show recent service errors to help diagnosis
                        $serviceLogFile = "$env:ProgramData\NetTrace\service.log"
                        if (Test-Path $serviceLogFile) {
                            Write-Information "Recent service errors:" -InformationAction Continue
                            $recentErrors = Get-Content $serviceLogFile -Tail 10 | Where-Object { $_ -match "\[ERROR\]" }
                            if ($recentErrors) {
                                $recentErrors | ForEach-Object { Write-Warning " $_" }
                            } else {
                                Write-Information " No recent errors in service log" -InformationAction Continue
                            }
                        }
                        
                        # Check service logs
                        $logDir = "$env:ProgramData\NetTrace\service_logs"
                        $stderrLog = "$logDir\service_stderr.log"
                        
                        if (Test-Path $stderrLog) {
                            $errorContent = Get-Content $stderrLog -Tail 10 -ErrorAction SilentlyContinue
                            if ($errorContent) {
                                Write-Information "Recent service errors:" -InformationAction Continue
                                $errorContent | ForEach-Object { Write-Information " $_" -InformationAction Continue }
                            }
                        }
                        
                        throw "Service started but is in PAUSED state. Check the service logs and Windows Event Logs for detailed error information."
                    }
                    elseif ($service.Status -eq 'Stopped') {
                        Write-Warning "Service stopped unexpectedly"
                        throw "Service stopped after starting - check Windows Event Logs and service logs for errors"
                    }
                }
            }
            
            # Final check
            $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if ($service) {
                throw "Service failed to start within $maxWaitTime seconds. Final status: $($service.Status)"
            } else {
                throw "Service not found after start attempt"
            }

        } catch {
            Write-Error "Failed to start NetTrace Windows Service: $($_.Exception.Message)"
            return $false
        }
    }
}

function Stop-WindowsService {
    <#
    .SYNOPSIS
        Stops the NetTrace Windows Service
    .DESCRIPTION
        Stops the Windows Service using NSSM or standard service controls
    #>

    [CmdletBinding(SupportsShouldProcess)]
    param()

    if ($PSCmdlet.ShouldProcess("NetTrace Windows Service", "Stop")) {
        try {
            # Get NSSM
            $nssm = Get-NSSM

            # Check if service exists
            $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if (-not $service) {
                Write-Information "NetTrace Windows Service is not installed" -InformationAction Continue
                return $true
            }

            # Stop service
            if ($service.Status -eq 'Running') {
                # Signal service to stop gracefully first
                Stop-NetTraceService

                Start-Sleep -Seconds 2

                # Use NSSM or standard service stop
                if ($nssm) {
                    $stopResult = Invoke-NSSM -NssmPath $nssm -Arguments @("stop", $ServiceName)
                    if ($LASTEXITCODE -ne 0) {
                        Write-Warning "NSSM stop returned: $stopResult"
                    }
                } else {
                    Stop-Service -Name $ServiceName -Force -ErrorAction SilentlyContinue
                }

                # Wait for service to stop
                Start-Sleep -Seconds 3

                # Verify service is stopped
                $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
                if ($service -and $service.Status -eq 'Stopped') {
                    Write-Information "NetTrace Windows Service stopped successfully" -InformationAction Continue
                    return $true
                } else {
                    Write-Warning "Service may not have stopped cleanly"
                    return $false
                }
            } else {
                Write-Information "NetTrace Windows Service is already stopped" -InformationAction Continue
                return $true
            }

        } catch {
            Write-Error "Failed to stop NetTrace Windows Service: $($_.Exception.Message)"
            return $false
        }
    }
}

function Start-NetTraceServiceRunner {
    [CmdletBinding(SupportsShouldProcess)]
    param(
        [string]$TracePath,
        [int]$MaxFiles,
        [int]$MaxSizeMB,
        [bool]$LogOutput,
        [bool]$EnableLogging
    )

    if ($PSCmdlet.ShouldProcess("NetTrace Windows Service", "Start monitoring")) {
        Write-Information "Starting NetTrace Windows Service..." -InformationAction Continue

        try {
            # Validate parameters
            if ($MaxFiles -le 0) {
                throw "MaxFiles parameter must be a positive integer"
            }
            if ($MaxSizeMB -le 0) {
                throw "MaxSizeMB parameter must be a positive integer"
            }
            if ($MaxSizeMB -lt 10) {
                throw "MaxSizeMB must be at least 10 MB. Netsh trace has a minimum file size of 10MB."
            }
            if ([string]::IsNullOrWhiteSpace($TracePath)) {
                throw "Path parameter is required"
            }

            # Ensure directory exists
            if (!(Test-Path $TracePath)) {
                New-Item -Path $TracePath -ItemType Directory -Force | Out-Null
                Write-Information "Created directory: $TracePath" -InformationAction Continue
            }

            # Check if service is installed
            $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if (-not $service) {
                Write-Information "NetTrace Windows Service is not installed. Installing automatically..." -InformationAction Continue
                $installSuccess = Install-NetTraceWindowsService
                if (-not $installSuccess) {
                    throw "Failed to install NetTrace Windows Service"
                }
            }

            # Check if service is already running
            $service = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if ($service -and $service.Status -eq 'Running') {
                Write-Warning "NetTrace Windows Service is already running. Use -Stop first to stop the current session."
                return $false
            }

            # Configure the service
            $configSuccess = Start-NetTraceService -Path $TracePath -MaxFiles $MaxFiles -MaxSizeMB $MaxSizeMB -LogOutput $LogOutput -EnableLogging $EnableLogging
            if (-not $configSuccess) {
                throw "Failed to configure NetTrace service"
            }

            # Start the Windows Service
            $startSuccess = Start-WindowsService
            if (-not $startSuccess) {
                throw "Failed to start NetTrace Windows Service"
            }

            Write-Information "NetTrace Windows Service started successfully" -InformationAction Continue
            Write-Information " Path: $TracePath" -InformationAction Continue
            Write-Information " Max Files: $MaxFiles" -InformationAction Continue
            Write-Information " Max Size: $MaxSizeMB MB" -InformationAction Continue
            Write-Information " Logging: $(if ($EnableLogging) { 'Enabled' } else { 'Disabled' })" -InformationAction Continue
            Write-Information " NetSH Output: $(if ($LogOutput) { 'Enabled' } else { 'Disabled' })" -InformationAction Continue
            Write-Information "" -InformationAction Continue
            Write-Information "Service is now running as a true Windows Service with complete persistence." -InformationAction Continue
            Write-Information "The service will survive user logouts and system reboots." -InformationAction Continue
            Write-Information "Use 'NetTrace -Stop' or 'NetTrace-ServiceRunner.ps1 -Stop' to stop the service." -InformationAction Continue

            if ($EnableLogging) {
                Write-Information "Monitor progress with: Get-Content '$TracePath\NetTrace_*.log' -Wait" -InformationAction Continue
            }

            return $true

        } catch {
            Write-Error "Error starting NetTrace Windows Service: $($_.Exception.Message)"
            return $false
        }
    }
}

function Stop-NetTraceServiceRunner {
    [CmdletBinding(SupportsShouldProcess)]
    param()

    if ($PSCmdlet.ShouldProcess("NetTrace Windows Service", "Stop monitoring")) {
        Write-Information "Stopping NetTrace Windows Service..." -InformationAction Continue

        try {
            # Stop the Windows Service
            $stopSuccess = Stop-WindowsService
            if ($stopSuccess) {
                Write-Information "NetTrace Windows Service stopped successfully" -InformationAction Continue
                return $true
            } else {
                Write-Warning "NetTrace Windows Service may not have stopped cleanly"
                return $false
            }

        } catch {
            Write-Error "Error stopping NetTrace Windows Service: $($_.Exception.Message)"
            return $false
        }
    }
}

function Show-NetTraceServiceStatus {
    if ($VerbosePreference -eq 'Continue') {
        Write-Information "NetTrace Windows Service Status" -InformationAction Continue
        Write-Information "===============================" -InformationAction Continue

        try {
            # Check Windows Service status
            $windowsService = Get-Service -Name $ServiceName -ErrorAction SilentlyContinue
            if ($windowsService) {
                $serviceStatusText = "Windows Service: $($windowsService.Status)"
                Write-Information $serviceStatusText -InformationAction Continue
                Write-Information "Service Type: True Windows Service (NSSM)" -InformationAction Continue
            } else {
                Write-Information "Windows Service: Not Installed" -InformationAction Continue
                Write-Information "Use -Install to install the service" -InformationAction Continue
            }

            # Check NetTrace service status
            $netTraceStatus = Get-ServiceStatus
            $netTraceStatusText = "NetTrace Service: $(if ($netTraceStatus.IsRunning) { 'Running' } else { 'Stopped' })"
            Write-Information $netTraceStatusText -InformationAction Continue

            if ($netTraceStatus.IsRunning) {
                Write-Information "" -InformationAction Continue
                Write-Information "Service Details:" -InformationAction Continue
                Write-Information " Files Created: $($netTraceStatus.FilesCreated)" -InformationAction Continue
                Write-Information " Files Rolled: $($netTraceStatus.FilesRolled)" -InformationAction Continue
                Write-Information " Current File: $($netTraceStatus.CurrentFile)" -InformationAction Continue
                Write-Information " Last Update: $($netTraceStatus.LastUpdate)" -InformationAction Continue

                if ($netTraceStatus.ErrorMessage) {
                    Write-Information " Error: $($netTraceStatus.ErrorMessage)" -InformationAction Continue
                }

                # Show configuration
                $config = Get-ServiceConfig
                if ($config) {
                    Write-Information "" -InformationAction Continue
                    Write-Information "Configuration:" -InformationAction Continue
                    Write-Information " Path: $($config.Path)" -InformationAction Continue
                    Write-Information " Max Files: $($config.MaxFiles)" -InformationAction Continue
                    Write-Information " Max Size: $($config.MaxSizeMB) MB" -InformationAction Continue
                    Write-Information " Logging: $(if ($config.EnableLogging) { 'Enabled' } else { 'Disabled' })" -InformationAction Continue
                    Write-Information " NetSH Output: $(if ($config.LogOutput) { 'Enabled' } else { 'Disabled' })" -InformationAction Continue
                    Write-Information " Started: $($config.StartTime)" -InformationAction Continue
                    Write-Information " Service Version: $($config.ServiceVersion)" -InformationAction Continue
                }
            } else {
                if ($netTraceStatus.ErrorMessage) {
                    Write-Information "Last Error: $($netTraceStatus.ErrorMessage)" -InformationAction Continue
                }
            }

            # Show persistence information
            if ($windowsService -and $windowsService.Status -eq 'Running') {
                Write-Information "" -InformationAction Continue
                Write-Information "Persistence Status:" -InformationAction Continue
                Write-Information " True Windows Service - survives user logouts" -InformationAction Continue
                Write-Information " Auto-start enabled - survives system reboots" -InformationAction Continue
                Write-Information " Service recovery configured - automatic restart on failure" -InformationAction Continue
            }

            # ENHANCED: Show validation information
            Write-Information "" -InformationAction Continue
            Write-Information "Validation Status:" -InformationAction Continue
            
            $wrapperBatch = "$env:ProgramData\NetTrace\NetTrace-Service.bat"
            $wrapperStatus = if (Test-Path $wrapperBatch) { "Found" } else { "Missing" }
            Write-Information " Service Wrapper: $wrapperStatus" -InformationAction Continue
            
            $serviceScriptStatus = if (Test-Path $ServiceScript) { "Found" } else { "Missing" }
            Write-Information " Service Script: $serviceScriptStatus" -InformationAction Continue
            
            $nssmPath = Get-NSSM
            $nssmStatus = if ($nssmPath) { "Available at $nssmPath" } else { "Not Available" }
            Write-Information " NSSM: $nssmStatus" -InformationAction Continue

        } catch {
            Write-Error "Error retrieving NetTrace Windows Service status: $($_.Exception.Message)"
            return $false
        }
    }
    
    return $true
}

# Main execution logic - ONLY run when script is executed directly, NOT when dot-sourced
if ($MyInvocation.InvocationName -eq $MyInvocation.MyCommand.Name) {
    try {
        switch ($PSCmdlet.ParameterSetName) {
            'Install' {
                if ($Install) {
                    Install-NetTraceWindowsService | Out-Null
                }
            }
            'Uninstall' {
                if ($Uninstall) {
                    Uninstall-NetTraceWindowsService | Out-Null
                }
            }
            'Start' {
                if ($Start) {
                    Start-NetTraceServiceRunner -TracePath $Path -MaxFiles $MaxFiles -MaxSizeMB $MaxSizeMB -LogOutput:$LogOutput -EnableLogging:$EnableLogging | Out-Null
                }
            }
            'Stop' {
                if ($Stop) {
                    Stop-NetTraceServiceRunner | Out-Null
                }
            }
            'Status' {
                Show-NetTraceServiceStatus | Out-Null
            }
            default {
                Show-NetTraceServiceStatus | Out-Null
            }
        }

        if ($VerbosePreference -eq 'Continue') {
            Write-Information "" -InformationAction Continue
            Write-Information "For more information: https://github.com/khannaveed2020/NetTrace" -InformationAction Continue
        }

    } catch {
        Write-Error "Fatal error in NetTrace Service Runner: $($_.Exception.Message)"
        exit 1
    }
}