Files
GraceSolutions 825dfdab79 Enhanced OpenSSH configuration with certificate auth, service management, and security features
Features added:
- Certificate authentication with Windows CA trust bridge
- CA filtering via regex inclusion/exclusion expressions
- Password authentication disable option
- Service auto-start and start management
- Config backup before modification (timestamped)
- Config validation (sshd -t) with automatic rollback on failure
- SFTP subsystem configured by default
- Public key management with deduplication
- Key pair generation (ed25519, rsa, ecdsa)

Toolkit enhancements:
- ConvertFrom-CertificateToPEM: Added -IncludePrivateKey, -ThumbprintList, -CreateCABundle
- Updated coding standards in PowershellScripts.md

Documentation:
- Comprehensive README with examples and troubleshooting
- Added .augment folder to .gitignore
2026-05-01 15:17:43 -04:00

5.0 KiB

type, description
type description
agent_requested Use these for powershell scripts

PowerShell Coding Standards

Output and Logging

  • No Write-Host
  • No AI icons in log messages and strings
  • Only Write-Verbose, Write-Warning, Write-Error, and Write-Output as needed
  • When using toolkit's $WriteLogMessage: do NOT add timestamps (handled by scriptblock), do NOT check for null
  • Centralized logging format: [TimestampUTC] - [Level] - Message
  • Use Start-Transcript for script logging (no -Append, no custom log appending functions)
  • Transcript log name should be based on the BaseName of the script

Object Construction

  • Use $Var = New-Object -TypeName 'Type' instead of [Type]::New()
  • Use OrderedDictionary for building object properties, then cast to PSObject
  • Use New-Object -TypeName 'System.Collections.Specialized.OrderedDictionary' for splatting parameters
  • Splatting dictionary properties should be indented one additional level from the variable assignment

Collections

  • Use generic lists: New-Object -TypeName 'System.Collections.Generic.List[System.String]'
  • Use .Add() and .AddRange() methods - never use += for array concatenation
  • Use HashSet<T> when checking for existence/uniqueness

Paths and File System

  • Use [System.IO.FileInfo] for file path parameters
  • Use [System.IO.DirectoryInfo] for directory path parameters
  • Build paths with: [System.IO.FileInfo][System.IO.Path]::Combine(Path1, Path2, Leaf) or [System.IO.DirectoryInfo][System.IO.Path]::Combine(Path1, Path2)
  • Use [System.IO.File]::Exists() for file existence checks
  • Use [System.IO.Directory]::Exists() for directory existence checks (not Test-Path)
  • Use environment variable paths like $Env:ProgramFiles instead of hardcoded paths like 'C:\Program Files'
  • ScriptPath should be dynamically determined and used for logpath and name

File Encoding

  • Use WriteAllText or WriteAllLines with non-BOM encoding
  • Use ASCII encoding for config files to avoid BOM issues
  • PowerShell's [System.Text.Encoding]::UTF8 adds BOM - avoid for config files

URLs and Web Requests

  • URLs should be System.URI with full scheme (e.g., https://)
  • Use System.Net.WebClient with default credentials for downloads instead of Invoke-WebRequest

Conditions and Filtering

Where-Object Syntax

  • Always wrap each condition in parentheses
  • No spaces after { or before }
# Correct - Single condition
Where-Object {($_.Type -eq 'CABundle')}

# Correct - Multiple conditions
Where-Object {($_.Type -eq 'CABundle') -and ($_.CertificateCount -gt 0)}

# Incorrect
Where-Object { $_.Type -eq 'CABundle' }

Switch Statements (Preferred over If Statements)

  • Use Switch ($VarName) with {($_ -eq $True)} and {($_ -eq $False)} for single boolean
  • Use Switch ($True) only for unrelated conditions
  • Use Default for else cases
  • Set conditional properties when splatting using switch statements
Switch ($SomeCondition)
  {
      {($_ -eq $True)}
        {
            # Do something
        }

      Default
        {
            # Else case
        }
  }

Combined Conditions

  • Each sub-condition must be wrapped in parentheses
  • Use -eq $True explicitly for switch parameters
# Correct
Switch (($EnableFeature.IsPresent -eq $True) -and ($ConfigExists -eq $True))

# Incorrect
Switch ($EnableFeature.IsPresent -and $ConfigExists)

Code Formatting

  • Do NOT put { on the same line - line break and indent one level
  • Code inside block indented one more level
  • Closing } at same indent as opening {
  • Applies to all blocks: Try/Catch/Finally, Switch, For, Function, etc.
  • Nested blocks continue the pattern

Loops

  • Use long loop format: For ($Counter Index etc) {}
  • Use Counter and Count variables for easy Write-Progress integration

Script Structure

  • Main script should always have Try/Catch/Finally
  • PS7 compatible for Linux/Mac portability (though not the main goal)
  • Environment variables only for paths and non-sensitive config, never for secrets/API keys
  • Here-strings should use $($Var) syntax to bake in values at generation time
  • Service names should be generic to the product, not specific to single use case

String Checks

  • Use ([System.String]::IsNullOrEmpty($var) -eq $False) instead of implicit boolean
  • Use ([System.String]::IsNullOrWhiteSpace($var) -eq $False) when whitespace matters

PowerShell Modules

  • No async/await
  • No updating progress bars from background threads
  • No workarounds without asking first
  • Code quality over quick delivery
  • Think before implementation - reusable code: BaseCmdlets, inherits, Classes, Models, Methods
  • Add Write-Progress to cmdlets where appropriate
  • Module folder should NOT be gitignored
  • Build artifacts go into Artifacts folder
  • All docs except README go into docs folder
  • Scripts go into scripts folder
  • Maintain a changelog
  • Avoid excessive printing to threads
  • Threads should track progress for resume capability
  • Release format: yyyy.mm.dd.hhmm