# 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 ```powershell #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: ```powershell 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: ```powershell 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: ```powershell 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: ```powershell @{ Application = @{ WindowWidth = 800 WindowHeight = 600 } Email = @{ SMTPServer = '' From = '' To = '' } } ``` - Never put actual credentials in `.psd1` config — use placeholder strings with comments ## Testing - Do **not** create test files — I'll run the code directly to verify it works - If asked to write tests, use **Pester** with `Invoke-Pester -Path .\Tests\ -Output Detailed` ## 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`)