Private/Test/Test-PowerShellEnvironment.ps1

function Test-PowerShellEnvironment {
    <#
        .SYNOPSIS
        Validates the PowerShell environment and returns diagnostic results.
 
        .DESCRIPTION
        Performs comprehensive validation of the PowerShell environment including:
        - Operating System (Windows only)
        - OS version (Windows 10 1607+/Server 2016+)
        - PowerShell version (5.1 or 7.4+)
        - PowerShell edition (Desktop vs Core)
        - Terminal environment (Windows Terminal recommended)
        - Output encoding (UTF-8 recommended)
        - Required and optional module availability
         
        Exits on critical failures (OS, OS version, or PowerShell version).
        Warns on non-critical issues (terminal, encoding, missing modules).
         
        Returns a hashtable containing all test results for diagnostic purposes.
 
        .INPUTS
        None. This function does not accept pipeline input.
 
        .OUTPUTS
        System.Collections.Hashtable
        Returns a hashtable with the following keys:
        - IsWindows: Boolean - Running on Windows OS
        - IsSupportedOS: Boolean - Running on supported Windows version
        - IsSupportedPS: Boolean - Running supported PowerShell version
        - IsPowerShellCore: Boolean - Running PowerShell Core/7+ (Core edition)
        - IsWindowsTerminal: Boolean - Running in Windows Terminal
        - IsUtf8: Boolean - Console output encoding is UTF-8
        - AllModulesLoaded: Boolean - All required modules are loaded in session
        - MissingModules: Array - List of module names that are not loaded
 
        .EXAMPLE
        Test-PowerShellEnvironment
        Validates the environment and returns diagnostic hashtable.
 
        .EXAMPLE
        $env = Test-PowerShellEnvironment -Verbose
        if ($env.AllModulesLoaded) {
            # All required modules are loaded
        } else {
            Write-Host "Missing modules: $($env.MissingModules -join ', ')"
        }
        Stores diagnostic results and checks module load status.
 
        .EXAMPLE
        Test-PowerShellEnvironment | ConvertTo-Json
        Validates environment and outputs results as JSON for logging.
 
        .NOTES
        Critical failures (OS, OS version, PowerShell version) will cause the function to exit.
        Non-critical issues generate warnings but allow execution to continue.
        Module availability is checked but not automatically installed by this function.
    #>

    [CmdletBinding()]
    [OutputType([hashtable])]
    param (
    )

    #requires -Version 5.1

    Write-Verbose "Starting PowerShell environment validation..."

    try {
        # Check Windows OS
        Write-Verbose "Checking if running on Windows..."
        $testIsWindows = Test-IsWindows
        if (-not $testIsWindows) {
            $errorRecord = [System.Management.Automation.ErrorRecord]::new(
                [System.Exception]::new('Locksmith 2 is only supported on Windows.'),
                'UnsupportedOS',
                [System.Management.Automation.ErrorCategory]::InvalidOperation,
                $PSVersionTable.OS
            )
            $PSCmdlet.ThrowTerminatingError($errorRecord)
        }

        $testIsSupportedOS = Test-IsSupportedOS
        if (-not $testIsSupportedOS) {
            $errorRecord = [System.Management.Automation.ErrorRecord]::new(
                [System.Exception]::new('Locksmith 2 is only supported on Windows 10 1607+/Server 2016+.'),
                'UnsupportedOSVersion',
                [System.Management.Automation.ErrorCategory]::InvalidOperation,
                $PSVersionTable.OS
            )
            $PSCmdlet.ThrowTerminatingError($errorRecord)
        }

        $testIsSupportedPS = Test-IsSupportedPS
        if (-not $testIsSupportedPS) {
            $errorRecord = [System.Management.Automation.ErrorRecord]::new(
                [System.Exception]::new('Locksmith 2 is only supported on Windows PowerShell 5.1 and PowerShell 7.4+.'),
                'UnsupportedPSVersion',
                [System.Management.Automation.ErrorCategory]::InvalidOperation,
                $PSVersionTable.PSVersion
            )
            $PSCmdlet.ThrowTerminatingError($errorRecord)
        }
        
        $testIsPowerShellCore = Test-IsPowerShellCore
        if (-not $testIsPowerShellCore) {
            Write-Warning 'Windows PowerShell detected. Locksmith 2 will run in headless mode. Interactive mode requires PowerShell 7.4+.'
        }

        $neededModules = @(
            'PSCertutil',
            'PwshSpectreConsole',
            'PSWriteHTML'
        )
        Write-Verbose "Modules to check: $($neededModules -join ', ')"

        $testIsWindowsTerminal = Test-IsWindowsTerminal
        if (-not $testIsWindowsTerminal) {
            Write-Warning 'Locksmith 2 is designed to work on Windows Terminal. Visual output may be degraded.'
        }

        $testIsUtf8 = Test-IsUtf8
        if (-not $testIsUtf8) {
            Write-Warning "Console Output Encoding is not set to UTF-8 (CodePage 65001). Visual output may be degraded."
        }

        $missingModules = @()
        foreach ($module in $neededModules) {
            $isLoaded = Test-IsModuleLoaded -Name $module
            Write-Verbose "$module is loaded: $isLoaded"
            
            if (-not $isLoaded) {
                Write-Warning "Needed module '$module' is not loaded. Locksmith 2 will guide you through installation and importation."
                $missingModules += $module
            }
        }

        if ($missingModules) {
            $allModulesLoaded = $false
        } else {
            $allModulesLoaded = $true
        }

        $returnObject = [ordered]@{
            IsWindows         = $testIsWindows
            IsSupportedOS     = $testIsSupportedOS
            IsSupportedPS     = $testIsSupportedPS
            IsPowerShellCore  = $testIsPowerShellCore
            IsWindowsTerminal = $testIsWindowsTerminal
            IsUtf8            = $testIsUtf8
            AllModulesLoaded  = $allModulesLoaded
            MissingModules    = $missingModules
        }

        Write-Verbose "PowerShell environment validation complete."
        Write-Verbose "Returning diagnostic object with $($returnObject.Count) properties."
        
        $returnObject
    } catch {
        $errorRecord = [System.Management.Automation.ErrorRecord]::new(
            $_.Exception,
            'EnvironmentValidationFailed',
            [System.Management.Automation.ErrorCategory]::NotSpecified,
            $null
        )
        $PSCmdlet.ThrowTerminatingError($errorRecord)
    }
}