PowerShell Installer Template

Overview

The PowerShell Installer Template provides a comprehensive foundation for creating robust, interactive installation scripts for Windows systems. This template includes error handling, progress tracking, user interaction, and Windows service management.

Complete PowerShell Installer Template

#Requires -Version 5.1
<#
.SYNOPSIS
    {{app_name}} Installer Script for Windows
    
.DESCRIPTION
    {{app_description}}
    Generated by I.S.A.A.C. v{{isaac_version}}
    
.PARAMETER ConfigFile
    Path to configuration file (optional)
    
.PARAMETER NonInteractive
    Run in non-interactive mode using defaults
    
.PARAMETER SkipDependencies
    Skip dependency installation
    
.PARAMETER DryRun
    Show what would be installed without making changes
    
.PARAMETER Verbose
    Enable verbose logging
    
.PARAMETER Force
    Force installation over existing installation
    
.EXAMPLE
    .\install_windows.ps1
    
.EXAMPLE
    .\install_windows.ps1 -NonInteractive -Verbose
    
.NOTES
    Version: {{app_version}}
    Generated: {{generation_timestamp}}
    Requires: PowerShell 5.1 or later, Administrator privileges
#>

[CmdletBinding()]
param(
    [Parameter(Mandatory=$false)]
    [string]$ConfigFile = "",
    
    [Parameter(Mandatory=$false)]
    [switch]$NonInteractive,
    
    [Parameter(Mandatory=$false)]
    [switch]$SkipDependencies,
    
    [Parameter(Mandatory=$false)]
    [switch]$DryRun,
    
    [Parameter(Mandatory=$false)]
    [switch]$Force
)

# =============================================================================
# CONFIGURATION VARIABLES
# =============================================================================

# Set error handling
$ErrorActionPreference = "Stop"
$ProgressPreference = "SilentlyContinue"

# Script configuration
$Script:ScriptName = $MyInvocation.MyCommand.Name
$Script:ScriptPath = $PSScriptRoot
$Script:LogFile = "$env:TEMP\{{app_name}}_install_$(Get-Date -Format 'yyyyMMdd_HHmmss').log"
$Script:TempDir = "$env:TEMP\{{app_name}}_install_$PID"
$Script:BackupDir = "$env:TEMP\{{app_name}}_backup_$(Get-Date -Format 'yyyyMMdd_HHmmss')"

# Application configuration
$Script:AppName = "{{app_name}}"
$Script:AppVersion = "{{app_version}}"
$Script:AppDescription = "{{app_description}}"
$Script:InstallPath = "{{install_path}}"
$Script:ServiceName = "{{service_name}}"
$Script:ServiceDisplayName = "{{service_display_name}}"

# Default configuration values
$Script:Config = @{
    {{#each default_config}}
    {{name}} = "{{value}}"
    {{/each}}
}

# Installation flags
$Script:InteractiveMode = -not $NonInteractive
$Script:VerboseLogging = $VerbosePreference -eq "Continue"

# =============================================================================
# UTILITY FUNCTIONS
# =============================================================================

function Write-Log {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$Message,
        
        [Parameter(Mandatory=$false)]
        [ValidateSet("Info", "Warning", "Error", "Debug")]
        [string]$Level = "Info"
    )
    
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logEntry = "[$Level] $timestamp - $Message"
    
    # Write to console with appropriate color
    switch ($Level) {
        "Info"    { Write-Host $logEntry -ForegroundColor Green }
        "Warning" { Write-Host $logEntry -ForegroundColor Yellow }
        "Error"   { Write-Host $logEntry -ForegroundColor Red }
        "Debug"   { if ($Script:VerboseLogging) { Write-Host $logEntry -ForegroundColor Cyan } }
    }
    
    # Write to log file
    Add-Content -Path $Script:LogFile -Value $logEntry -Encoding UTF8
}

function Show-Progress {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [int]$Current,
        
        [Parameter(Mandatory=$true)]
        [int]$Total,
        
        [Parameter(Mandatory=$true)]
        [string]$Activity,
        
        [Parameter(Mandatory=$false)]
        [string]$Status = "Processing..."
    )
    
    $percentComplete = [math]::Round(($Current / $Total) * 100, 0)
    Write-Progress -Activity $Activity -Status $Status -PercentComplete $percentComplete
    
    if ($Current -eq $Total) {
        Write-Progress -Activity $Activity -Completed
    }
}

function Test-Administrator {
    $currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
    $principal = New-Object Security.Principal.WindowsPrincipal($currentUser)
    return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}

function Test-PowerShellVersion {
    $requiredVersion = [Version]"5.1"
    $currentVersion = $PSVersionTable.PSVersion
    
    if ($currentVersion -lt $requiredVersion) {
        throw "PowerShell $requiredVersion or later is required. Current version: $currentVersion"
    }
    
    return $true
}

function Get-WindowsVersion {
    $version = [System.Environment]::OSVersion.Version
    return "$($version.Major).$($version.Minor).$($version.Build)"
}

function Test-WindowsVersion {
    $currentVersion = Get-WindowsVersion
    $requiredVersion = "{{min_windows_version}}"
    
    if ([Version]$currentVersion -lt [Version]$requiredVersion) {
        throw "Windows $requiredVersion or later is required. Current version: $currentVersion"
    }
    
    return $true
}

# =============================================================================
# USER INTERFACE FUNCTIONS
# =============================================================================

function Show-Welcome {
    Clear-Host
    
    $welcomeText = @"
╔══════════════════════════════════════════════════════════════╗
β•‘                    {{app_name}} Installer                    β•‘
β•‘                        Version {{app_version}}                        β•‘
╠══════════════════════════════════════════════════════════════╣
β•‘                                                              β•‘
β•‘  {{app_description}}  β•‘
β•‘                                                              β•‘
β•‘  This installer will guide you through the setup process.   β•‘
β•‘  You can exit at any time with Ctrl+C.                     β•‘
β•‘                                                              β•‘
β•‘  Estimated installation time: {{estimated_time}}                  β•‘
β•‘  Required disk space: {{required_space}}                         β•‘
β•‘                                                              β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
"@
    
    Write-Host $welcomeText -ForegroundColor Cyan
    Write-Host ""
    
    if ($Script:InteractiveMode) {
        Read-Host "Press Enter to continue or Ctrl+C to exit"
    }
}

function Show-Menu {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$Title,
        
        [Parameter(Mandatory=$true)]
        [string[]]$Options
    )
    
    Write-Host ""
    Write-Host "β”Œβ”€ $Title ─────────────────────────────────────────────────────┐" -ForegroundColor Cyan
    Write-Host "β”‚                                                              β”‚" -ForegroundColor Cyan
    
    for ($i = 0; $i -lt $Options.Length; $i++) {
        $option = "  $($i + 1)) $($Options[$i])"
        Write-Host "β”‚$($option.PadRight(62))β”‚" -ForegroundColor White
    }
    
    Write-Host "β”‚                                                              β”‚" -ForegroundColor Cyan
    Write-Host "β”‚  Q) Quit installer                                          β”‚" -ForegroundColor Yellow
    Write-Host "β”‚  H) Help                                                    β”‚" -ForegroundColor Yellow
    Write-Host "β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜" -ForegroundColor Cyan
    Write-Host ""
}

function Get-MenuChoice {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [int]$MaxChoice
    )
    
    do {
        $choice = Read-Host "Enter your choice [1-$MaxChoice, Q, H]"
        
        switch ($choice.ToUpper()) {
            "Q" {
                Write-Host "Installation cancelled by user." -ForegroundColor Yellow
                Exit-Installation 0
            }
            "H" {
                Show-Help
                continue
            }
            default {
                if ($choice -match '^\d+$' -and [int]$choice -ge 1 -and [int]$choice -le $MaxChoice) {
                    return [int]$choice
                } else {
                    Write-Host "Invalid choice. Please enter a number between 1 and $MaxChoice, Q to quit, or H for help." -ForegroundColor Red
                }
            }
        }
    } while ($true)
}

function Get-ValidatedInput {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$Prompt,
        
        [Parameter(Mandatory=$true)]
        [scriptblock]$Validator,
        
        [Parameter(Mandatory=$false)]
        [string]$Default = ""
    )
    
    do {
        if ($Default) {
            $input = Read-Host "$Prompt [$Default]"
            if ([string]::IsNullOrEmpty($input)) { $input = $Default }
        } else {
            $input = Read-Host $Prompt
        }
        
        if ([string]::IsNullOrEmpty($input) -and [string]::IsNullOrEmpty($Default)) {
            Write-Host "This field is required. Please enter a value." -ForegroundColor Red
            continue
        }
        
        $validationResult = & $Validator $input
        if ($validationResult -eq $true) {
            return $input
        } else {
            Write-Host "Invalid input: $validationResult" -ForegroundColor Red
            Write-Host "Please try again." -ForegroundColor Yellow
        }
    } while ($true)
}

# =============================================================================
# VALIDATION FUNCTIONS
# =============================================================================

function Test-Port {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$Port
    )
    
    # Check if it's a number
    if (-not ($Port -match '^\d+$')) {
        return "Port must be a number"
    }
    
    $portNumber = [int]$Port
    
    # Check range
    if ($portNumber -lt 1024 -or $portNumber -gt 65535) {
        return "Port must be between 1024 and 65535"
    }
    
    # Check if port is in use
    $portInUse = Get-NetTCPConnection -LocalPort $portNumber -ErrorAction SilentlyContinue
    if ($portInUse) {
        if ($Script:InteractiveMode) {
            $continue = Read-Host "Warning: Port $portNumber appears to be in use. Continue anyway? [y/N]"
            if ($continue -notmatch '^[Yy]$') {
                return "Port is in use and user chose not to continue"
            }
        } else {
            return "Port $portNumber is in use"
        }
    }
    
    return $true
}

function Test-Path {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]$Path
    )
    
    # Check if path is valid
    try {
        $null = [System.IO.Path]::GetFullPath($Path)
    } catch {
        return "Invalid path format"
    }
    
    # Check if parent directory exists or can be created
    $parentPath = Split-Path -Path $Path -Parent
    if (-not (Test-Path -Path $parentPath)) {
        try {
            New-Item -Path $parentPath -ItemType Directory -Force -WhatIf | Out-Null
        } catch {
            return "Cannot create parent directory: $parentPath"
        }
    }
    
    return $true
}

# =============================================================================
# SYSTEM CHECKS
# =============================================================================

function Test-SystemRequirements {
    Write-Log "Checking system requirements..." -Level Info
    
    try {
        # Check PowerShell version
        Test-PowerShellVersion
        Write-Log "PowerShell version check passed" -Level Info
        
        # Check Windows version
        Test-WindowsVersion
        $windowsVersion = Get-WindowsVersion
        Write-Log "Windows version: $windowsVersion - compatible" -Level Info
        
        # Check administrator privileges
        if (-not (Test-Administrator)) {
            throw "Administrator privileges are required for installation"
        }
        Write-Log "Administrator privileges confirmed" -Level Info
        
        # Check architecture
        $architecture = $env:PROCESSOR_ARCHITECTURE
        Write-Log "Architecture: $architecture" -Level Info
        
        if ($architecture -notin @("AMD64", "ARM64")) {
            Write-Log "Untested architecture: $architecture" -Level Warning
        }
        
        # Check required tools
        $requiredTools = @({{#each required_tools}}"{{this}}"{{#unless @last}}, {{/unless}}{{/each}})
        foreach ($tool in $requiredTools) {
            if (-not (Get-Command $tool -ErrorAction SilentlyContinue)) {
                throw "Required tool not found: $tool"
            }
        }
        Write-Log "Required tools check passed" -Level Info
        
        # Check disk space
        $installDrive = (Split-Path -Path $Script:InstallPath -Qualifier)
        $driveInfo = Get-WmiObject -Class Win32_LogicalDisk | Where-Object { $_.DeviceID -eq $installDrive }
        $availableSpaceGB = [math]::Round($driveInfo.FreeSpace / 1GB, 2)
        $requiredSpaceGB = {{required_disk_space_gb}}
        
        if ($availableSpaceGB -lt $requiredSpaceGB) {
            throw "Insufficient disk space. Required: ${requiredSpaceGB}GB, Available: ${availableSpaceGB}GB"
        }
        Write-Log "Disk space check passed: ${availableSpaceGB}GB available" -Level Info
        
        Write-Log "System requirements check completed successfully" -Level Info
        return $true
        
    } catch {
        Write-Log "System requirements check failed: $($_.Exception.Message)" -Level Error
        throw
    }
}

# =============================================================================
# CONFIGURATION COLLECTION
# =============================================================================

function Get-Configuration {
    if (-not $Script:InteractiveMode) {
        Write-Log "Using default configuration (non-interactive mode)" -Level Info
        return
    }
    
    Write-Log "Collecting configuration parameters..." -Level Info
    
    Write-Host ""
    Write-Host "╔══════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
    Write-Host "β•‘                    Configuration Setup                      β•‘" -ForegroundColor Cyan
    Write-Host "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•" -ForegroundColor Cyan
    Write-Host ""
    
    {{#each configurable_parameters}}
    {{#if (eq type "choice")}}
    # {{description}}
    Write-Host "{{prompt}}:" -ForegroundColor Yellow
    $choices = @(
        {{#each choices}}
        @{ Value = "{{value}}"; Label = "{{label}}"; Description = "{{description}}" }{{#unless @last}},{{/unless}}
        {{/each}}
    )
    
    for ($i = 0; $i -lt $choices.Length; $i++) {
        Write-Host "  $($i + 1)) $($choices[$i].Label) - $($choices[$i].Description)" -ForegroundColor White
    }
    
    do {
        $choice = Read-Host "Choice [{{default_index}}]"
        if ([string]::IsNullOrEmpty($choice)) { $choice = "{{default_index}}" }
        
        if ($choice -match '^\d+$' -and [int]$choice -ge 1 -and [int]$choice -le $choices.Length) {
            $Script:Config.{{name}} = $choices[[int]$choice - 1].Value
            break
        } else {
            Write-Host "Invalid choice. Please try again." -ForegroundColor Red
        }
    } while ($true)
    {{else}}
    # {{description}}
    $Script:Config.{{name}} = Get-ValidatedInput -Prompt "{{prompt}}" -Validator {
        param($value)
        {{#if validation.pattern}}
        if ($value -notmatch "{{validation.pattern}}") {
            return "Value must match pattern: {{validation.pattern}}"
        }
        {{/if}}
        {{#if validation.min}}
        if ([int]$value -lt {{validation.min}}) {
            return "Value must be at least {{validation.min}}"
        }
        {{/if}}
        {{#if validation.max}}
        if ([int]$value -gt {{validation.max}}) {
            return "Value must be at most {{validation.max}}"
        }
        {{/if}}
        return $true
    } -Default "{{default}}"
    {{/if}}
    
    {{/each}}
    
    Write-Log "Configuration collection completed" -Level Info
}

function Show-ConfigurationSummary {
    Write-Host ""
    Write-Host "╔══════════════════════════════════════════════════════════════╗" -ForegroundColor Cyan
    Write-Host "β•‘                   Configuration Summary                      β•‘" -ForegroundColor Cyan
    Write-Host "╠══════════════════════════════════════════════════════════════╣" -ForegroundColor Cyan
    Write-Host "β•‘                                                              β•‘" -ForegroundColor Cyan
    Write-Host "β•‘  Application: $($Script:AppName) v$($Script:AppVersion)".PadRight(62) + "β•‘" -ForegroundColor White
    Write-Host "β•‘  Installation Path: $($Script:InstallPath)".PadRight(62) + "β•‘" -ForegroundColor White
    {{#each configurable_parameters}}
    Write-Host "β•‘  {{display_name}}: $($Script:Config.{{name}})".PadRight(62) + "β•‘" -ForegroundColor White
    {{/each}}
    Write-Host "β•‘                                                              β•‘" -ForegroundColor Cyan
    Write-Host "╠══════════════════════════════════════════════════════════════╣" -ForegroundColor Cyan
    Write-Host "β•‘                                                              β•‘" -ForegroundColor Cyan
    Write-Host "β•‘  The installer will now proceed with these settings.        β•‘" -ForegroundColor Cyan
    Write-Host "β•‘  This process may take several minutes to complete.         β•‘" -ForegroundColor Cyan
    Write-Host "β•‘                                                              β•‘" -ForegroundColor Cyan
    Write-Host "β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•" -ForegroundColor Cyan
    Write-Host ""
    
    if ($Script:InteractiveMode) {
        $confirm = Read-Host "Proceed with installation? [Y/n]"
        if ($confirm -match '^[Nn]$') {
            Write-Host "Installation cancelled by user." -ForegroundColor Yellow
            Exit-Installation 0
        }
    }
}

# =============================================================================
# INSTALLATION FUNCTIONS
# =============================================================================

function Install-Dependencies {
    if ($SkipDependencies) {
        Write-Log "Skipping dependency installation" -Level Info
        return
    }
    
    Write-Log "Installing dependencies..." -Level Info
    
    # Check for package managers
    $packageManagers = @()
    
    if (Get-Command choco -ErrorAction SilentlyContinue) {
        $packageManagers += "chocolatey"
    }
    
    if (Get-Command winget -ErrorAction SilentlyContinue) {
        $packageManagers += "winget"
    }
    
    if ($packageManagers.Count -eq 0) {
        Write-Log "Installing Chocolatey package manager..." -Level Info
        if (-not $DryRun) {
            Set-ExecutionPolicy Bypass -Scope Process -Force
            [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
            Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))
        }
        $packageManagers += "chocolatey"
    }
    
    Write-Log "Available package managers: $($packageManagers -join ', ')" -Level Info
    
    # Install dependencies
    {{#each windows_dependencies}}
    Write-Log "Installing {{name}}..." -Level Info
    
    if (-not $DryRun) {
        $installed = $false
        
        foreach ($pm in $packageManagers) {
            try {
                switch ($pm) {
                    "chocolatey" {
                        choco install {{chocolatey_name}} -y
                        $installed = $true
                        break
                    }
                    "winget" {
                        winget install {{winget_id}}
                        $installed = $true
                        break
                    }
                }
            } catch {
                Write-Log "Failed to install {{name}} using $pm" -Level Warning
                continue
            }
        }
        
        if (-not $installed) {
            throw "Failed to install dependency: {{name}}"
        }
        
        # Verify installation
        if (-not ({{verify_command}})) {
            throw "Installation verification failed for {{name}}"
        }
    }
    {{/each}}
    
    Write-Log "Dependencies installed successfully" -Level Info
}

# =============================================================================
# CLEANUP AND ERROR HANDLING
# =============================================================================

function Remove-TempFiles {
    if (Test-Path -Path $Script:TempDir) {
        Write-Log "Cleaning up temporary directory: $($Script:TempDir)" -Level Debug
        Remove-Item -Path $Script:TempDir -Recurse -Force -ErrorAction SilentlyContinue
    }
}

function Exit-Installation {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        [int]$ExitCode = 0
    )
    
    Write-Log "Cleaning up and exiting..." -Level Info
    Remove-TempFiles
    
    if ($ExitCode -eq 0) {
        Write-Log "Installation completed successfully!" -Level Info
        
        $successMessage = @"
╔══════════════════════════════════════════════════════════════╗
β•‘                 Installation Complete!                      β•‘
╠══════════════════════════════════════════════════════════════╣
β•‘                                                              β•‘
β•‘  {{app_name}} has been successfully installed.               β•‘
β•‘                                                              β•‘
β•‘  Service status: Get-Service {{service_name}}                β•‘
β•‘  Logs location: {{log_path}}                                 β•‘
β•‘  Configuration: {{config_path}}                              β•‘
β•‘                                                              β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
"@
        Write-Host $successMessage -ForegroundColor Green
    } else {
        Write-Log "Installation failed with exit code: $ExitCode" -Level Error
        Write-Host "Check the log file for details: $($Script:LogFile)" -ForegroundColor Red
    }
    
    exit $ExitCode
}

# =============================================================================
# MAIN INSTALLATION WORKFLOW
# =============================================================================

function Start-Installation {
    try {
        # Create temporary directory
        New-Item -Path $Script:TempDir -ItemType Directory -Force | Out-Null
        
        # Start installation
        Write-Log "Starting $($Script:AppName) installation..." -Level Info
        Write-Log "Log file: $($Script:LogFile)" -Level Info
        
        # Installation steps
        Show-Welcome
        Test-SystemRequirements
        Get-Configuration
        Show-ConfigurationSummary
        
        # Main installation phases
        $totalSteps = {{total_installation_steps}}
        $currentStep = 0
        
        {{#each installation_steps}}
        $currentStep++
        Show-Progress -Current $currentStep -Total $totalSteps -Activity "Installing $($Script:AppName)" -Status "{{description}}"
        {{function_name}}
        {{/each}}
        
        # Final validation
        $currentStep++
        Show-Progress -Current $currentStep -Total $totalSteps -Activity "Installing $($Script:AppName)" -Status "Validating installation"
        Test-Installation
        
        # Success
        Exit-Installation 0
        
    } catch {
        Write-Log "Installation failed: $($_.Exception.Message)" -Level Error
        
        if ($Script:InteractiveMode) {
            Write-Host ""
            Write-Host "Installation failed. Would you like to:" -ForegroundColor Yellow
            Write-Host "1) View the error log" -ForegroundColor White
            Write-Host "2) Attempt to rollback changes" -ForegroundColor White
            Write-Host "3) Exit" -ForegroundColor White
            
            $choice = Read-Host "Choice [3]"
            if ([string]::IsNullOrEmpty($choice)) { $choice = "3" }
            
            switch ($choice) {
                "1" { Get-Content $Script:LogFile | Out-Host -Paging }
                "2" { Invoke-Rollback }
            }
        }
        
        Exit-Installation 1
    }
}

# Execute main function
Start-Installation

Template Features

Windows-Specific Capabilities

  • PowerShell 5.1+ Compatibility: Leverages modern PowerShell features

  • Administrator Privilege Checking: Ensures proper permissions

  • Windows Service Management: Native Windows service integration

  • Package Manager Support: Chocolatey and WinGet integration

  • Registry Management: Windows registry configuration support

Advanced Error Handling

  • Comprehensive Try-Catch: Proper PowerShell error handling

  • Interactive Recovery: User-guided error recovery options

  • Detailed Logging: Structured logging with multiple levels

  • Rollback Capabilities: Automatic cleanup on failure

User Experience Features

  • Rich Console Output: Colored output with progress indicators

  • Interactive Menus: User-friendly configuration collection

  • Input Validation: Robust parameter validation

  • Help System: Built-in help and guidance

Configuration Management

  • Dynamic Parameter Collection: Based on manifest configuration

  • Type-Safe Validation: PowerShell-native type checking

  • Default Value Handling: Intelligent default value management

  • Configuration Persistence: Save and restore configuration settings

This PowerShell template provides enterprise-grade installation capabilities specifically designed for Windows environments while maintaining the same high standards of user experience and reliability as the Bash template.

Last updated