Files
AI/preferences/powershell-wpf.md

3.8 KiB

PowerShell & WPF Standards

General Rules

  • Always include #Requires -Version 5.1 at the top of every .ps1 file
  • Use $script: scope for module-level variables — never $Global: unless absolutely necessary
  • Keep credential and sensitive values out of code — load from config files or environment variables only
  • Use .psd1 files for all external configuration (not JSON, not XML, not hardcoded)

Code Structure

  • Organize code using #region / #endregion blocks with descriptive names
  • Group related functions within their own region
  • One function per logical task — keep functions focused
#region Configuration Functions

function Initialize-Config {
    ...
}

#endregion

#region UI Functions

function Show-MainWindow {
    ...
}

#endregion

Naming Conventions

  • Functions: PascalCase Verb-Noun (Get-UserConfig, Show-MainWindow, Initialize-App)
  • Variables: PascalCase ($UserConfig, $ScriptRoot, $AppVersion)
  • Script-scoped: $script:VariableName
  • Use approved PowerShell verbs (Get-, Set-, Show-, New-, Remove-, Initialize-, Invoke-, etc.)

Error Handling

  • Use try/catch for all operations that can fail (file I/O, network, registry, etc.)
  • Use Write-Warning for non-fatal errors that should be logged but allow execution to continue
  • Use Write-Error for failures that should stop the current operation
  • Create centralized helper functions for user-facing messages:
function Show-Error   { param([string]$Message, [string]$Title = "Error") ... }
function Show-Warning { param([string]$Message, [string]$Title = "Warning") ... }
function Show-Info    { param([string]$Message, [string]$Title = "Information") ... }

WPF Specifics

  • Always ensure STA thread mode for WPF — include an STA re-launch block at the top of .ps1 entry points
  • Load all WPF assemblies at the top of the file:
Add-Type -AssemblyName PresentationFramework
Add-Type -AssemblyName PresentationCore
Add-Type -AssemblyName WindowsBase
Add-Type -AssemblyName System.Windows.Forms
  • Define XAML as a here-string and load it via [System.Windows.Markup.XamlReader]::Parse()
  • Use $script: variables to hold window/control references so they're accessible across functions

Modules

  • Shared/reusable functions belong in a .psm1 module under a Modules/ folder
  • The main .ps1 entry point imports the module at startup:
Import-Module "$script:AppRoot\Modules\ProjectName.psm1" -Force
  • Module files follow the same naming, scoping, and region conventions

Configuration Files

  • Use .psd1 (PowerShell Data Files) for all config — they're native, typed, and easy to version
  • Always provide a default config creation block if the file doesn't exist
  • Config keys should use PascalCase nested hashtables:
@{
    Application = @{
        WindowWidth  = 800
        WindowHeight = 600
    }
    Email = @{
        SMTPServer = ''
        From       = ''
        To         = ''
    }
}
  • Never put actual credentials in .psd1 config — use placeholder strings with comments

Testing

  • Use Pester for unit testing
  • Always provide a Pester test file alongside new functions
  • At minimum, test: happy path, expected failure cases, and edge cases
  • Run tests with: Invoke-Pester -Path .\Tests\ -Output Detailed
# Tests/Get-UserConfig.Tests.ps1
Describe "Get-UserConfig" {
    It "Returns default config when file does not exist" { ... }
    It "Loads config from valid .psd1 file" { ... }
}

Comments

  • Comment the why, not the what — code should be readable on its own
  • Use inline comments for non-obvious logic
  • Use block comments (<# ... #>) for function documentation (.SYNOPSIS, .DESCRIPTION, .PARAMETER, .EXAMPLE)