PowerShell Patterns
This skill provides PowerShell scripting patterns and conventions used in the dotfiles project.
Code Style
- •Match existing style: Verb-Noun function names
- •Use comment-based help
- •Export only necessary functions via
Export-ModuleMember - •Windows automation should fail gracefully when run without elevation if elevation is required
Logging Conventions
Stage Headers
Write-Output ":: Stage Name"
- •Use
::prefix - •Print only once per stage using
$actflag - •Set
$act = $trueafter first action
Action Types
- •Dry-run actions:
Write-Output "DRY-RUN: Would <action>"(shown when-DryRunis set) - •Verbose details:
Write-Verbose "<message>"for routine operations - •Skipping actions:
Write-Verbose "Skipping <item>: <reason>"
Note: Logging output does not automatically prevent actions. Always check the $DryRun switch before performing system modifications. The Write-Output "DRY-RUN: ..." pattern is a convention for clarity, but you must still wrap actual work in the else block:
Stage Logging Pattern
$act = $false
foreach ($item in $items) {
if ($shouldProcess) {
if (-not $act) {
$act = $true
Write-Output ":: Stage Name"
}
# Process item
}
}
Idempotency
Check if action is needed before taking it:
- •Check file existence, registry values, installed packages/extensions
- •Skip with verbose message if already correct:
powershell
Write-Verbose "Skipping <item>: already <state>"
Dry-Run Pattern
All functions support -DryRun switch:
function Install-Something {
[CmdletBinding()]
param (
[Parameter(Mandatory = $true)]
[string]$Item,
[Parameter(Mandatory = $false)]
[switch]$DryRun
)
if ($DryRun) {
Write-Output "DRY-RUN: Would install $Item"
} else {
Write-Verbose "Installing $Item"
# actual work
}
}
- •Check
if ($DryRun)before any system modification - •Log intended action with
Write-Output "DRY-RUN: Would <action>" - •Never modify system state when
$DryRunis set
INI Parsing
Always use Read-IniSection helper from Profile.psm1 instead of manual parsing:
$fonts = Read-IniSection -FilePath $configFile -SectionName "fonts"
- •Reads a specific section from an INI file
- •Returns array of non-empty, non-comment lines
Profile Filtering
Use Test-ShouldIncludeSection to check if a section should be processed:
if (Test-ShouldIncludeSection -SectionName $section -ExcludedCategories $excludedCategories) {
# Process this section
}
- •Returns
$trueif ALL required categories in section name are NOT excluded
Use Get-ProfileExclusion to resolve profile to excluded categories in main script:
$excludedCategories = Get-ProfileExclusion -Profile $profile
See the profile-system skill for details on how profile filtering works and section naming conventions.
Configuration Processing Pattern
# Reading from config
$items = Read-IniSection -FilePath $configFile -SectionName "section"
# Get all sections
$content = Get-Content $configFile
$sections = @()
foreach ($line in $content) {
if ($line -match '^\[(.+)\]$') {
$sections += $matches[1]
}
}
# Process each section
foreach ($section in $sections) {
# Checking sections
if (-not (Test-ShouldIncludeSection -SectionName $section -ExcludedCategories $excludedCategories)) {
Write-Verbose "Skipping section [$section]: profile not included"
continue
}
# Process items in section
$items = Read-IniSection -FilePath $configFile -SectionName $section
foreach ($item in $items) {
# Process item
}
}
Error Suppression
Use -ErrorAction SilentlyContinue only when appropriate, prefer explicit checks:
# Prefer explicit check
if (Test-Path $path) {
$content = Get-Content $path
}
# Instead of
$content = Get-Content $path -ErrorAction SilentlyContinue
Configuration Format
Configuration files in conf/ follow these patterns:
- •
symlinks.ini: Uses[windows]section with paths relative tosymlinks/(no leading dot)- •Well-known Windows folders (AppData, Documents, etc.) remain as-is in target
- •Unix-style paths (config, ssh) get prefixed with dot by Symlinks.psm1
- •
registry.ini: Registry paths as sections withname = valueformat- •Section headers are registry paths (e.g.,
[HKCU:\Software\Example]) - •No profile filtering (Windows-only by nature, all settings applied on Windows)
- •Section headers are registry paths (e.g.,
- •All other INI files: Follow section-based format like Linux (e.g.,
[windows],[base])
Rules
- •Use Verb-Noun function names with approved PowerShell verbs
- •Include comment-based help for exported functions
- •Export only necessary functions via
Export-ModuleMember - •Support
-DryRunswitch for all functions that modify system state - •Use
Write-Outputfor stage headers with::prefix - •Use
Write-Verbosefor routine operations and skipped items - •Check idempotency before performing actions
- •Always use
Read-IniSectionhelper for INI parsing - •Use
Test-ShouldIncludeSectionfor profile filtering - •Prefer explicit checks over
-ErrorAction SilentlyContinue