Files
AI/preferences/powershell-wpf.md
2026-04-03 00:56:48 -07:00

118 lines
4.0 KiB
Markdown

# 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`
## Common Gotchas
- **Variable followed by colon:** `"$var: text"` fails — PowerShell treats `: text` as part of the variable name. Use `"${var}: text"` instead.
- **Returning arrays from functions:** A single-item array gets unrolled on return. Use `return ,$array` (comma prefix) to force PowerShell to return the array as-is.
- **UTF-8 file writes:** Use `[System.IO.File]::WriteAllText($path, $content, [System.Text.Encoding]::UTF8)` instead of `Out-File` — avoids BOM and encoding issues with special characters.
## 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`)