Public/Test-EnvkInstallation.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Checks installation health and reports results as a structured summary. .DESCRIPTION Test-EnvkInstallation verifies four areas of installation health: 1. Module loading: PowerShell version (5.1 minimum, 7+ for parallel features) and UIAutomationClient assembly availability. 2. Config validity: Config file found and parseable via Get-EnvkConfig; all app paths resolvable via Resolve-EnvkExecutablePath. 3. Task Scheduler configuration: Scheduled task exists whose action references Envoke.vbs; ScheduledTasks module available. 4. Write permissions: Log directory writable; registry path accessible. Each check produces a PSCustomObject with Name, Status (Pass/Fail/Warn), and Message properties. After all checks run, a formatted summary table is written to the console via Write-EnvkLog. The function is report-only -- it does not modify system state or auto-fix any issues. Failed and Warn results include actionable messages telling the user what command to run. .PARAMETER ConfigPath Optional path to a config.json file. When omitted, Get-EnvkConfig uses its default three-location search order. Passed directly to Get-EnvkConfig. .OUTPUTS [PSCustomObject[]] Array of check result objects. Each object has: Name [string] -- Check area label Status [string] -- 'Pass' | 'Fail' | 'Warn' Message [string] -- Human-readable detail; actionable for non-Pass results .EXAMPLE # Run installation checks with default config search $results = Test-EnvkInstallation .EXAMPLE # Run checks against an explicit config path $results = Test-EnvkInstallation -ConfigPath 'C:\repos\Envoke\config.json' .EXAMPLE # Filter for only non-passing checks Test-EnvkInstallation | Where-Object { $_.Status -ne 'Pass' } .NOTES Author: Aaron AlAnsari Created: 2026-02-26 #> # PSUseOutputTypeCorrectly: unary comma forces Object[] wrapper to prevent single-element # unboxing in the pipeline. Element type is always PSCustomObject. [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseOutputTypeCorrectly', '')] param () function Test-EnvkInstallation { [CmdletBinding()] [OutputType([PSCustomObject[]])] param ( [Parameter()] [string]$ConfigPath ) $results = [System.Collections.Generic.List[PSCustomObject]]::new() # Private helper: adds a single check result to the list. function Add-Check { param ( [string]$Name, [string]$Status, [string]$Message ) $results.Add([PSCustomObject]@{ Name = $Name Status = $Status Message = $Message }) } # ------------------------------------------------------------------------- # Area 1: Module loading # ------------------------------------------------------------------------- # -- PS version check $psMajor = Get-PSMajorVersion if ($psMajor -lt 5) { Add-Check -Name 'PS version' -Status 'Fail' ` -Message "PowerShell $psMajor is below minimum required 5.1." } elseif ($psMajor -ge 7) { Add-Check -Name 'PS version' -Status 'Pass' ` -Message "PowerShell $psMajor -- parallel launching available." } else { Add-Check -Name 'PS version' -Status 'Warn' ` -Message "PowerShell 5.1 detected -- parallel launching unavailable. Install PowerShell 7+ for parallel mode." } # -- UIAutomationClient assembly check try { Invoke-LoadUIAutomationAssembly Add-Check -Name 'UIAutomation assembly' -Status 'Pass' ` -Message 'UIAutomationClient assembly loaded.' } catch { Add-Check -Name 'UIAutomation assembly' -Status 'Warn' ` -Message 'UIAutomationClient assembly not available -- window maximization will use WinAPI fallback only.' } # ------------------------------------------------------------------------- # Area 2: Config validity # ------------------------------------------------------------------------- $loadedConfig = $null # -- Config file found and parseable $configLoadParams = @{} if (-not [string]::IsNullOrEmpty($ConfigPath)) { $configLoadParams['ConfigPath'] = $ConfigPath } try { $loadedConfig = Get-EnvkConfig @configLoadParams Add-Check -Name 'Config file' -Status 'Pass' ` -Message "Configuration loaded successfully." } catch { Add-Check -Name 'Config file' -Status 'Fail' ` -Message $_.Exception.Message } # -- App paths resolvable (only if config loaded successfully) if ($null -ne $loadedConfig) { $appCount = 0 $failedApps = [System.Collections.Generic.List[PSCustomObject]]::new() $appProps = $loadedConfig.apps.PSObject.Properties foreach ($prop in $appProps) { $appCount++ $appEntry = $prop.Value $resolved = Resolve-EnvkExecutablePath -Path $appEntry.path if ($null -eq $resolved -or $resolved.Valid -eq $false) { $reason = if ($null -eq $resolved) { 'Could not resolve path' } else { $resolved.Reason } $failedApps.Add([PSCustomObject]@{ Name = $prop.Name Path = $appEntry.path Reason = $reason }) } } if ($failedApps.Count -gt 0) { $details = $failedApps | ForEach-Object { "'$($_.Name)': $($_.Reason)" } $msg = "App path(s) not found: $($details -join '; '). Verify paths in your config." Add-Check -Name 'App paths' -Status 'Warn' ` -Message $msg } else { Add-Check -Name 'App paths' -Status 'Pass' ` -Message "All $appCount app path(s) verified." } } else { Add-Check -Name 'App paths' -Status 'Warn' ` -Message 'App path check skipped -- config file could not be loaded.' } # ------------------------------------------------------------------------- # Area 3: Task Scheduler configuration # ------------------------------------------------------------------------- $taskFound = $null try { $allTasks = Get-ScheduledTask -ErrorAction Stop $taskFound = $allTasks | Where-Object { $_.Actions | Where-Object { $_.Arguments -like '*Envoke.vbs*' } } | Select-Object -First 1 } catch { # ScheduledTasks module not available on this system. Add-Check -Name 'Task Scheduler' -Status 'Warn' ` -Message 'ScheduledTasks module not available -- verify Task Scheduler setup manually.' $taskFound = 'unavailable' } if ($taskFound -ne 'unavailable') { if ($null -eq $taskFound) { Add-Check -Name 'Task Scheduler' -Status 'Fail' ` -Message 'No scheduled task found running Envoke.vbs. Import the task: schtasks /Create /XML "EnvokeTask.xml" /TN "Envoke"' } else { Add-Check -Name 'Task Scheduler' -Status 'Pass' ` -Message "Task Scheduler task '$($taskFound.TaskName)' configured correctly." } } # ------------------------------------------------------------------------- # Area 4: Write permissions # ------------------------------------------------------------------------- # -- Log directory writable $logDirectory = Join-Path $env:LOCALAPPDATA 'Envoke\Logs' $logDirExists = Test-Path -Path $logDirectory -PathType Container if ($logDirExists) { Add-Check -Name 'Log directory' -Status 'Pass' ` -Message "Log directory writable: $logDirectory" } else { try { New-Item -ItemType Directory -Path $logDirectory -Force | Out-Null Add-Check -Name 'Log directory' -Status 'Pass' ` -Message "Log directory created: $logDirectory" } catch { Add-Check -Name 'Log directory' -Status 'Fail' ` -Message "Cannot write to log directory: $logDirectory. Create it: New-Item -ItemType Directory -Path '$logDirectory'" } } # -- Registry path accessible $registryPath = 'HKCU:\Software\Envoke' $regExists = Test-Path -Path $registryPath if ($regExists) { Add-Check -Name 'Registry path' -Status 'Pass' ` -Message "Registry path exists: $registryPath" } else { Add-Check -Name 'Registry path' -Status 'Warn' ` -Message "Registry path $registryPath not yet created -- will be created on first run." } # ------------------------------------------------------------------------- # Console summary table # ------------------------------------------------------------------------- Write-EnvkLog -Level 'INFO' -Message '========================================' Write-EnvkLog -Level 'INFO' -Message 'Installation Check Summary' Write-EnvkLog -Level 'INFO' -Message '========================================' Write-EnvkLog -Level 'INFO' -Message ('{0,-30} {1}' -f 'Check', 'Status') Write-EnvkLog -Level 'INFO' -Message '----------------------------------------' foreach ($r in $results) { $level = if ($r.Status -eq 'Fail') { 'ERROR' } elseif ($r.Status -eq 'Warn') { 'WARNING' } else { 'INFO' } Write-EnvkLog -Level $level -Message ('{0,-30} {1}' -f $r.Name, $r.Status) if ($r.Status -ne 'Pass') { Write-EnvkLog -Level $level -Message " -> $($r.Message)" } } Write-EnvkLog -Level 'INFO' -Message '========================================' # ------------------------------------------------------------------------- # Return results array -- unary comma prevents single-element unboxing. # ------------------------------------------------------------------------- return , $results.ToArray() } |