# CLAUDE.md: PowerShell

## Commands
- Lint: `Invoke-ScriptAnalyzer -Path . -Recurse -Settings ./PSScriptAnalyzerSettings.psd1` (use the defaults if no settings file)
- Test: `Invoke-Pester -Path ./tests -Output Detailed`
- Target PowerShell 7 (`pwsh`) unless `#Requires -Version 5.1` or the README says Windows PowerShell must be supported. Check before using 7-only syntax (`??`, `?.`, ternary, `ForEach-Object -Parallel`).

## Writing code
- Every function is an advanced function: `[CmdletBinding()]`, an approved verb (`Get-Verb`) in `Verb-Noun` form, typed `param()` with `[Parameter(Mandatory)]` and validation attributes (`[ValidateSet()]`, `[ValidateNotNullOrEmpty()]`).
- Start scripts with `#Requires` lines, `Set-StrictMode -Version Latest` and `$ErrorActionPreference = 'Stop'`. Use `try/catch` around external calls and rethrow with context; never swallow errors silently.
- Functions that change state (files, services, registry, cloud resources) declare `SupportsShouldProcess` and wrap the change in `if ($PSCmdlet.ShouldProcess($target, $action))`, so `-WhatIf` and `-Confirm` work.
- Output objects (`[pscustomobject]`), not formatted text. No `Write-Host` for data; use `Write-Verbose`, `Write-Information`, `Write-Warning`. `Format-*` only at the very end of interactive use.
- No aliases (`%`, `?`, `ls`, `gci`) or positional parameters in committed code. Use splatting for calls with more than three parameters.
- Paths with `Join-Path` and `-LiteralPath` for user-supplied paths; never build paths by string concatenation.
- Secrets: `[SecureString]`/`PSCredential` parameters or the SecretManagement module; never hardcode or print credentials. Don't use `Invoke-Expression` on input.
- Modules: one function per file under `Public/` and `Private/`, exported explicitly in the `.psd1` (`FunctionsToExport`, no wildcards). Comment-based help (`.SYNOPSIS`, `.EXAMPLE`) on every public function.

## Done when
ScriptAnalyzer reports no errors or warnings for changed files and Pester tests (with mocks for external commands) pass. Never run destructive commands against real systems to test.
