Skip to content

PowerShell

PowerShell is a shell built around objects, pipelines, and cmdlet conventions. Code that ignores these conventions — using aliases in scripts, returning formatted strings, skipping -WhatIf support — breaks the pipeline and frustrates users. These 15 principles come from the PowerShell Best Practices and the community's hard-won experience.

Optional External Tool Augmentation

Consent-first external tooling

External tool execution is optional and disabled by default. Use --enable-external-tools (CLI) or enable_external_tools=true (MCP) to opt in. Missing tools should return recommendations; no automatic installs occur during analysis.

Tool Default invocation Output
pwsh pwsh -Command Invoke-ScriptAnalyzer -ScriptDefinition $input Text / structured stderr

Zen Principles

15 principles across 12 categories, drawn from PoshCode Style Guide.

Clarity · 1 principle Correctness · 1 principle Debugging · 1 principle Design · 2 principles Documentation · 1 principle Error Handling · 1 principle Idioms · 1 principle Naming · 2 principles Readability · 2 principles Robustness · 1 principle Safety · 1 principle Scope · 1 principle

Rule ID Principle Category Severity Dogma
ps-001 Use approved verbs Naming 7 ZEN-UNAMBIGUOUS-NAME
ps-002 Use proper error handling Error Handling 9 ZEN-FAIL-FAST
ps-003 Use cmdlet binding and parameters Design 8 ZEN-RIGHT-ABSTRACTION
ps-004 Use PascalCase for function names Naming 7 ZEN-UNAMBIGUOUS-NAME
ps-005 Use Write-Verbose and Write-Debug Debugging 6 ZEN-EXPLICIT-INTENT
ps-006 Avoid positional parameters Readability 7 ZEN-UNAMBIGUOUS-NAME
ps-007 Use pipeline properly Idioms 7 ZEN-RIGHT-ABSTRACTION
ps-008 Use -WhatIf and -Confirm support Safety 8 ZEN-FAIL-FAST
ps-009 Use splatting for readability Readability 6 ZEN-UNAMBIGUOUS-NAME
ps-010 Validate parameters properly Robustness 8 ZEN-FAIL-FAST
ps-011 Use comment-based help Documentation 7 ZEN-UNAMBIGUOUS-NAME
ps-012 Avoid aliases in scripts Clarity 6 ZEN-EXPLICIT-INTENT, ZEN-UNAMBIGUOUS-NAME
ps-013 Return objects, not formatted text Design 8 ZEN-RIGHT-ABSTRACTION
ps-014 Use script scope carefully Scope 7 ZEN-STRICT-FENCES, ZEN-EXPLICIT-INTENT
ps-015 Handle null values explicitly Correctness 7 ZEN-EXPLICIT-INTENT, ZEN-FAIL-FAST
ps-001 — Use approved verbs

Function names should use approved PowerShell verbs

Universal Dogmas: ZEN-UNAMBIGUOUS-NAME Common Violations:

  • Non-standard verbs in function names
  • Custom verbs without approval
  • Unclear function naming

Detectable Patterns:

  • function CustomVerb-Noun

Recommended Fix

Get-Verb to see approved verbs, use Verb-Noun pattern

ps-002 — Use proper error handling

Use try/catch/finally and -ErrorAction

Universal Dogmas: ZEN-FAIL-FAST Common Violations:

  • Commands without error handling
  • Not using try/catch
  • Ignoring $Error variable
  • Silent failures

Detectable Patterns:

  • command without try/catch
  • -ErrorAction SilentlyContinue abuse
ps-003 — Use cmdlet binding and parameters

Functions should use [CmdletBinding()] and proper parameters

Universal Dogmas: ZEN-RIGHT-ABSTRACTION Common Violations:

  • Functions without [CmdletBinding()]
  • Using $args instead of parameters
  • Missing parameter validation
  • No parameter attributes

Detectable Patterns:

  • !CmdletBinding

Recommended Fix

[CmdletBinding()] with [Parameter()] attributes

ps-004 — Use PascalCase for function names

Follow PowerShell naming conventions

Universal Dogmas: ZEN-UNAMBIGUOUS-NAME Common Violations:

  • camelCase function names
  • snake_case in PowerShell
  • All lowercase names
  • Inconsistent casing

Thresholds:

Parameter Default
naming_convention PascalCase for functions, camelCase for variables
ps-005 — Use Write-Verbose and Write-Debug

Use proper output streams for logging

Universal Dogmas: ZEN-EXPLICIT-INTENT Common Violations:

  • Using Write-Host for logging
  • Not using Write-Verbose
  • No debug output
  • Mixing output streams

Detectable Patterns:

  • Write-Host for logging

Recommended Fix

Write-Verbose, Write-Debug, Write-Information

ps-006 — Avoid positional parameters

Always use named parameters in scripts

Universal Dogmas: ZEN-UNAMBIGUOUS-NAME Common Violations:

  • Positional parameter usage
  • Unclear command calls
  • Not using -ParameterName syntax

Detectable Patterns:

  • $args

Recommended Fix

Get-ChildItem -Path $path -Filter $filter

ps-007 — Use pipeline properly

Leverage PowerShell pipeline for object processing

Universal Dogmas: ZEN-RIGHT-ABSTRACTION Common Violations:

  • ForEach-Object loops instead of pipeline
  • Not using pipeline when appropriate
  • Breaking pipeline chain unnecessarily

Detectable Patterns:

  • !|

Recommended Fix

Get-Process | Where-Object { $_.CPU -gt 10 }

ps-008 — Use -WhatIf and -Confirm support

Implement ShouldProcess for destructive operations

Universal Dogmas: ZEN-FAIL-FAST Common Violations:

  • Destructive commands without -WhatIf
  • Not using ShouldProcess
  • No user confirmation for dangerous operations

Detectable Patterns:

  • !WhatIf

Recommended Fix

[CmdletBinding(SupportsShouldProcess)]

ps-009 — Use splatting for readability

Use splatting for multiple parameters

Universal Dogmas: ZEN-UNAMBIGUOUS-NAME Common Violations:

  • Long parameter lists inline
  • Not using @splat syntax
  • Unreadable command calls

Detectable Patterns:

  • !@{

Recommended Fix

$params = @{...}; Command @params

ps-010 — Validate parameters properly

Use parameter validation attributes

Universal Dogmas: ZEN-FAIL-FAST Common Violations:

  • No [ValidateNotNull()]
  • No [ValidateSet()]
  • Missing [ValidateRange()]
  • No input validation

Detectable Patterns:

  • ![Validate

Recommended Fix

[ValidateNotNullOrEmpty()], [ValidateSet('value1','value2')]

ps-011 — Use comment-based help

Include .SYNOPSIS, .DESCRIPTION, .EXAMPLE

Universal Dogmas: ZEN-UNAMBIGUOUS-NAME Common Violations:

  • Functions without help comments
  • Missing .SYNOPSIS
  • No usage examples
  • Incomplete documentation

Detectable Patterns:

  • !.SYNOPSIS
ps-012 — Avoid aliases in scripts

Use full cmdlet names, not aliases

Universal Dogmas: ZEN-EXPLICIT-INTENT, ZEN-UNAMBIGUOUS-NAME Common Violations:

  • Using aliases like 'gci' instead of Get-ChildItem
  • Using '%' instead of ForEach-Object
  • Using '?' instead of Where-Object
  • Unclear abbreviated commands

Detectable Patterns:

  • gci, ls, dir, cat, etc.

Recommended Fix

Full cmdlet names

ps-013 — Return objects, not formatted text

Return structured objects for pipeline compatibility

Universal Dogmas: ZEN-RIGHT-ABSTRACTION Common Violations:

  • Returning formatted strings
  • Using Format-Table in functions
  • Breaking pipeline with text output
  • Not using PSCustomObject

Detectable Patterns:

  • Format-Table
  • Out-String

Recommended Fix

[PSCustomObject]@{Property='Value'}

ps-014 — Use script scope carefully

Be explicit about variable scope

Universal Dogmas: ZEN-STRICT-FENCES, ZEN-EXPLICIT-INTENT Common Violations:

  • Unintended global variables
  • Not using $script: or $global:
  • Scope pollution
  • Variable leakage

Detectable Patterns:

  • $global:
  • $script:
ps-015 — Handle null values explicitly

Check for null before operations

Universal Dogmas: ZEN-EXPLICIT-INTENT, ZEN-FAIL-FAST Common Violations:

  • Not checking for $null
  • NullReferenceException in scripts
  • Assuming objects exist
  • No null coalescing

Detectable Patterns:

  • !$null

Recommended Fix

if ($null -ne $variable) or $variable ?? 'default'

Detector Catalog

Clarity

Detector What It Catches Rule IDs
PowerShellAliasUsageDetector Detect built-in aliases (gci, ls, %, ?) used in scripts ps-012

Correctness

Detector What It Catches Rule IDs
PowerShellNullHandlingDetector Detect functions and param blocks that never check for $null ps-015

Debugging

Detector What It Catches Rule IDs
PowerShellVerboseDebugDetector Detect Write-Host calls that should use Write-Verbose or Write-Debug ps-005

Design

Detector What It Catches Rule IDs
PowerShellCmdletBindingDetector Detect advanced functions missing [CmdletBinding()] and param() ps-003
PowerShellReturnObjectsDetector Detect functions that return formatted text instead of objects ps-013

Documentation

Detector What It Catches Rule IDs
PowerShellCommentHelpDetector Detect functions missing comment-based help with .SYNOPSIS ps-011

Error Handling

Detector What It Catches Rule IDs
PowerShellErrorHandlingDetector Detect scripts that lack any form of error handling ps-002

Idioms

Detector What It Catches Rule IDs
PowerShellPipelineUsageDetector Detect ForEach-Object or foreach loops that should use pipelines ps-007

Naming

Detector What It Catches Rule IDs
PowerShellApprovedVerbDetector Detect function names that use unapproved PowerShell verbs ps-001
PowerShellPascalCaseDetector Detect function names that violate PascalCase naming conventions ps-004

Readability

Detector What It Catches Rule IDs
PowerShellPositionalParamsDetector Detect reliance on $args for positional parameter access ps-006
PowerShellSplattingDetector Detect cmdlet calls with many inline parameters that should use splatting ps-009

Robustness

Detector What It Catches Rule IDs
PowerShellParameterValidationDetector Detect param() blocks that lack [Validate*] attributes ps-010

Safety

Detector What It Catches Rule IDs
PowerShellShouldProcessDetector Detect destructive cmdlet verbs missing SupportsShouldProcess ps-008

Scope

Detector What It Catches Rule IDs
PowerShellScopeUsageDetector Detect explicit $global: and $script: scope modifiers ps-014
Principle → Detector Wiring
%%{init: {"theme": "base", "flowchart": {"useMaxWidth": false, "htmlLabels": true, "nodeSpacing": 40, "rankSpacing": 60}}}%%
graph TD
ps_001["ps-001<br/>Use approved verbs"]
ps_002["ps-002<br/>Use proper error handling"]
ps_003["ps-003<br/>Use cmdlet binding and pa..."]
ps_004["ps-004<br/>Use PascalCase for functi..."]
ps_005["ps-005<br/>Use Write-Verbose and Wri..."]
ps_006["ps-006<br/>Avoid positional paramete..."]
ps_007["ps-007<br/>Use pipeline properly"]
ps_008["ps-008<br/>Use -WhatIf and -Confirm ..."]
ps_009["ps-009<br/>Use splatting for readabi..."]
ps_010["ps-010<br/>Validate parameters prope..."]
ps_011["ps-011<br/>Use comment-based help"]
ps_012["ps-012<br/>Avoid aliases in scripts"]
ps_013["ps-013<br/>Return objects, not forma..."]
ps_014["ps-014<br/>Use script scope carefull..."]
ps_015["ps-015<br/>Handle null values explic..."]
det_PowerShellAliasUsageDetector["Power Shell<br/>Alias Usage"]
ps_012 --> det_PowerShellAliasUsageDetector
det_PowerShellApprovedVerbDetector["Power Shell<br/>Approved Verb"]
ps_001 --> det_PowerShellApprovedVerbDetector
det_PowerShellCmdletBindingDetector["Power Shell<br/>Cmdlet Binding"]
ps_003 --> det_PowerShellCmdletBindingDetector
det_PowerShellCommentHelpDetector["Power Shell<br/>Comment Help"]
ps_011 --> det_PowerShellCommentHelpDetector
det_PowerShellErrorHandlingDetector["Power Shell<br/>Error Handling"]
ps_002 --> det_PowerShellErrorHandlingDetector
det_PowerShellNullHandlingDetector["Power Shell<br/>Null Handling"]
ps_015 --> det_PowerShellNullHandlingDetector
det_PowerShellParameterValidationDetector["Power Shell<br/>Parameter Validation"]
ps_010 --> det_PowerShellParameterValidationDetector
det_PowerShellPascalCaseDetector["Power Shell<br/>Pascal Case"]
ps_004 --> det_PowerShellPascalCaseDetector
det_PowerShellPipelineUsageDetector["Power Shell<br/>Pipeline Usage"]
ps_007 --> det_PowerShellPipelineUsageDetector
det_PowerShellPositionalParamsDetector["Power Shell<br/>Positional Params"]
ps_006 --> det_PowerShellPositionalParamsDetector
det_PowerShellReturnObjectsDetector["Power Shell<br/>Return Objects"]
ps_013 --> det_PowerShellReturnObjectsDetector
det_PowerShellScopeUsageDetector["Power Shell<br/>Scope Usage"]
ps_014 --> det_PowerShellScopeUsageDetector
det_PowerShellShouldProcessDetector["Power Shell<br/>Should Process"]
ps_008 --> det_PowerShellShouldProcessDetector
det_PowerShellSplattingDetector["Power Shell<br/>Splatting"]
ps_009 --> det_PowerShellSplattingDetector
det_PowerShellVerboseDebugDetector["Power Shell<br/>Verbose Debug"]
ps_005 --> det_PowerShellVerboseDebugDetector
Detector Class Hierarchy
%%{init: {"theme": "base"}}%%
classDiagram
    direction TB
    class ViolationDetector {
        <<abstract>>
        +detect(context, config)
    }
    class det_01["Power Shell Alias Usage"]
    ViolationDetector <|-- det_01
    class det_02["Power Shell Approved Verb"]
    ViolationDetector <|-- det_02
    class det_03["Power Shell Cmdlet Binding"]
    ViolationDetector <|-- det_03
    class det_04["Power Shell Comment Help"]
    ViolationDetector <|-- det_04
    class det_05["Power Shell Error Handling"]
    ViolationDetector <|-- det_05
    class det_06["Power Shell Null Handling"]
    ViolationDetector <|-- det_06
    class det_07["Power Shell Parameter Validation"]
    ViolationDetector <|-- det_07
    class det_08["Power Shell Pascal Case"]
    ViolationDetector <|-- det_08
    class det_09["Power Shell Pipeline Usage"]
    ViolationDetector <|-- det_09
    class det_10["Power Shell Positional Params"]
    ViolationDetector <|-- det_10
    class det_11["Power Shell Return Objects"]
    ViolationDetector <|-- det_11
    class det_12["Power Shell Scope Usage"]
    ViolationDetector <|-- det_12
    class det_13["Power Shell Should Process"]
    ViolationDetector <|-- det_13
    class det_14["Power Shell Splatting"]
    ViolationDetector <|-- det_14
    class det_15["Power Shell Verbose Debug"]
    ViolationDetector <|-- det_15
Analysis Pipeline
%%{init: {"theme": "base", "flowchart": {"useMaxWidth": false, "htmlLabels": true, "nodeSpacing": 50, "rankSpacing": 70}}}%%
flowchart TD
Source(["Source Code"]) --> Parse["Parse & Tokenize"]
Parse --> Metrics["Compute Metrics"]
Metrics --> Pipeline{"15 Detectors"}
Pipeline --> Collect["Aggregate Violations"]
Collect --> Result(["AnalysisResult<br/>15 principles"])
Analysis States
%%{init: {"theme": "base"}}%%
stateDiagram-v2
    [*] --> Ready
    Ready --> Parsing : analyze(code)
    Parsing --> Computing : AST ready
    Computing --> Detecting : metrics ready
    Detecting --> Reporting : 15 detectors run
    Reporting --> [*] : AnalysisResult
    Parsing --> Reporting : parse error (best-effort)

Configuration

languages:
  powershell:
    enabled: true
    pipeline:
      - type: powershell_approved_verbs
        approved_verbs: ['get', 'set', 'new', 'remove', 'add', 'clear', 'start', 'stop']

See Also