Complete PowerShell expertise system across ALL platforms (Windows/Linux/macOS). PROACTIVELY activate for: (1) ANY PowerShell task (scripts/modules/cmdlets), (2) CI/CD automation (GitHub Actions/Azure DevOps/Bitbucket), (3) Cross-platform scripting, (4) Module discovery and management (PSGallery), (5) Azure/AWS/Microsoft 365 automation, (6) Script debugging and optimization, (7) Best practices and security. Provides: PowerShell 7+ features, popular module expertise (Az, Microsoft.Graph, PnP, AWS Tools), PSGallery integration, platform-specific guidance, CI/CD pipeline patterns, cmdlet syntax mastery, and production-ready scripting patterns. Ensures professional-grade, cross-platform PowerShell automation following industry standards.
/plugin marketplace add JosiahSiegel/claude-code-marketplace/plugin install powershell-master@claude-plugin-marketplaceThis skill inherits all available tools. When active, it can use any tool Claude has access to.
MANDATORY: Always Use Backslashes on Windows for File Paths
When using Edit or Write tools on Windows, you MUST use backslashes (\) in file paths, NOT forward slashes (/).
Examples:
D:/repos/project/file.tsxD:\repos\project\file.tsxThis applies to:
NEVER create new documentation files unless explicitly requested by the user.
Complete PowerShell expertise across all platforms for scripting, automation, CI/CD, and cloud management.
PROACTIVELY activate for ANY PowerShell-related task:
PowerShell 7+ (Recommended)
Windows PowerShell 5.1 (Legacy)
Installation Locations:
C:\Program Files\PowerShell\7\ (PS7) or C:\Windows\System32\WindowsPowerShell\v1.0\ (5.1)/opt/microsoft/powershell/7/ or /usr/bin/pwsh/usr/local/microsoft/powershell/7/ or /usr/local/bin/pwshDO:
# Use Join-Path for cross-platform paths
$configPath = Join-Path -Path $PSScriptRoot -ChildPath "config.json"
# Use [System.IO.Path] for path manipulation
$fullPath = [System.IO.Path]::Combine($home, "documents", "file.txt")
# Forward slashes work on all platforms in PowerShell 7+
$path = "$PSScriptRoot/subfolder/file.txt"
DON'T:
# Hardcoded backslashes (Windows-only)
$path = "C:\Users\Name\file.txt"
# Assume case-insensitive file systems
Get-ChildItem "MyFile.txt" # Works on Windows, fails on Linux/macOS if casing is wrong
# Use automatic variables
if ($IsWindows) {
# Windows-specific code
$env:Path -split ';'
}
elseif ($IsLinux) {
# Linux-specific code
$env:PATH -split ':'
}
elseif ($IsMacOS) {
# macOS-specific code
$env:PATH -split ':'
}
# Check PowerShell version
if ($PSVersionTable.PSVersion.Major -ge 7) {
# PowerShell 7+ features
}
# DON'T use aliases (they may differ across platforms)
ls | ? {$_.Length -gt 1MB} | % {$_.Name}
# DO use full cmdlet names
Get-ChildItem | Where-Object {$_.Length -gt 1MB} | ForEach-Object {$_.Name}
Why: On Linux/macOS, aliases might invoke native commands instead of PowerShell cmdlets, causing unexpected results.
# PowerShell 7+ uses UTF-8 by default
"Hello" | Out-File -FilePath output.txt
# For PowerShell 5.1 compatibility, specify encoding
"Hello" | Out-File -FilePath output.txt -Encoding UTF8
# Best practice: Always specify encoding for cross-platform scripts
$content | Set-Content -Path $file -Encoding UTF8NoBOM
# BEST PRACTICE: Use .NET Environment class for cross-platform compatibility
[Environment]::UserName # Works on all platforms
[Environment]::MachineName # Works on all platforms
[IO.Path]::GetTempPath() # Works on all platforms
# AVOID: These are platform-specific
$env:USERNAME # Windows only
$env:USER # Linux/macOS only
# Environment variable names are CASE-SENSITIVE on Linux/macOS
$env:PATH # Correct on Linux/macOS
$env:Path # May not work on Linux/macOS
CRITICAL: On Windows, distinguish between PowerShell and Git Bash/MSYS2 environments:
# PowerShell detection (most reliable)
if ($env:PSModulePath -and ($env:PSModulePath -split ';').Count -ge 3) {
Write-Host "Running in PowerShell"
}
# Platform-specific automatic variables (PowerShell 7+)
if ($IsWindows) {
# Windows-specific code
}
elseif ($IsLinux) {
# Linux-specific code
}
elseif ($IsMacOS) {
# macOS-specific code
}
Git Bash/MSYS2 Detection:
# Bash detection - check MSYSTEM environment variable
if [ -n "$MSYSTEM" ]; then
echo "Running in Git Bash/MSYS2: $MSYSTEM"
# MSYSTEM values: MINGW64, MINGW32, MSYS
fi
When to Use Each Shell:
Path Handling Differences:
C:\Users\John or C:/Users/John (both work in PS 7+)/c/Users/John (Unix-style, auto-converts to Windows when calling Windows tools)See powershell-shell-detection skill for comprehensive cross-shell guidance.
# PowerShell handles line endings automatically
# But be explicit for git or cross-platform tools
git config core.autocrlf input # Linux/macOS
git config core.autocrlf true # Windows
PSResourceGet is 2x faster than PowerShellGet and actively maintained:
# PSResourceGet ships with PowerShell 7.4+ (or install manually)
Install-Module -Name Microsoft.PowerShell.PSResourceGet -Force
# Modern commands (PSResourceGet)
Install-PSResource -Name Az -Scope CurrentUser # 2x faster
Find-PSResource -Name "*Azure*" # Faster search
Update-PSResource -Name Az # Batch updates
Get-InstalledPSResource # List installed
Uninstall-PSResource -Name OldModule # Clean uninstall
# Compatibility: Your old Install-Module commands still work
# They automatically call PSResourceGet internally
Install-Module -Name Az -Scope CurrentUser # Works, uses PSResourceGet
# PSResourceGet (Modern)
Find-PSResource -Name "*Azure*"
Find-PSResource -Tag "Security"
Find-PSResource -Name Az | Select-Object Name, Version, PublishedDate
# Legacy PowerShellGet (still works)
Find-Module -Name "*Azure*"
Find-Command -Name Get-AzVM
# RECOMMENDED: PSResourceGet (2x faster)
Install-PSResource -Name Az -Scope CurrentUser -TrustRepository
Install-PSResource -Name Microsoft.Graph -Version 2.32.0
# Legacy: PowerShellGet (slower, but still works)
Install-Module -Name Az -Scope CurrentUser -Force
Install-Module -Name Pester -Scope AllUsers # Requires elevation
# List installed (PSResourceGet)
Get-InstalledPSResource
Get-InstalledPSResource -Name Az
# Update modules (PSResourceGet)
Update-PSResource -Name Az
Update-PSResource # Updates all
# Uninstall (PSResourceGet)
Uninstall-PSResource -Name OldModule -AllVersions
# Import module
Import-Module -Name Az.Accounts
# Save module (works with both)
Save-PSResource -Name Az -Path C:\OfflineModules
# Or: Save-Module -Name Az -Path C:\OfflineModules
# Install from saved location
Install-PSResource -Name Az -Path C:\OfflineModules
Latest: Az 14.5.0 (October 2025) with zone redundancy and symbolic links
# Install Azure module 14.5.0
Install-PSResource -Name Az -Scope CurrentUser
# Or: Install-Module -Name Az -Scope CurrentUser -Force
# Connect to Azure
Connect-AzAccount
# Common operations
Get-AzVM
Get-AzResourceGroup
New-AzResourceGroup -Name "MyRG" -Location "EastUS"
# NEW in Az 14.5: Zone redundancy for storage
New-AzStorageAccount -ResourceGroupName "MyRG" -Name "storage123" `
-Location "EastUS" -SkuName "Standard_LRS" -EnableZoneRedundancy
# NEW in Az 14.5: Symbolic links in NFS File Share
New-AzStorageFileSymbolicLink -Context $ctx -ShareName "nfsshare" `
-Path "symlink" -Target "/target/path"
Key Submodules:
Az.Accounts - Authentication (MFA required Sep 2025+)Az.Compute - VMs, scale setsAz.Storage - Storage accounts (zone redundancy support)Az.Network - Virtual networks, NSGsAz.KeyVault - Key Vault operationsAz.Resources - Resource groups, deploymentsCRITICAL: MSOnline and AzureAD modules retired (March-May 2025). Use Microsoft.Graph instead.
# Install Microsoft Graph 2.32.0 (October 2025)
Install-PSResource -Name Microsoft.Graph -Scope CurrentUser
# Or: Install-Module -Name Microsoft.Graph -Scope CurrentUser
# Connect with required scopes
Connect-MgGraph -Scopes "User.Read.All", "Group.ReadWrite.All"
# Common operations
Get-MgUser
Get-MgGroup
New-MgUser -DisplayName "John Doe" -UserPrincipalName "john@domain.com" -MailNickname "john"
Get-MgTeam
# Migration from AzureAD/MSOnline
# OLD: Connect-AzureAD / Connect-MsolService
# NEW: Connect-MgGraph
# OLD: Get-AzureADUser / Get-MsolUser
# NEW: Get-MgUser
# Install PnP PowerShell
Install-Module -Name PnP.PowerShell -Scope CurrentUser
# Connect to SharePoint Online
Connect-PnPOnline -Url "https://tenant.sharepoint.com/sites/site" -Interactive
# Common operations
Get-PnPList
Get-PnPFile -Url "/sites/site/Shared Documents/file.docx"
Add-PnPListItem -List "Tasks" -Values @{"Title"="New Task"}
# Install AWS Tools
Install-Module -Name AWS.Tools.Installer -Force
Install-AWSToolsModule AWS.Tools.EC2,AWS.Tools.S3
# Configure credentials
Set-AWSCredential -AccessKey $accessKey -SecretKey $secretKey -StoreAs default
# Common operations
Get-EC2Instance
Get-S3Bucket
New-S3Bucket -BucketName "my-bucket"
# Pester (Testing framework)
Install-Module -Name Pester -Force
# PSScriptAnalyzer (Code analysis)
Install-Module -Name PSScriptAnalyzer
# ImportExcel (Excel manipulation without Excel)
Install-Module -Name ImportExcel
# PowerShellGet 3.x (Modern package management)
Install-Module -Name Microsoft.PowerShell.PSResourceGet
name: PowerShell CI
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install PowerShell modules
shell: pwsh
run: |
Install-Module -Name Pester -Force -Scope CurrentUser
Install-Module -Name PSScriptAnalyzer -Force -Scope CurrentUser
- name: Run Pester tests
shell: pwsh
run: |
Invoke-Pester -Path ./tests -OutputFormat NUnitXml -OutputFile TestResults.xml
- name: Run PSScriptAnalyzer
shell: pwsh
run: |
Invoke-ScriptAnalyzer -Path . -Recurse -ReportSummary
Multi-Platform Matrix:
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Test on ${{ matrix.os }}
shell: pwsh
run: |
./test-script.ps1
trigger:
- main
pool:
vmImage: 'ubuntu-latest'
steps:
- task: PowerShell@2
inputs:
targetType: 'inline'
script: |
Install-Module -Name Pester -Force -Scope CurrentUser
Invoke-Pester -Path ./tests -OutputFormat NUnitXml
displayName: 'Run Pester Tests'
- task: PowerShell@2
inputs:
filePath: '$(System.DefaultWorkingDirectory)/build.ps1'
arguments: '-Configuration Release'
displayName: 'Run Build Script'
- task: PublishTestResults@2
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResults.xml'
Cross-Platform Pipeline:
strategy:
matrix:
linux:
imageName: 'ubuntu-latest'
windows:
imageName: 'windows-latest'
mac:
imageName: 'macos-latest'
pool:
vmImage: $(imageName)
steps:
- pwsh: |
Write-Host "Running on $($PSVersionTable.OS)"
./test-script.ps1
displayName: 'Cross-platform test'
image: mcr.microsoft.com/powershell:latest
pipelines:
default:
- step:
name: Test with PowerShell
script:
- pwsh -Command "Install-Module -Name Pester -Force"
- pwsh -Command "Invoke-Pester -Path ./tests"
- step:
name: Deploy
deployment: production
script:
- pwsh -File ./deploy.ps1
# Verb-Noun pattern
Get-ChildItem
Set-Location
New-Item
Remove-Item
# Common parameters (available on all cmdlets)
Get-Process -Verbose
Set-Content -Path file.txt -WhatIf
Remove-Item -Path folder -Confirm
Invoke-RestMethod -Uri $url -ErrorAction Stop
# Variables (loosely typed)
$string = "Hello World"
$number = 42
$array = @(1, 2, 3, 4, 5)
$hashtable = @{Name="John"; Age=30}
# Strongly typed
[string]$name = "John"
[int]$age = 30
[datetime]$date = Get-Date
# Special variables
$PSScriptRoot # Directory containing the script
$PSCommandPath # Full path to the script
$args # Script arguments
$_ # Current pipeline object
# Comparison operators
-eq # Equal
-ne # Not equal
-gt # Greater than
-lt # Less than
-match # Regex match
-like # Wildcard match
-contains # Array contains
# Logical operators
-and
-or
-not
# PowerShell 7+ ternary operator
$result = $condition ? "true" : "false"
# Null-coalescing (PS 7+)
$value = $null ?? "default"
# If-ElseIf-Else
if ($condition) {
# Code
} elseif ($otherCondition) {
# Code
} else {
# Code
}
# Switch
switch ($value) {
1 { "One" }
2 { "Two" }
{$_ -gt 10} { "Greater than 10" }
default { "Other" }
}
# Loops
foreach ($item in $collection) {
# Process item
}
for ($i = 0; $i -lt 10; $i++) {
# Loop code
}
while ($condition) {
# Loop code
}
do {
# Loop code
} while ($condition)
function Get-Something {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Name,
[Parameter()]
[int]$Count = 1,
[Parameter(ValueFromPipeline=$true)]
[string[]]$InputObject
)
begin {
# Initialization
}
process {
# Process each pipeline object
foreach ($item in $InputObject) {
# Work with $item
}
}
end {
# Cleanup
return $result
}
}
# Pipeline basics
Get-Process | Where-Object {$_.CPU -gt 100} | Select-Object Name, CPU
# Simplified syntax (PS 3.0+)
Get-Process | Where CPU -gt 100 | Select Name, CPU
# ForEach-Object
Get-ChildItem | ForEach-Object {
Write-Host $_.Name
}
# Simplified (PS 4.0+)
Get-ChildItem | % Name
# Group, Sort, Measure
Get-Process | Group-Object ProcessName
Get-Service | Sort-Object Status
Get-ChildItem | Measure-Object -Property Length -Sum
# Try-Catch-Finally
try {
Get-Content -Path "nonexistent.txt" -ErrorAction Stop
}
catch [System.IO.FileNotFoundException] {
Write-Error "File not found"
}
catch {
Write-Error "An error occurred: $_"
}
finally {
# Cleanup code
}
# Error action preference
$ErrorActionPreference = "Stop" # Treat all errors as terminating
$ErrorActionPreference = "Continue" # Default
$ErrorActionPreference = "SilentlyContinue" # Suppress errors
2025 Security Requirements:
Required for production environments in 2025:
# Create JEA session configuration file
New-PSSessionConfigurationFile -SessionType RestrictedRemoteServer `
-Path "C:\JEA\HelpDesk.pssc" `
-VisibleCmdlets @{
Name = 'Restart-Service'
Parameters = @{ Name = 'Name'; ValidateSet = 'Spooler', 'Wuauserv' }
}, @{
Name = 'Get-Service'
} `
-LanguageMode NoLanguage `
-ExecutionPolicy RemoteSigned
# Register JEA endpoint
Register-PSSessionConfiguration -Name HelpDesk `
-Path "C:\JEA\HelpDesk.pssc" `
-Force
# Connect with limited privileges
Enter-PSSession -ComputerName Server01 -ConfigurationName HelpDesk
Replaces AppLocker for PowerShell script control:
# Create WDAC policy for approved scripts
New-CIPolicy -FilePath "C:\WDAC\PowerShellPolicy.xml" `
-ScanPath "C:\ApprovedScripts" `
-Level FilePublisher `
-Fallback Hash
# Convert to binary
ConvertFrom-CIPolicy -XmlFilePath "C:\WDAC\PowerShellPolicy.xml" `
-BinaryFilePath "C:\Windows\System32\CodeIntegrity\SIPolicy.p7b"
# Deploy via Group Policy or MDM
Recommended for all non-admin users:
# Check current language mode
$ExecutionContext.SessionState.LanguageMode
# Output: FullLanguage (admin) or ConstrainedLanguage (standard user)
# Enable system-wide via environment variable
[Environment]::SetEnvironmentVariable(
"__PSLockdownPolicy",
"4",
[System.EnvironmentVariableTarget]::Machine
)
Enable for security auditing:
# Enable via Group Policy or Registry
# HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging
# EnableScriptBlockLogging = 1
# EnableScriptBlockInvocationLogging = 1
# Check logs
Get-WinEvent -LogName "Microsoft-Windows-PowerShell/Operational" |
Where-Object Id -eq 4104 | # Script Block Logging
Select-Object TimeCreated, Message -First 10
# Check current execution policy
Get-ExecutionPolicy
# Set for current user (no admin needed)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Bypass for single session (use sparingly)
pwsh -ExecutionPolicy Bypass -File script.ps1
# NEVER hardcode credentials
# BAD: $password = "MyP@ssw0rd"
# Use SecretManagement module (modern approach)
Install-PSResource -Name Microsoft.PowerShell.SecretManagement
Install-PSResource -Name SecretManagement.KeyVault
Register-SecretVault -Name AzureKeyVault -ModuleName SecretManagement.KeyVault
$secret = Get-Secret -Name "DatabasePassword" -Vault AzureKeyVault
# Legacy: Get-Credential for interactive
$cred = Get-Credential
# Azure Key Vault for production
$vaultName = "MyKeyVault"
$secret = Get-AzKeyVaultSecret -VaultName $vaultName -Name "DatabasePassword"
$secret.SecretValue
function Do-Something {
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[ValidateNotNullOrEmpty()]
[string]$Name,
[Parameter()]
[ValidateRange(1, 100)]
[int]$Count,
[Parameter()]
[ValidateSet("Option1", "Option2", "Option3")]
[string]$Option,
[Parameter()]
[ValidatePattern('^\d{3}-\d{3}-\d{4}$')]
[string]$PhoneNumber
)
}
# Get code signing certificate
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
# Sign script
Set-AuthenticodeSignature -FilePath script.ps1 -Certificate $cert
# Parallel ForEach (PS 7+)
1..10 | ForEach-Object -Parallel {
Start-Sleep -Seconds 1
"Processed $_"
} -ThrottleLimit 5
# Ternary operator
$result = $value ? "true" : "false"
# Null-coalescing
$name = $userName ?? "default"
# Null-conditional member access
$length = $string?.Length
# Use .NET methods for performance
# Instead of: Get-Content large.txt | Where-Object {$_ -match "pattern"}
[System.IO.File]::ReadLines("large.txt") | Where-Object {$_ -match "pattern"}
# Use -Filter parameter when available
Get-ChildItem -Path C:\ -Filter *.log -Recurse
# Instead of: Get-ChildItem -Path C:\ -Recurse | Where-Object {$_.Extension -eq ".log"}
# Arrays are immutable - slow for additions
$array = @()
1..1000 | ForEach-Object { $array += $_ } # SLOW
# Use ArrayList for dynamic collections
$list = [System.Collections.ArrayList]::new()
1..1000 | ForEach-Object { [void]$list.Add($_) } # FAST
# Or use generic List
$list = [System.Collections.Generic.List[int]]::new()
1..1000 | ForEach-Object { $list.Add($_) }
# Install Pester
Install-Module -Name Pester -Force
# Basic test structure
Describe "Get-Something Tests" {
Context "When input is valid" {
It "Should return expected value" {
$result = Get-Something -Name "Test"
$result | Should -Be "Expected"
}
}
Context "When input is invalid" {
It "Should throw an error" {
{ Get-Something -Name $null } | Should -Throw
}
}
}
# Run tests
Invoke-Pester -Path ./tests
Invoke-Pester -Path ./tests -OutputFormat NUnitXml -OutputFile TestResults.xml
# Code coverage
Invoke-Pester -Path ./tests -CodeCoverage ./src/*.ps1
# Require specific PowerShell version
#Requires -Version 7.0
# Require modules
#Requires -Modules Az.Accounts, Az.Compute
# Require admin/elevated privileges (Windows)
#Requires -RunAsAdministrator
# Combine multiple requirements
#Requires -Version 7.0
#Requires -Modules @{ModuleName='Pester'; ModuleVersion='5.0.0'}
# Use strict mode
Set-StrictMode -Version Latest
Get-ChildItem (gci, ls, dir)
Set-Location (cd, sl)
New-Item (ni)
Remove-Item (rm, del)
Copy-Item (cp, copy)
Move-Item (mv, move)
Rename-Item (rn, ren)
Get-Content (gc, cat, type)
Set-Content (sc)
Add-Content (ac)
Get-Process (ps, gps)
Stop-Process (kill, spps)
Start-Process (start, saps)
Wait-Process
Get-Service (gsv)
Start-Service (sasv)
Stop-Service (spsv)
Restart-Service (srsv)
Set-Service
Test-Connection (ping)
Test-NetConnection
Invoke-WebRequest (curl, wget, iwr)
Invoke-RestMethod (irm)
Select-Object (select)
Where-Object (where, ?)
ForEach-Object (foreach, %)
Sort-Object (sort)
Group-Object (group)
Measure-Object (measure)
Compare-Object (compare, diff)
# GET request
$response = Invoke-RestMethod -Uri "https://api.example.com/data" -Method Get
# POST with JSON body
$body = @{
name = "John"
age = 30
} | ConvertTo-Json
$response = Invoke-RestMethod -Uri "https://api.example.com/users" `
-Method Post -Body $body -ContentType "application/json"
# With headers and authentication
$headers = @{
"Authorization" = "Bearer $token"
"Accept" = "application/json"
}
$response = Invoke-RestMethod -Uri $url -Headers $headers
# Download file
Invoke-WebRequest -Uri $url -OutFile "file.zip"
<#
.SYNOPSIS
Brief description
.DESCRIPTION
Detailed description
.PARAMETER Name
Parameter description
.EXAMPLE
PS> .\script.ps1 -Name "John"
Example usage
.NOTES
Author: Your Name
Version: 1.0.0
Date: 2025-01-01
#>
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[string]$Name
)
# Script-level error handling
$ErrorActionPreference = "Stop"
# Use strict mode
Set-StrictMode -Version Latest
try {
# Main script logic
Write-Verbose "Starting script"
# ... script code ...
Write-Verbose "Script completed successfully"
}
catch {
Write-Error "Script failed: $_"
exit 1
}
finally {
# Cleanup
}
# Find modules by keyword
Find-Module -Tag "Azure"
Find-Module -Tag "Security"
# Explore commands in a module
Get-Command -Module Az.Compute
Get-Command -Verb Get -Noun *VM*
# Get command help
Get-Help Get-AzVM -Full
Get-Help Get-AzVM -Examples
Get-Help Get-AzVM -Online
# Update help files (requires internet)
Update-Help -Force -ErrorAction SilentlyContinue
# Update help for specific modules
Update-Help -Module Az -Force
Use PowerShell 7+ when:
Use Windows PowerShell 5.1 when:
Choose Azure CLI when:
Choose PowerShell Az module when:
Before running any PowerShell script, ensure:
$IsWindows, $IsLinux, $IsMacOS#Requires -Version 7.0 if needed#Requires -Modules specifiedtry/catch blocks in placeJoin-Path or [IO.Path]::Combine()Write-Verbose for debugging# Known Issue: Out-GridView search doesn't work in PowerShell 7.5 due to .NET 9 changes
# Workaround: Use Where-Object or Select-Object for filtering
Get-Process | Where-Object CPU -gt 100 | Format-Table
# Or export to CSV and use external tools
Get-Process | Export-Csv processes.csv -NoTypeInformation
# Linux/macOS are case-sensitive
# This fails on Linux if file is "File.txt"
Get-Content "file.txt"
# Solution: Use exact casing or Test-Path first
if (Test-Path "file.txt") {
Get-Content "file.txt"
}
# Solution: Set for current user
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Or bypass for session
powershell.exe -ExecutionPolicy Bypass -File script.ps1
# Solution: Check module availability and install
if (-not (Get-Module -ListAvailable -Name Az)) {
Install-Module -Name Az -Force -Scope CurrentUser
}
Import-Module -Name Az
# Bad: $array += $item (recreates array each time)
# Good: Use ArrayList or List
$list = [System.Collections.Generic.List[object]]::new()
$list.Add($item)
Remember: ALWAYS research latest PowerShell documentation and module versions before implementing solutions. The PowerShell ecosystem evolves rapidly, and best practices are updated frequently.
This skill should be used when the user asks to "create an agent", "add an agent", "write a subagent", "agent frontmatter", "when to use description", "agent examples", "agent tools", "agent colors", "autonomous agent", or needs guidance on agent structure, system prompts, triggering conditions, or agent development best practices for Claude Code plugins.
This skill should be used when the user asks to "create a slash command", "add a command", "write a custom command", "define command arguments", "use command frontmatter", "organize commands", "create command with file references", "interactive command", "use AskUserQuestion in command", or needs guidance on slash command structure, YAML frontmatter fields, dynamic arguments, bash execution in commands, user interaction patterns, or command development best practices for Claude Code.
This skill should be used when the user asks to "create a hook", "add a PreToolUse/PostToolUse/Stop hook", "validate tool use", "implement prompt-based hooks", "use ${CLAUDE_PLUGIN_ROOT}", "set up event-driven automation", "block dangerous commands", or mentions hook events (PreToolUse, PostToolUse, Stop, SubagentStop, SessionStart, SessionEnd, UserPromptSubmit, PreCompact, Notification). Provides comprehensive guidance for creating and implementing Claude Code plugin hooks with focus on advanced prompt-based hooks API.