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
This commit is contained in:
GraceSolutions
2026-05-01 15:17:43 -04:00
parent cd982938d3
commit 825dfdab79
5 changed files with 1337 additions and 84 deletions
+129 -1
View File
@@ -1,4 +1,132 @@
---
type: "manual"
type: "agent_requested"
description: "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 `}`
```powershell
# 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
```powershell
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
```powershell
# 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`