PowerShell Expert Skill <identity Automation Architect and Windows Internals Specialist -- expert in high-scale scripting, system orchestration, and secure administrative patterns. Specialist in PowerShell 7 Core, Desired State Configuration (DSC), Just Enough Administration (JEA), and Pester testing. </identity <capabilities - Design and implement robust automation scripts using PowerShell 7+ - Audit scripts for security (injection, plaintext secrets, unsafe aliases) - Optimize pipeline performance using parallelization and background jobs - Manage complex system states across Windows, Linux…

)] # Regex pattern\n[ValidateScript({ $_ -gt 0 })] # Custom script validation\n```\n\n### Pipeline Support\n\n```powershell\nparam(\n [Parameter(Mandatory, ValueFromPipeline, ValueFromPipelineByPropertyName)]\n [string[]]$Name\n)\n\nprocess {\n foreach ($Item in $Name) {\n # Process one at a time for streaming\n }\n}\n```\n\n### ShouldProcess for Destructive Operations\n\n```powershell\n[CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'High')]\nparam(...)\n\nprocess {\n if ($PSCmdlet.ShouldProcess($target, 'Delete')) {\n Remove-Item $target\n }\n}\n```\n\n### OutputType Attribute\n\n```powershell\n[OutputType([PSCustomObject])]\n[OutputType([System.IO.FileInfo])]\n```\n\n## Comment-Based Help\n\nAlways include comment-based help for public functions:\n\n```powershell\n\u003c#\n.SYNOPSIS\n One-line description.\n.DESCRIPTION\n Detailed description. Can be multi-line.\n.PARAMETER ComputerName\n Description of ComputerName parameter.\n.PARAMETER Credential\n Description of Credential parameter.\n.EXAMPLE\n Get-Something -ComputerName 'server1'\n Example description.\n.EXAMPLE\n 'server1', 'server2' | Get-Something\n Pipeline example.\n.INPUTS\n System.String\n.OUTPUTS\n PSCustomObject with Name, Status, Data properties.\n.NOTES\n Author: Your Name\n Version: 1.0\n.LINK\n https://docs.example.com/Get-Something\n#>\n```\n\n## Code Style\n\n### No Aliases in Scripts\n\n```powershell\n# BAD (aliases - break on other systems/profiles)\nls | ? { $_.Name -match '*.ps1' } | % { $_.FullName }\n\n# GOOD (full cmdlet names)\nGet-ChildItem | Where-Object { $_.Name -match '*.ps1' } | ForEach-Object { $_.FullName }\n```\n\n### Splatting for Long Commands\n\n```powershell\n# BAD (long line, hard to read)\nInvoke-Command -ComputerName $server -Credential $cred -ScriptBlock $sb -ErrorAction Stop\n\n# GOOD (splatting)\n$invokeParams = @{\n ComputerName = $server\n Credential = $cred\n ScriptBlock = $sb\n ErrorAction = 'Stop'\n}\nInvoke-Command @invokeParams\n```\n\n### Output Objects, Not Text\n\n```powershell\n# BAD: Returns text\n\"Server: $name, Status: $status\"\n\n# GOOD: Returns structured objects\n[PSCustomObject]@{\n Server = $name\n Status = $status\n}\n```\n\n### Write-Output vs Write-Host\n\n- `Write-Output` — sends to pipeline (use for data)\n- `Write-Host` — directly to console, bypasses pipeline (use only for display)\n- `Write-Verbose` — informational messages with -Verbose\n- `Write-Warning` — warnings (non-terminating issues)\n- `Write-Error` — non-terminating errors\n- `throw` — terminating errors\n\n### Avoid Format-\\* in Functions\n\n```powershell\n# BAD: Format-Table breaks pipeline\nfunction Get-Data {\n Get-Process | Format-Table # Can't pipe this output\n}\n\n# GOOD: Return objects, let caller format\nfunction Get-Data {\n Get-Process # Caller can pipe to Format-Table, Select-Object, etc.\n}\n```\n\n## Error Handling Best Practices\n\n1. Use specific exception types in catch blocks\n2. Use `-ErrorAction Stop` on individual cmdlets rather than `$ErrorActionPreference`\n3. Always re-throw if you can't handle the error: `throw`\n4. Log errors with context: `Write-Error -ErrorRecord $_`\n5. Use `finally` for cleanup that must always run\n\n## Compatibility Notes (5.1 vs 7+)\n\n| Feature | PS 5.1 | PS 7+ |\n| ----------------------------- | --------------- | ------------------- |\n| `??` null-coalescing | No | Yes |\n| `?.` null-conditional | No | Yes |\n| Ternary `? :` | No | Yes |\n| `&&` / `\\|\\|` pipeline chains | No | Yes |\n| `ForEach-Object -Parallel` | No | Yes |\n| `Start-ThreadJob` | Module required | Built-in |\n| Cross-platform | Windows only | Windows/Linux/macOS |\n| UTF-8 default | No | Yes |\n\nAdd `#Requires -Version 7.0` at top of scripts that use PS7+ features.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5316,"content_sha256":"d2367ea8eeaabb44b52a8c387e5cd45736cbd291a4c533ca8c32b1df45daaae7"},{"filename":"references/devops-integration.md","content":"# PowerShell DevOps Integration\n\n## GitHub Actions with PowerShell\n\n### Basic Workflow\n\n```yaml\nname: PowerShell CI\n\non:\n push:\n branches: [main]\n pull_request:\n branches: [main]\n\njobs:\n test:\n runs-on: windows-latest\n steps:\n - uses: actions/checkout@v4\n\n - name: Install Dependencies\n shell: pwsh\n run: |\n Set-PSRepository -Name PSGallery -InstallationPolicy Trusted\n Install-PSResource -Name Pester -Scope CurrentUser\n Install-PSResource -Name PSScriptAnalyzer -Scope CurrentUser\n\n - name: Run PSScriptAnalyzer\n shell: pwsh\n run: |\n $results = Invoke-ScriptAnalyzer -Path ./src -Recurse -Severity Error\n if ($results.Count -gt 0) {\n $results | Format-Table -AutoSize\n throw \"PSScriptAnalyzer found $($results.Count) error(s)\"\n }\n Write-Host \"PSScriptAnalyzer: No errors found\"\n\n - name: Run Pester Tests\n shell: pwsh\n run: |\n $config = New-PesterConfiguration\n $config.Run.Path = './tests'\n $config.Output.Verbosity = 'Detailed'\n $config.TestResult.Enabled = $true\n $config.TestResult.OutputPath = 'TestResults.xml'\n $config.TestResult.OutputFormat = 'NUnitXml'\n $config.Run.Exit = $true\n Invoke-Pester -Configuration $config\n\n - name: Publish Test Results\n uses: actions/upload-artifact@v4\n if: always()\n with:\n name: test-results\n path: TestResults.xml\n```\n\n### Cross-Platform Matrix\n\n```yaml\njobs:\n test:\n strategy:\n matrix:\n os: [windows-latest, ubuntu-latest, macos-latest]\n runs-on: ${{ matrix.os }}\n steps:\n - uses: actions/checkout@v4\n - name: Run Tests\n shell: pwsh # 'pwsh' works on all platforms; 'powershell' is Windows-only\n run: Invoke-Pester -Path ./tests -CI\n```\n\n### Publish to PSGallery from CI\n\n```yaml\n- name: Publish Module\n if: github.ref == 'refs/heads/main'\n shell: pwsh\n env:\n PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }}\n run: |\n Publish-PSResource -Path ./MyModule -Repository PSGallery -ApiKey $env:PSGALLERY_API_KEY\n```\n\n## Azure DevOps Pipeline\n\n```yaml\ntrigger:\n branches:\n include:\n - main\n\npool:\n vmImage: 'windows-latest'\n\nsteps:\n - task: PowerShell@2\n displayName: 'Run Pester Tests'\n inputs:\n targetType: inline\n pwsh: true # Use pwsh (cross-platform) not powershell\n script: |\n Install-PSResource -Name Pester -Scope CurrentUser\n $config = New-PesterConfiguration\n $config.Run.Path = './tests'\n $config.TestResult.Enabled = $true\n $config.TestResult.OutputPath = '$(System.DefaultWorkingDirectory)/TestResults.xml'\n $config.TestResult.OutputFormat = 'NUnitXml'\n $config.Run.Exit = $true\n Invoke-Pester -Configuration $config\n\n - task: PublishTestResults@2\n displayName: 'Publish Test Results'\n condition: always()\n inputs:\n testResultsFormat: NUnit\n testResultsFiles: '**/TestResults.xml'\n```\n\n## Azure PowerShell Module\n\n```powershell\n# Install Az module (modular)\nInstall-PSResource -Name Az -Scope CurrentUser\n\n# Or install only needed submodules\nInstall-PSResource -Name Az.Compute -Scope CurrentUser\nInstall-PSResource -Name Az.Storage -Scope CurrentUser\n\n# Authenticate\nConnect-AzAccount # Interactive\nConnect-AzAccount -ServicePrincipal -Credential $spCred -Tenant $tenantId # SP\n\n# Managed Identity (in Azure resources)\nConnect-AzAccount -Identity\n\n# Common operations\n$vms = Get-AzVM -ResourceGroupName 'MyRG'\nNew-AzResourceGroup -Name 'MyRG' -Location 'eastus'\nGet-AzStorageAccount | Where-Object { $_.Kind -eq 'StorageV2' }\n```\n\n## AWS Tools for PowerShell\n\n```powershell\n# Install modular AWS.Tools\nInstall-PSResource -Name AWS.Tools.Common -Scope CurrentUser\nInstall-PSResource -Name AWS.Tools.S3 -Scope CurrentUser\nInstall-PSResource -Name AWS.Tools.EC2 -Scope CurrentUser\n\n# Configure credentials\nSet-AWSCredential -AccessKey $accessKey -SecretKey $secretKey -StoreAs 'default'\n\n# Use profiles\nSet-AWSCredential -ProfileName 'production'\n\n# Common operations\nGet-S3Bucket\nGet-EC2Instance | Select-Object -ExpandProperty Instances\nWrite-S3Object -BucketName 'my-bucket' -Key 'folder/file.txt' -File 'C:\\file.txt'\n```\n\n## PowerShell in Docker\n\n```dockerfile\n# Windows container\nFROM mcr.microsoft.com/powershell:7.4-windowsservercore-ltsc2022\n\nWORKDIR /app\nCOPY MyModule/ ./MyModule/\nCOPY tests/ ./tests/\n\nRUN pwsh -Command \"Install-PSResource -Name Pester -Scope AllUsers\"\n\nCMD [\"pwsh\", \"-Command\", \"Invoke-Pester -Path ./tests -CI\"]\n```\n\n```dockerfile\n# Linux container (cross-platform PS)\nFROM mcr.microsoft.com/powershell:7.4-ubuntu-22.04\n\nWORKDIR /app\nCOPY . .\n\nRUN pwsh -Command \"Install-PSResource -Name Pester -Scope AllUsers && Install-PSResource -Name PSScriptAnalyzer -Scope AllUsers\"\n\nCMD [\"pwsh\", \"-Command\", \"Invoke-Pester -CI\"]\n```\n\n## Environment-Specific Configuration\n\n```powershell\n# Best practice: Use environment-specific config files\n$env = $env:DEPLOYMENT_ENV ?? 'development'\n$configPath = Join-Path $PSScriptRoot \"config.$env.json\"\n$config = Get-Content $configPath | ConvertFrom-Json\n\n# Or use #Requires for environment validation\n#Requires -Modules Az.Accounts\n#Requires -Version 7.2\n#Requires -RunAsAdministrator\n\n# Environment detection in CI\n$isCI = [bool]($env:CI -or $env:TF_BUILD -or $env:GITHUB_ACTIONS)\nif ($isCI) {\n $ErrorActionPreference = 'Stop'\n $ProgressPreference = 'SilentlyContinue' # Speeds up downloads in CI\n}\n```\n\n## CI Best Practices\n\n1. Use `pwsh` shell target (not `powershell`) for cross-platform compatibility\n2. Run Pester with `-CI` flag for machine-readable output\n3. Publish NUnit test results for CI dashboards\n4. Run PSScriptAnalyzer as a gate before tests\n5. Store API keys in CI secrets, not code\n6. Use `$ProgressPreference = 'SilentlyContinue'` to speed up downloads\n7. Set `$ErrorActionPreference = 'Stop'` in CI scripts to fail fast\n8. Use `Install-PSResource` (PSResourceGet) not `Install-Module` (deprecated)\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6086,"content_sha256":"ce2076cee8ea71a77e92ddd97ce13fc2d7325f3f8b3eae96a7907157a056e321"},{"filename":"references/module-authoring.md","content":"# PowerShell Module Authoring\n\n## Module Structure\n\n```\nMyModule/\n MyModule.psd1 (module manifest - REQUIRED)\n MyModule.psm1 (root module file)\n Public/ (exported functions)\n Get-Something.ps1\n Set-Something.ps1\n New-Something.ps1\n Remove-Something.ps1\n Private/ (internal helper functions, NOT exported)\n Invoke-Helper.ps1\n ConvertTo-Internal.ps1\n Tests/ (Pester tests)\n Get-Something.Tests.ps1\n en-US/\n MyModule-help.xml (MAML help - generated by platyPS)\n MyModule.Format.ps1xml (optional formatting rules)\n MyModule.Types.ps1xml (optional type extensions)\n LICENSE\n README.md\n```\n\n## Creating the Manifest\n\n```powershell\n# Create initial manifest\nNew-ModuleManifest -Path .\\MyModule\\MyModule.psd1 `\n -RootModule 'MyModule.psm1' `\n -ModuleVersion '1.0.0' `\n -Guid (New-Guid) `\n -Author 'Your Name' `\n -CompanyName 'Your Company' `\n -Copyright \"(c) $(Get-Date -Format yyyy) Your Name. All rights reserved.\" `\n -Description 'Brief module description' `\n -PowerShellVersion '7.0' `\n -FunctionsToExport @('Get-Something', 'Set-Something', 'New-Something', 'Remove-Something') `\n -CmdletsToExport @() `\n -AliasesToExport @() `\n -VariablesToExport @() `\n -RequiredModules @(\n @{ ModuleName = 'Az.Accounts'; ModuleVersion = '2.0.0' }\n ) `\n -Tags @('tag1', 'tag2', 'automation') `\n -ProjectUri 'https://github.com/owner/MyModule' `\n -LicenseUri 'https://github.com/owner/MyModule/blob/main/LICENSE' `\n -IconUri 'https://example.com/icon.png' `\n -ReleaseNotes 'Initial release'\n```\n\n**IMPORTANT**: Never recreate the manifest — the GUID must stay constant.\nUse `Update-ModuleManifest` for subsequent changes:\n\n```powershell\nUpdate-ModuleManifest -Path .\\MyModule\\MyModule.psd1 `\n -ModuleVersion '1.1.0' `\n -FunctionsToExport @('Get-Something', 'Set-Something', 'New-Something', 'Remove-Something', 'Get-NewFeature')\n```\n\n## Root Module (MyModule.psm1)\n\n```powershell\n# Load private functions\n$Private = Get-ChildItem -Path \"$PSScriptRoot\\Private\\*.ps1\" -ErrorAction SilentlyContinue\nforeach ($file in $Private) {\n . $file.FullName\n}\n\n# Load and export public functions\n$Public = Get-ChildItem -Path \"$PSScriptRoot\\Public\\*.ps1\" -ErrorAction SilentlyContinue\nforeach ($file in $Public) {\n . $file.FullName\n}\n\n# Export using manifest (preferred over Export-ModuleMember)\n# FunctionsToExport in .psd1 handles this\n```\n\n## Semantic Versioning\n\nFollow [SemVer](https://semver.org/):\n\n- `MAJOR.MINOR.PATCH` (e.g., `2.1.3`)\n- MAJOR: Breaking changes\n- MINOR: New backward-compatible features\n- PATCH: Bug fixes\n\nPSGallery pre-release: append `-beta1`, `-rc1` suffix to version string.\n\n## PSGallery Publishing\n\n### Prerequisites\n\n```powershell\n# Install PSResourceGet (modern replacement for PowerShellGet)\nInstall-PSResource -Name Microsoft.PowerShell.PSResourceGet -Scope CurrentUser\n\n# Get API key from https://www.powershellgallery.com/account/apikeys\n$apiKey = Get-Secret -Name 'PSGalleryApiKey' -AsPlainText\n```\n\n### Pre-publish Checklist\n\n```powershell\n# 1. Run Pester tests\nInvoke-Pester -Path .\\Tests\\ -CI\n\n# 2. Run PSScriptAnalyzer\n$results = Invoke-ScriptAnalyzer -Path .\\MyModule\\ -Recurse -Severity Error\nif ($results.Count -gt 0) { throw 'PSScriptAnalyzer errors found' }\n\n# 3. Validate manifest\nTest-ModuleManifest -Path .\\MyModule\\MyModule.psd1\n\n# 4. Check module imports cleanly\nImport-Module .\\MyModule\\MyModule.psd1 -Force -ErrorAction Stop\n\n# 5. Verify exports\nGet-Command -Module MyModule | Select-Object Name, CommandType\n```\n\n### Publish\n\n```powershell\n# Publish to PSGallery\nPublish-PSResource -Path .\\MyModule -Repository PSGallery -ApiKey $apiKey\n\n# Publish pre-release\nPublish-PSResource -Path .\\MyModule -Repository PSGallery -ApiKey $apiKey -Prerelease\n```\n\n## Module Versioning in CI/CD\n\n```powershell\n# Bump version in manifest from CI pipeline\n$version = '1.2.0'\nUpdate-ModuleManifest -Path .\\MyModule\\MyModule.psd1 -ModuleVersion $version\n```\n\n## Comment-Based Help for Module\n\nEach public function must have comment-based help. Use platyPS to generate external MAML help:\n\n```powershell\nInstall-PSResource -Name platyPS\n\n# Generate markdown help docs\nNew-MarkdownHelp -Module MyModule -OutputFolder .\\docs\\\n\n# Update markdown after changes\nUpdate-MarkdownHelp -Path .\\docs\\\n\n# Generate MAML XML from markdown\nNew-ExternalHelp -Path .\\docs\\ -OutputPath .\\en-US\\ -Force\n```\n\n## Module Types (Choosing the Right Type)\n\n| Type | Extension | Use Case |\n| --------------- | ---------- | ----------------------------------- |\n| Script module | .psm1 | General purpose, most common |\n| Binary module | .dll | High performance, compiled C# |\n| Manifest module | .psd1 only | Grouping other modules |\n| Dynamic module | In-memory | Temporary, programmatically created |\n\n## Best Practices\n\n1. **Always use a manifest** — gives you metadata, versioning, dependency management\n2. **Separate public/private** — prevents accidental exposure of internal helpers\n3. **Never use `Export-ModuleMember` AND `FunctionsToExport`** — pick one (manifest preferred)\n4. **Use specific exports, never `'*'`** — performance and security\n5. **Include Pester tests in `Tests/`**\n6. **Run PSScriptAnalyzer before each publish**\n7. **Keep GUID constant** — required for PSGallery identity\n8. **Use semantic versioning** — clear communication of breaking changes\n9. **Generate help from comment-based help** — use platyPS for MAML\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5595,"content_sha256":"88d7ab29bb4ed32bcd26966219e72b3f57293c48fcfd38ba6c394c2da2324ac5"},{"filename":"references/performance-patterns.md","content":"# PowerShell Performance Patterns\n\n## Measuring Performance\n\n```powershell\n# Time a block of code\n$elapsed = Measure-Command {\n Get-ChildItem -Recurse C:\\Windows\\System32\n}\nWrite-Host \"Elapsed: $($elapsed.TotalSeconds)s\"\n\n# Compare two approaches\n$approach1 = Measure-Command {\n $result = @()\n 1..10000 | ForEach-Object { $result += $_ }\n}\n\n$approach2 = Measure-Command {\n $result = [System.Collections.Generic.List[int]]::new()\n 1..10000 | ForEach-Object { $result.Add($_) }\n}\n\n\"Array +=: $($approach1.TotalMilliseconds)ms\"\n\"List.Add: $($approach2.TotalMilliseconds)ms\"\n```\n\n## Array Building (Critical)\n\n```powershell\n# BAD: O(n²) — creates new array on each iteration\n$array = @()\nforeach ($item in $source) { $array += $item }\n\n# GOOD: O(n) — amortized constant append\n$list = [System.Collections.Generic.List[object]]::new()\nforeach ($item in $source) { $list.Add($item) }\n\n# Convert back to array if needed\n$array = $list.ToArray()\n\n# Also good: ArrayList (non-generic)\n$list = [System.Collections.ArrayList]::new()\n$list.Add($item) | Out-Null # Suppress return value\n\n# Best for known size: pre-allocated array\n$array = [object[]]::new(10000)\nfor ($i = 0; $i -lt 10000; $i++) { $array[$i] = $i }\n```\n\n## Pipeline vs Loop Performance\n\n```powershell\n# ForEach-Object pipeline — functional but slower (overhead per object)\n1..10000 | ForEach-Object { $_ * 2 }\n\n# foreach statement — fastest for simple loops\n$results = [System.Collections.Generic.List[int]]::new()\nforeach ($n in 1..10000) { $results.Add($n * 2) }\n\n# .NET LINQ (fastest for filtering/projecting)\n$data = 1..10000\n$results = [System.Linq.Enumerable]::Where($data, [Func[int,bool]]{ param($x) $x % 2 -eq 0 })\n```\n\n## Parallel Processing (PS7+)\n\n```powershell\n# ForEach-Object -Parallel for CPU-bound work\n$servers = 'server1', 'server2', 'server3', 'server4', 'server5'\n$results = $servers | ForEach-Object -Parallel {\n $pingResult = Test-Connection $_ -Count 1 -Quiet\n [PSCustomObject]@{\n Server = $_\n Online = $pingResult\n }\n} -ThrottleLimit 10\n\n# Pass variables into parallel scope with $using:\n$threshold = 80\nGet-Process | ForEach-Object -Parallel {\n if ($_.CPU -gt $using:threshold) {\n [PSCustomObject]@{ Name = $_.Name; CPU = $_.CPU }\n }\n} -ThrottleLimit 4\n```\n\n## ThreadJob for Background I/O\n\n```powershell\n# Start-ThreadJob (lightweight, lower overhead than Start-Job)\n$jobs = 'server1', 'server2', 'server3' | ForEach-Object {\n $server = $_\n Start-ThreadJob -ScriptBlock {\n param($s)\n Invoke-RestMethod \"https://$s/api/health\" -TimeoutSec 5\n } -ArgumentList $server -ThrottleLimit 5\n}\n\n# Wait and collect results\n$results = $jobs | Receive-Job -Wait -AutoRemoveJob\n```\n\n## .NET Methods for Hot Paths\n\n```powershell\n# File I/O — .NET is faster than cmdlets for large files\n# BAD (Get-Content loads entire file into PS objects)\n$lines = Get-Content -Path .\\large.log\n\n# GOOD (.NET ReadAllLines is faster for one-shot reads)\n$lines = [System.IO.File]::ReadAllLines('C:\\large.log')\n\n# BEST (streaming for large files)\n$reader = [System.IO.StreamReader]::new('C:\\large.log')\nwhile (-not $reader.EndOfStream) {\n $line = $reader.ReadLine()\n if ($line -match 'ERROR') { $line }\n}\n$reader.Dispose()\n\n# String operations — .NET StringBuilder for concatenation\n$sb = [System.Text.StringBuilder]::new()\nforeach ($line in $lines) { [void]$sb.AppendLine($line) }\n$result = $sb.ToString()\n```\n\n## Hashtable for O(1) Lookups\n\n```powershell\n# BAD: O(n) search — array contains check\n$validValues = @('red', 'green', 'blue')\nif ($color -in $validValues) { ... } # Scans entire array\n\n# GOOD: O(1) lookup — hashtable/hashset\n$validValues = @{ red = $true; green = $true; blue = $true }\nif ($validValues.ContainsKey($color)) { ... }\n\n# Or HashSet\n$validSet = [System.Collections.Generic.HashSet[string]]::new([string[]]@('red', 'green', 'blue'))\nif ($validSet.Contains($color)) { ... }\n```\n\n## Provider Filtering vs Client Filtering\n\n```powershell\n# BAD: Client-side filtering (downloads all, filters locally)\nGet-ChildItem C:\\Windows -Recurse | Where-Object { $_.Name -like '*.dll' }\n\n# GOOD: Provider-side filtering (server/filesystem filters before returning)\nGet-ChildItem C:\\Windows -Recurse -Filter '*.dll'\n\n# BAD: Download all log entries then filter\nGet-WinEvent -LogName System | Where-Object { $_.Level -eq 2 }\n\n# GOOD: Filter at source\nGet-WinEvent -FilterHashtable @{ LogName = 'System'; Level = 2 }\n```\n\n## WMI/CIM Performance\n\n```powershell\n# BAD: Get-WmiObject (deprecated, slower, DCOM)\nGet-WmiObject -Class Win32_Process\n\n# GOOD: Get-CimInstance (faster, uses WS-Man/DCOM fallback)\nGet-CimInstance -ClassName Win32_Process\n\n# GOOD: CimSession for multiple queries to same server\n$session = New-CimSession -ComputerName 'server1'\n$procs = Get-CimInstance -CimSession $session -ClassName Win32_Process\n$disks = Get-CimInstance -CimSession $session -ClassName Win32_LogicalDisk\n$session | Remove-CimSession\n```\n\n## Runspaces for Advanced Parallelism\n\n```powershell\n# For high-volume I/O-bound parallelism (hundreds of targets)\n$runspacePool = [System.Management.Automation.Runspaces.RunspacePool]::CreateRunspacePool(1, 50)\n$runspacePool.Open()\n\n$jobs = foreach ($server in $servers) {\n $ps = [powershell]::Create()\n $ps.RunspacePool = $runspacePool\n [void]$ps.AddScript({\n param($srv)\n Test-Connection $srv -Count 1 -Quiet\n }).AddArgument($server)\n\n @{\n PowerShell = $ps\n Handle = $ps.BeginInvoke()\n Server = $server\n }\n}\n\n# Collect results\nforeach ($job in $jobs) {\n $result = $job.PowerShell.EndInvoke($job.Handle)\n [PSCustomObject]@{ Server = $job.Server; Online = $result }\n $job.PowerShell.Dispose()\n}\n\n$runspacePool.Close()\n$runspacePool.Dispose()\n```\n\n## Performance Tips Summary\n\n| Scenario | Recommendation |\n| ----------------------------------- | -------------------------------------------------- |\n| Building large arrays | `List[T]`, not `@() +=` |\n| Tight loops | `foreach` statement, not `ForEach-Object` |\n| Large file reads | `[System.IO.File]::ReadAllLines()` or StreamReader |\n| Filtering collections | Hashtable/HashSet for O(1) lookups |\n| CIM/WMI queries | `Get-CimInstance`, not `Get-WmiObject` |\n| Multiple CIM queries to same server | `CimSession` |\n| Provider-level filtering | Use `-Filter` parameter, not `Where-Object` |\n| I/O-bound parallel work | `Start-ThreadJob` or runspaces |\n| CPU-bound parallel work | `ForEach-Object -Parallel` |\n| Profiling | `Measure-Command` |\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":6948,"content_sha256":"a32908beda61994519a82d958ef3cc082f501359e416f015a0b747bbc8a49eec"},{"filename":"references/research-requirements.md","content":"# powershell-expert Research Requirements\n\nGenerated: 2026-02-28\n\n## Skill Description\n\n'Master PowerShell scripting and Windows system administration for 2026. Enforces cross-platform compatibility (PS 7+), secure credential handling, and high-fidelity automation patterns.'\n\n## Research Areas\n\n- Current best practices for powershell-expert\n- Industry standards and tooling\n- Integration patterns\n\n## Source References\n\n- To be populated by skill-updater research phase\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":472,"content_sha256":"42be34c52267e68605697501f51a348be243f89cca30abc89883d1af013810d7"},{"filename":"references/security-patterns.md","content":"# PowerShell Security Patterns\n\n## Execution Policy\n\n```powershell\n# Check current policy\nGet-ExecutionPolicy -List\n\n# Set policy for current user (safe default for developers)\nSet-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser\n\n# Common values:\n# Restricted - No scripts (Windows client default)\n# AllSigned - All scripts must be signed\n# RemoteSigned - Downloaded scripts must be signed; local run freely\n# Unrestricted - All scripts run (with warning for downloaded)\n# Bypass - No restrictions (CI/CD pipelines)\n\n# Bypass for single script (without changing policy)\npowershell.exe -ExecutionPolicy Bypass -File .\\script.ps1\n```\n\n## Script Signing\n\n```powershell\n# Get code signing certificate\n$cert = Get-ChildItem -Path Cert:\\CurrentUser\\My -CodeSigningCert\n\n# Sign a script\nSet-AuthenticodeSignature -FilePath .\\script.ps1 -Certificate $cert\n\n# Verify signature\n$sig = Get-AuthenticodeSignature -FilePath .\\script.ps1\n$sig.Status # Should be 'Valid'\n```\n\n## Credential Management\n\n### Interactive (Never Hardcode)\n\n```powershell\n# Prompt user securely\n$cred = Get-Credential -Message 'Enter your credentials'\n$securePass = Read-Host -AsSecureString -Prompt 'Password'\n```\n\n### SecretManagement Module (Production Standard)\n\n```powershell\n# Install\nInstall-PSResource -Name Microsoft.PowerShell.SecretManagement\nInstall-PSResource -Name Microsoft.PowerShell.SecretStore # Local vault\n\n# Register vault\nRegister-SecretVault -Name 'LocalVault' -ModuleName Microsoft.PowerShell.SecretStore\n\n# Store secrets\nSet-Secret -Name 'APIKey' -Secret 'your-api-key'\nSet-Secret -Name 'DBPassword' -Secret (ConvertTo-SecureString 'pass' -AsPlainText -Force)\n\n# Retrieve secrets\n$apiKey = Get-Secret -Name 'APIKey' -AsPlainText\n$dbPass = Get-Secret -Name 'DBPassword' # Returns SecureString by default\n\n# List all secrets\nGet-SecretInfo\n\n# Remove secret\nRemove-Secret -Name 'APIKey'\n```\n\n### PSCredential Pattern\n\n```powershell\n# Construct from components\n$username = 'domain\\user'\n$securePass = Get-Secret -Name 'MyPassword' # SecureString from vault\n$cred = [PSCredential]::new($username, $securePass)\n\n# Use with cmdlets\nConnect-AzAccount -Credential $cred\nInvoke-Command -ComputerName 'server1' -Credential $cred -ScriptBlock { ... }\n```\n\n## Avoid Insecure Patterns\n\n```powershell\n# BAD: Plaintext password in code\n$password = 'MySecretPassword'\n\n# BAD: ConvertTo-SecureString from plaintext (only for testing)\n$secure = ConvertTo-SecureString 'MyPassword' -AsPlainText -Force\n\n# BAD: Invoke-Expression with user input (injection risk)\nInvoke-Expression $userInput\n\n# GOOD: Validate and restrict user input\n$allowedValues = @('start', 'stop', 'restart')\nif ($action -notin $allowedValues) {\n throw \"Invalid action: $action\"\n}\n```\n\n## Constrained Language Mode\n\n```powershell\n# Check language mode\n$ExecutionContext.SessionState.LanguageMode\n# FullLanguage | ConstrainedLanguage | RestrictedLanguage | NoLanguage\n\n# Constrained mode restricts:\n# - Add-Type\n# - COM object creation\n# - .NET type methods\n# - Reflection\n\n# Set constrained mode (system-wide security measure)\n# Typically configured via WDAC/AppLocker policies\n```\n\n## Just Enough Administration (JEA)\n\n```powershell\n# Create JEA role capability file\nNew-PSRoleCapabilityFile -Path .\\Capabilities\\HelpDesk.psrc `\n -VisibleCmdlets @(\n 'Get-Service',\n @{ Name = 'Restart-Service'; Parameters = @{ Name = 'Name'; ValidateSet = 'spooler', 'w32time' } }\n ) `\n -VisibleFunctions 'Get-DiskUsage' `\n -VisibleProviders 'FileSystem'\n\n# Create JEA session configuration\nNew-PSSessionConfigurationFile -Path .\\SessionConfigs\\JEA.pssc `\n -SessionType RestrictedRemoteServer `\n -RoleDefinitions @{\n 'DOMAIN\\HelpDesk' = @{ RoleCapabilities = 'HelpDesk' }\n } `\n -RunAsVirtualAccount\n\n# Register JEA endpoint\nRegister-PSSessionConfiguration -Name 'JEA_HelpDesk' `\n -Path .\\SessionConfigs\\JEA.pssc `\n -Force\n\n# Connect to JEA endpoint\nEnter-PSSession -ComputerName 'server1' -ConfigurationName 'JEA_HelpDesk'\n```\n\n## Input Validation Best Practices\n\n```powershell\nfunction Invoke-SafeCommand {\n param(\n [Parameter(Mandatory)]\n [ValidateSet('start', 'stop', 'restart')]\n [string]$Action,\n\n [Parameter(Mandatory)]\n [ValidatePattern('^[a-zA-Z0-9_-]+

PowerShell Expert Skill <identity Automation Architect and Windows Internals Specialist -- expert in high-scale scripting, system orchestration, and secure administrative patterns. Specialist in PowerShell 7 Core, Desired State Configuration (DSC), Just Enough Administration (JEA), and Pester testing. </identity <capabilities - Design and implement robust automation scripts using PowerShell 7+ - Audit scripts for security (injection, plaintext secrets, unsafe aliases) - Optimize pipeline performance using parallelization and background jobs - Manage complex system states across Windows, Linux…

)] # Allow only safe characters\n [string]$ServiceName\n )\n\n # Never use: Start-Service $userInput (unvalidated)\n # Always validate before using in commands\n switch ($Action) {\n 'start' { Start-Service -Name $ServiceName -ErrorAction Stop }\n 'stop' { Stop-Service -Name $ServiceName -ErrorAction Stop }\n 'restart' { Restart-Service -Name $ServiceName -ErrorAction Stop }\n }\n}\n```\n\n## Script Security Checklist\n\n- [ ] No hardcoded credentials (use SecretManagement)\n- [ ] Input validated before use (ValidateSet, ValidatePattern, ValidateScript)\n- [ ] No Invoke-Expression with user input\n- [ ] No -AsPlainText except in tests\n- [ ] Script signed if distributed\n- [ ] #Requires -RunAsAdministrator when needed\n- [ ] Sensitive data removed from error messages\n- [ ] Transcript logging enabled for audit trails\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":5184,"content_sha256":"b61ca5b02cedae5e6b50f8f5bfe79f02e75318c28826f916adec50e57b905c6f"},{"filename":"references/testing-patterns.md","content":"# PowerShell Testing Patterns\n\n## Pester 5 (Current Standard)\n\n### Installation\n\n```powershell\nInstall-PSResource -Name Pester -Repository PSGallery -Scope CurrentUser\nImport-Module Pester -MinimumVersion 5.0\n```\n\n### Test File Structure\n\n```powershell\n# MyFunction.Tests.ps1\nBeforeAll {\n # Load the function under test\n . $PSCommandPath.Replace('.Tests.ps1', '.ps1')\n # Or for module functions:\n Import-Module \"$PSScriptRoot/../MyModule.psm1\" -Force\n}\n\nDescribe 'Function-Name' {\n Context 'Normal operation' {\n It 'Returns expected output for valid input' {\n $result = Function-Name -Parameter 'value'\n $result | Should -Be 'expected'\n }\n\n It 'Returns PSCustomObject with correct properties' {\n $result = Function-Name -Parameter 'value'\n $result | Should -BeOfType [PSCustomObject]\n $result.Name | Should -Not -BeNullOrEmpty\n }\n }\n\n Context 'Error handling' {\n It 'Throws on null input' {\n { Function-Name -Parameter $null } | Should -Throw\n }\n\n It 'Does not throw on invalid but non-null input' {\n { Function-Name -Parameter 'bad' } | Should -Not -Throw\n }\n }\n}\n```\n\n### Should Assertions\n\n```powershell\n$value | Should -Be 42 # Exact equality\n$value | Should -BeExactly 'CaseSensitive' # Case-sensitive equality\n$value | Should -BeGreaterThan 0\n$value | Should -BeLessThan 100\n$value | Should -BeIn @('A', 'B', 'C')\n$value | Should -BeNullOrEmpty\n$value | Should -Not -BeNullOrEmpty\n$value | Should -BeOfType [System.IO.FileInfo]\n$value | Should -Match 'pattern' # Regex match\n$value | Should -Contain 'item' # Collection contains\n{ $block } | Should -Throw\n{ $block } | Should -Throw -ErrorId 'ErrorIdValue'\n{ $block } | Should -Not -Throw\n```\n\n### Mocking\n\n```powershell\nDescribe 'Function with external dependency' {\n BeforeAll {\n Mock Get-ChildItem {\n [PSCustomObject]@{ Name = 'file.txt'; Length = 1024 }\n }\n\n # Mock with parameter filter\n Mock Invoke-RestMethod {\n @{ Status = 'OK'; Data = 'result' }\n } -ParameterFilter { $Uri -like '*api.example.com*' }\n }\n\n It 'Calls Get-ChildItem with correct path' {\n $result = Get-SomeData -Path 'C:\\temp'\n Should -Invoke Get-ChildItem -Times 1 -ParameterFilter { $Path -eq 'C:\\temp' }\n }\n\n It 'Uses mocked data correctly' {\n $result = Get-SomeData -Path 'C:\\temp'\n $result.FileName | Should -Be 'file.txt'\n }\n}\n```\n\n### TestDrive and TestRegistry\n\n```powershell\nDescribe 'File operations' {\n It 'Creates a file in TestDrive' {\n $path = Join-Path $TestDrive 'test.txt'\n 'content' | Out-File $path\n Test-Path $path | Should -BeTrue\n }\n}\n\nDescribe 'Registry operations' {\n It 'Reads from TestRegistry' {\n # TestRegistry is automatically cleaned up\n $key = Join-Path $TestRegistry 'HKCU:\\Software\\Test'\n New-Item $key | Out-Null\n Test-Path $key | Should -BeTrue\n }\n}\n```\n\n### Running Pester Tests\n\n```powershell\n# Run all tests in current directory\nInvoke-Pester\n\n# Run specific test file\nInvoke-Pester -Path .\\tests\\MyFunction.Tests.ps1\n\n# Run with detailed output\nInvoke-Pester -Path .\\tests\\ -Output Detailed\n\n# CI mode (throws on failure, NUnit output)\nInvoke-Pester -Path .\\tests\\ -CI\n\n# Run only tests matching a name\nInvoke-Pester -Path .\\tests\\ -TestName '*error handling*'\n\n# Code coverage\nInvoke-Pester -Path .\\tests\\ -CodeCoverage .\\src\\*.ps1 -CodeCoverageOutputFile coverage.xml\n```\n\n### Pester Configuration Object\n\n```powershell\n$config = New-PesterConfiguration\n$config.Run.Path = '.\\tests\\'\n$config.Output.Verbosity = 'Detailed'\n$config.CodeCoverage.Enabled = $true\n$config.CodeCoverage.Path = '.\\src\\*.ps1'\n$config.TestResult.Enabled = $true\n$config.TestResult.OutputPath = 'TestResults.xml'\n$config.TestResult.OutputFormat = 'NUnitXml'\n\nInvoke-Pester -Configuration $config\n```\n\n## PSScriptAnalyzer\n\n### Installation\n\n```powershell\nInstall-PSResource -Name PSScriptAnalyzer -Repository PSGallery\n```\n\n### Basic Usage\n\n```powershell\n# Analyze a single file\nInvoke-ScriptAnalyzer -Path .\\script.ps1\n\n# Analyze entire module/directory\nInvoke-ScriptAnalyzer -Path .\\MyModule\\ -Recurse\n\n# Analyze with summary\nInvoke-ScriptAnalyzer -Path .\\MyModule\\ -Recurse -ReportSummary\n\n# Return only specific severity\nInvoke-ScriptAnalyzer -Path .\\script.ps1 -Severity Error, Warning\n\n# Include specific rules only\nInvoke-ScriptAnalyzer -Path .\\script.ps1 -IncludeRule PSAvoidUsingPlainTextForPassword\n\n# Exclude specific rules\nInvoke-ScriptAnalyzer -Path .\\script.ps1 -ExcludeRule PSAvoidUsingWriteHost\n```\n\n### Common Rules\n\n| Rule | Severity | Description |\n| ---------------------------------------------- | ----------- | ---------------------------------- |\n| PSAvoidUsingCmdletAliases | Warning | Avoid aliases like `ls`, `%`, `?` |\n| PSAvoidUsingPositionalParameters | Warning | Use named parameters |\n| PSUseDeclaredVarsMoreThanAssignments | Warning | Variables assigned but not used |\n| PSAvoidUsingPlainTextForPassword | Error | Don't use plaintext passwords |\n| PSAvoidUsingConvertToSecureStringWithPlainText | Error | Secure string from plaintext |\n| PSUseShouldProcessForStateChangingFunctions | Warning | ShouldProcess on verb functions |\n| PSUseApprovedVerbs | Warning | Only use approved PowerShell verbs |\n| PSAvoidUsingWriteHost | Information | Use Write-Output instead |\n| PSAvoidUsingInvokeExpression | Error | Security risk |\n\n### PSScriptAnalyzer in CI (GitHub Actions)\n\n```yaml\n- name: Run PSScriptAnalyzer\n shell: pwsh\n run: |\n $results = Invoke-ScriptAnalyzer -Path ./src -Recurse -ReportSummary\n $errors = $results | Where-Object Severity -eq 'Error'\n if ($errors.Count -gt 0) {\n $errors | Format-Table -AutoSize\n throw \"PSScriptAnalyzer found $($errors.Count) error(s)\"\n }\n```\n\n### Settings File\n\nCreate `.vscode/PSScriptAnalyzerSettings.psd1` or `PSScriptAnalyzerSettings.psd1` in module root:\n\n```powershell\n@{\n Severity = @('Error', 'Warning')\n ExcludeRules = @(\n 'PSAvoidUsingWriteHost' # Intentional in interactive scripts\n )\n Rules = @{\n PSUseConsistentIndentation = @{\n Enable = $true\n IndentationSize = 4\n }\n PSAlignAssignmentStatement = @{\n Enable = $true\n CheckHashtable = $true\n }\n }\n}\n```\n\n## TDD Workflow for PowerShell\n\n1. Write failing Pester test first\n2. Run: `Invoke-Pester -Path .\\tests\\MyFunction.Tests.ps1` → verify RED\n3. Implement minimal function code\n4. Run again → verify GREEN\n5. Refactor\n6. Run PSScriptAnalyzer: `Invoke-ScriptAnalyzer -Path .\\src\\`\n7. Fix any analyzer warnings\n8. Commit\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":7108,"content_sha256":"096cfe4ecf3a7b4b2eccca42576e726957c94e7ffbdd8994bfcbbf4c3a03f7fa"},{"filename":"rules/powershell-expert.md","content":"# powershell-expert Rules\n\n## Purpose\n\n'Master PowerShell scripting and Windows system administration for 2026. Enforces cross-platform compatibility (PS 7+), secure credential handling, and high-fidelity automation patterns.'\n\n## Best Practices\n\n- Prefer PowerShell 7+ syntax for cross-platform (Core) compatibility\n- Enforce strict error handling via $ErrorActionPreference = 'Stop'\n- Use structured objects (PSCustomObject) rather than parsing strings\n- Secure sensitive data using SecretManagement and SecretStore modules\n- Place all enforcement rules in .claude/rules/powershell-expert.md\n\n## Integration Points\n\nSee SKILL.md for complete documentation.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":659,"content_sha256":"bb9f1e2888824261f61025b247f8ac42aa6d21c79066e3d8043d19eab8990109"},{"filename":"schemas/input.schema.json","content":"{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"title\": \"powershell-expert Input Schema\",\n \"description\": \"Input validation schema for powershell-expert skill\",\n \"type\": \"object\",\n \"required\": [],\n \"properties\": {},\n \"additionalProperties\": true\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":271,"content_sha256":"d1431c0d5b5685a66a30b117be42caf87103643676610054b07f5f3adb0794dc"},{"filename":"schemas/output.schema.json","content":"{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"title\": \"powershell-expert Output Schema\",\n \"description\": \"Output validation schema for powershell-expert skill\",\n \"type\": \"object\",\n \"required\": [\"success\"],\n \"properties\": {\n \"success\": {\n \"type\": \"boolean\",\n \"description\": \"Whether the skill executed successfully\"\n },\n \"result\": {\n \"type\": \"object\",\n \"description\": \"The skill execution result\",\n \"additionalProperties\": true\n },\n \"error\": {\n \"type\": \"string\",\n \"description\": \"Error message if execution failed\"\n }\n },\n \"additionalProperties\": true\n}\n","content_type":"application/json; charset=utf-8","language":"json","size":632,"content_sha256":"5edd3501a5abb1436b915024e7bc5cc830a18a66610fffd8adf822a3e8b842a4"},{"filename":"templates/implementation-template.md","content":"# powershell-expert Implementation Template\n\n## Goal\n\n- Define target outcome and acceptance criteria.\n\n## TDD\n\n1. Red\n2. Green\n3. Refactor\n\n## Verification\n\n- lint\n- format\n- targeted tests\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":191,"content_sha256":"5c0e88a16b04014fc0f62f3a9a0c4ce61f05dc1bce18f2bf1346d88e415f3804"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"PowerShell Expert Skill","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cidentity> Automation Architect and Windows Internals Specialist -- expert in high-scale scripting, system orchestration, and secure administrative patterns. Specialist in PowerShell 7 Core, Desired State Configuration (DSC), Just Enough Administration (JEA), and Pester testing. \u003c/identity>","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003ccapabilities>","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Design and implement robust automation scripts using PowerShell 7+","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Audit scripts for security (injection, plaintext secrets, unsafe aliases)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Optimize pipeline performance using parallelization and background jobs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Manage complex system states across Windows, Linux, and cloud environments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Design custom modules with structured help and unit tests (Pester)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Orchestrate secure deployments using JEA (Just Enough Administration) patterns","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Configure Desired State Configuration (DSC) for infrastructure as code","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Build CI/CD pipelines with PowerShell-based build and deploy scripts \u003c/capabilities>","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Overview","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill covers PowerShell 7+ (Core) for cross-platform automation, system administration, and DevOps scripting. The core philosophy is: treat PowerShell as a typed, object-oriented automation language -- not a bash replacement. Every script must handle errors explicitly, use structured objects instead of text parsing, and never expose credentials in plaintext.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"When to Use","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When writing PowerShell automation scripts for Windows or cross-platform","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When auditing existing PowerShell scripts for security and reliability","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When setting up CI/CD pipelines with PowerShell-based tooling","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When managing Windows infrastructure with DSC or JEA","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When building PowerShell modules with proper structure and testing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When migrating from Windows PowerShell 5.1 to PowerShell 7+","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Iron Laws","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ALWAYS","type":"text","marks":[{"type":"strong"}]},{"text":" set ","type":"text"},{"text":"$ErrorActionPreference = 'Stop'","type":"text","marks":[{"type":"code_inline"}]},{"text":" at the top of scripts -- silent failures are the primary cause of automation bugs and data loss.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" hardcode credentials or secrets in scripts -- use ","type":"text"},{"text":"Microsoft.PowerShell.SecretManagement","type":"text","marks":[{"type":"code_inline"}]},{"text":" module to pull secrets from vaults.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ALWAYS","type":"text","marks":[{"type":"strong"}]},{"text":" use ","type":"text"},{"text":"[PSCustomObject]","type":"text","marks":[{"type":"code_inline"}]},{"text":" or ","type":"text"},{"text":"-OutputType JSON","type":"text","marks":[{"type":"code_inline"}]},{"text":" for structured output -- text parsing with regex is fragile and breaks on locale/format changes.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"NEVER","type":"text","marks":[{"type":"strong"}]},{"text":" use ","type":"text"},{"text":"Invoke-Expression","type":"text","marks":[{"type":"code_inline"}]},{"text":" (IEX) on untrusted input -- it is the PowerShell equivalent of ","type":"text"},{"text":"eval()","type":"text","marks":[{"type":"code_inline"}]},{"text":" and enables arbitrary code execution.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"ALWAYS","type":"text","marks":[{"type":"strong"}]},{"text":" write Pester tests for production scripts -- untested automation is a liability in enterprise environments.","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Anti-Patterns","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Anti-Pattern","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Why It Fails","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Correct Approach","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Parsing command output with regex instead of using objects","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Breaks on locale changes, format updates, and different OS versions","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use cmdlet object output directly or convert to PSCustomObject","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Using ","type":"text"},{"text":"Invoke-Expression","type":"text","marks":[{"type":"code_inline"}]},{"text":" to build dynamic commands","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Enables code injection; any user input can execute arbitrary PowerShell","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use splatting (","type":"text"},{"text":"@params","type":"text","marks":[{"type":"code_inline"}]},{"text":") for dynamic parameters; use ","type":"text"},{"text":"Start-Process","type":"text","marks":[{"type":"code_inline"}]},{"text":" for external commands","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Catching all exceptions with empty catch blocks","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Silently swallows errors; automation appears to succeed when it failed","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use typed catch blocks; log and re-throw unexpected exceptions","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Using Windows PowerShell 5.1 syntax without checking compatibility","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Scripts fail on Linux/macOS where PS 7 is the only option","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"$PSVersionTable.PSVersion","type":"text","marks":[{"type":"code_inline"}]},{"text":" checks; prefer PS 7 cross-platform cmdlets","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Storing credentials in script variables or config files","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Plaintext secrets in source control; credential theft risk","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"Get-Secret","type":"text","marks":[{"type":"code_inline"}]},{"text":" from SecretManagement module; inject via environment variables in CI","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 1: Script Structure","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"#Requires -Version 7.0\n#Requires -Modules @{ ModuleName='Microsoft.PowerShell.SecretManagement'; ModuleVersion='1.1.0' }\n\n$ErrorActionPreference = 'Stop'\nSet-StrictMode -Version Latest\n\nfunction Invoke-DataBackup {\n [CmdletBinding()]\n param(\n [Parameter(Mandatory)]\n [ValidateNotNullOrEmpty()]\n [string]$TargetPath,\n\n [Parameter()]\n [switch]$Compress\n )\n\n begin {\n Write-Verbose \"Starting backup to $TargetPath\"\n }\n\n process {\n try {\n # Business logic here\n }\n catch [System.IO.IOException] {\n Write-Error \"IO error during backup: $_\"\n throw\n }\n catch {\n Write-Error \"Unexpected error: $_\"\n throw\n }\n }\n\n end {\n Write-Verbose \"Backup complete\"\n }\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 2: Secure Secret Retrieval","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"# Register a vault (one-time setup)\nRegister-SecretVault -Name 'AzureKeyVault' -ModuleName 'Az.KeyVault'\n\n# Retrieve secret at runtime\n$apiKey = Get-Secret -Name 'MyApiKey' -Vault 'AzureKeyVault' -AsPlainText\n\n# Use in automation (never log the value)\n$headers = @{ 'Authorization' = \"Bearer $apiKey\" }\nInvoke-RestMethod -Uri $endpoint -Headers $headers","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 3: Object-Oriented Pipeline","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"# Process structured data through the pipeline\nGet-ChildItem -Path $target -Filter *.json |\n ForEach-Object {\n $data = Get-Content -Path $_.FullName | ConvertFrom-Json\n [PSCustomObject]@{\n FileName = $_.Name\n ItemCount = $data.items.Count\n LastModified = $_.LastWriteTime\n }\n } |\n Sort-Object -Property ItemCount -Descending |\n Export-Csv -Path 'report.csv' -NoTypeInformation","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 4: Pester Testing","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"# Invoke-DataBackup.Tests.ps1\nDescribe 'Invoke-DataBackup' {\n BeforeAll {\n . $PSScriptRoot/Invoke-DataBackup.ps1\n }\n\n Context 'When target path exists' {\n It 'Should create backup file' {\n $result = Invoke-DataBackup -TargetPath $TestDrive\n $result | Should -Not -BeNullOrEmpty\n Test-Path \"$TestDrive/backup.zip\" | Should -BeTrue\n }\n }\n\n Context 'When target path is invalid' {\n It 'Should throw IO exception' {\n { Invoke-DataBackup -TargetPath '/nonexistent/path' } |\n Should -Throw -ExceptionType ([System.IO.IOException])\n }\n }\n}","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Step 5: Cross-Platform Compatibility","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"powershell"},"content":[{"text":"# Use Join-Path for all path operations\n$configPath = Join-Path -Path $HOME -ChildPath '.config' -AdditionalChildPath 'myapp', 'settings.json'\n\n# Check platform before using platform-specific features\nif ($IsWindows) {\n # Windows-specific: registry, WMI, COM\n $os = Get-CimInstance -ClassName Win32_OperatingSystem\n} elseif ($IsLinux -or $IsMacOS) {\n # Unix-specific: /proc, systemctl\n $os = uname -a\n}","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Complementary Skills","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Skill","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Relationship","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"devops","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"CI/CD pipeline integration with PowerShell scripts","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"docker-compose","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Containerized PowerShell automation","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"terraform-infra","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Infrastructure provisioning alongside PS configuration","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"tdd","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Test-driven development methodology for Pester tests","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Memory Protocol (MANDATORY)","type":"text"}]},{"type":"paragraph","content":[{"text":"Before starting:","type":"text","marks":[{"type":"strong"}]}]},{"type":"paragraph","content":[{"text":"Read ","type":"text"},{"text":".claude/context/memory/learnings.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for prior PowerShell modules, Pester testing patterns, or OS-specific workarounds.","type":"text"}]},{"type":"paragraph","content":[{"text":"After completing:","type":"text","marks":[{"type":"strong"}]},{"text":" Record new PowerShell modules, Pester testing patterns, or OS-specific workarounds to ","type":"text"},{"text":".claude/context/memory/learnings.md","type":"text","marks":[{"type":"code_inline"}]},{"text":".","type":"text"}]},{"type":"blockquote","content":[{"type":"paragraph","content":[{"text":"ASSUME INTERRUPTION: Your context may reset. If it's not in memory, it didn't happen.","type":"text"}]}]},{"type":"hr","attrs":{"markup":"---"}}]},"metadata":{"date":"2026-06-05","name":"powershell-expert","tags":["powershell","windows","automation","scripting","pester","dsc","system-administration"],"model":"sonnet","tools":["Read","Write","Edit","Bash","Grep","Glob","WebSearch","WebFetch"],"agents":["developer","devops"],"author":"@skillopedia","source":{"stars":29,"repo_name":"agent-studio","origin_url":"https://github.com/oimiragieo/agent-studio/blob/HEAD/.claude/skills/powershell-expert/SKILL.md","repo_owner":"oimiragieo","body_sha256":"5c32d48b982b9d71ec751e847d132bbe36817134496e7b46aa0cdf63394a9930","cluster_key":"088f56799d6897f87281f4ab81c1db6ff08a2292d8b02439600c7bc04943ac7f","clean_bundle":{"format":"clean-skill-bundle-v1","source":"oimiragieo/agent-studio/.claude/skills/powershell-expert/SKILL.md","attachments":[{"id":"c8655301-3795-506b-86cb-d128e3a72fdf","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c8655301-3795-506b-86cb-d128e3a72fdf/attachment.md","path":"commands/powershell-expert.md","size":117,"sha256":"160241609474878636c6fa47af052fe8ed40538ea1483ad8497b48def57debfb","contentType":"text/markdown; charset=utf-8"},{"id":"3c9cece8-e084-5d77-b389-6130afd01d2e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/3c9cece8-e084-5d77-b389-6130afd01d2e/attachment.cjs","path":"hooks/post-execute.cjs","size":312,"sha256":"9ae539f696e7928d405dca196faee1101706ac99e0cc94803453d6147de993e0","contentType":"text/plain; charset=utf-8"},{"id":"2c27b26b-f984-5a49-ae0a-f1624020c325","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/2c27b26b-f984-5a49-ae0a-f1624020c325/attachment.cjs","path":"hooks/pre-execute.cjs","size":429,"sha256":"ed8c38248237c6d5b8c48b3650a1a3b9083f8ee4a19db614b3375298fc249f67","contentType":"text/plain; charset=utf-8"},{"id":"e1e3bdc4-1cd3-5e8c-9cbf-52dd65baca27","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e1e3bdc4-1cd3-5e8c-9cbf-52dd65baca27/attachment","path":"references/.gitkeep","size":37,"sha256":"609eba819592e70b9d88682bd7c17dcff9fb0a2cb095a1527c8a0230275efe15","contentType":"text/plain; charset=utf-8"},{"id":"c5f5eea7-072f-5c0a-b111-c64e43bc899a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c5f5eea7-072f-5c0a-b111-c64e43bc899a/attachment.md","path":"references/best-practices.md","size":5316,"sha256":"d2367ea8eeaabb44b52a8c387e5cd45736cbd291a4c533ca8c32b1df45daaae7","contentType":"text/markdown; charset=utf-8"},{"id":"52307b05-e52d-55b8-95ea-fff4763337b3","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/52307b05-e52d-55b8-95ea-fff4763337b3/attachment.md","path":"references/devops-integration.md","size":6086,"sha256":"ce2076cee8ea71a77e92ddd97ce13fc2d7325f3f8b3eae96a7907157a056e321","contentType":"text/markdown; charset=utf-8"},{"id":"e7f12066-dad1-544a-8466-491089feb55e","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e7f12066-dad1-544a-8466-491089feb55e/attachment.md","path":"references/module-authoring.md","size":5595,"sha256":"88d7ab29bb4ed32bcd26966219e72b3f57293c48fcfd38ba6c394c2da2324ac5","contentType":"text/markdown; charset=utf-8"},{"id":"ac1851e1-f41c-586d-8cc7-71aed17d5f85","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ac1851e1-f41c-586d-8cc7-71aed17d5f85/attachment.md","path":"references/performance-patterns.md","size":6948,"sha256":"a32908beda61994519a82d958ef3cc082f501359e416f015a0b747bbc8a49eec","contentType":"text/markdown; charset=utf-8"},{"id":"6204e0bc-6fc6-56ad-bb66-e0803639623a","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6204e0bc-6fc6-56ad-bb66-e0803639623a/attachment.md","path":"references/research-requirements.md","size":472,"sha256":"42be34c52267e68605697501f51a348be243f89cca30abc89883d1af013810d7","contentType":"text/markdown; charset=utf-8"},{"id":"4782568c-a1da-5fab-875d-1e509ea952b7","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/4782568c-a1da-5fab-875d-1e509ea952b7/attachment.md","path":"references/security-patterns.md","size":5184,"sha256":"b61ca5b02cedae5e6b50f8f5bfe79f02e75318c28826f916adec50e57b905c6f","contentType":"text/markdown; charset=utf-8"},{"id":"fd222ad0-4a20-5afc-b137-9d4435398465","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/fd222ad0-4a20-5afc-b137-9d4435398465/attachment.md","path":"references/testing-patterns.md","size":7108,"sha256":"096cfe4ecf3a7b4b2eccca42576e726957c94e7ffbdd8994bfcbbf4c3a03f7fa","contentType":"text/markdown; charset=utf-8"},{"id":"6df48c5c-d399-5225-ab7c-93f90d89c649","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/6df48c5c-d399-5225-ab7c-93f90d89c649/attachment.md","path":"rules/powershell-expert.md","size":659,"sha256":"bb9f1e2888824261f61025b247f8ac42aa6d21c79066e3d8043d19eab8990109","contentType":"text/markdown; charset=utf-8"},{"id":"5dd19cf0-e1b2-537e-b9a1-765ff0b89a7f","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5dd19cf0-e1b2-537e-b9a1-765ff0b89a7f/attachment.json","path":"schemas/input.schema.json","size":271,"sha256":"d1431c0d5b5685a66a30b117be42caf87103643676610054b07f5f3adb0794dc","contentType":"application/json; charset=utf-8"},{"id":"23e76fbf-6d9b-5fba-90b3-cec80746c5c2","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/23e76fbf-6d9b-5fba-90b3-cec80746c5c2/attachment.json","path":"schemas/output.schema.json","size":632,"sha256":"5edd3501a5abb1436b915024e7bc5cc830a18a66610fffd8adf822a3e8b842a4","contentType":"application/json; charset=utf-8"},{"id":"a05f5c60-93f1-5c98-995c-f69889c31c6c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/a05f5c60-93f1-5c98-995c-f69889c31c6c/attachment.cjs","path":"scripts/main.cjs","size":577,"sha256":"3418b581f86004c60636eddcec70cc211f32c8756f5a501cf4dc2a9501f67f5a","contentType":"text/plain; charset=utf-8"},{"id":"5bdc8e22-1ca7-5670-a6ff-88b128731f33","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/5bdc8e22-1ca7-5670-a6ff-88b128731f33/attachment.md","path":"templates/implementation-template.md","size":191,"sha256":"5c0e88a16b04014fc0f62f3a9a0c4ce61f05dc1bce18f2bf1346d88e415f3804","contentType":"text/markdown; charset=utf-8"}],"bundle_sha256":"87d240c2f1f99d5fe1c7828d4cfdbe7c9c9107282b9b35ab0ad82a4a0d061ad6","attachment_count":16,"text_attachments":15,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":1,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":".claude/skills/powershell-expert/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"testing-qa","category_label":"Testing"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"testing-qa","verified":true,"streaming":"supported","import_tag":"clean-skills-v1","invoked_by":"both","description":"PowerShell 7+ scripting and Windows system administration -- cross-platform automation, secure credential handling, Pester testing, DSC, and JEA patterns.","trust_score":100,"best_practices":["Prefer PowerShell 7+ syntax for cross-platform (Core) compatibility","Enforce strict error handling via $ErrorActionPreference = 'Stop'","Use structured objects (PSCustomObject) rather than parsing strings","Secure sensitive data using SecretManagement and SecretStore modules","Test all scripts with Pester 5+ before deployment"],"error_handling":"graceful","lastVerifiedAt":"2026-03-01","provenance_sha":"e9a647ca32cddd3f","user_invocable":true}},"renderedAt":1782986539214}

PowerShell Expert Skill <identity Automation Architect and Windows Internals Specialist -- expert in high-scale scripting, system orchestration, and secure administrative patterns. Specialist in PowerShell 7 Core, Desired State Configuration (DSC), Just Enough Administration (JEA), and Pester testing. </identity <capabilities - Design and implement robust automation scripts using PowerShell 7+ - Audit scripts for security (injection, plaintext secrets, unsafe aliases) - Optimize pipeline performance using parallelization and background jobs - Manage complex system states across Windows, Linux…