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, ...
Scanned 9/2/2026
Install to Claude Code
npx -y skills add majiayu000/claude-skill-registry --skill powershell-master --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Powershell Master?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/majiayu000-powershell-master-claude-skill-registry)More formats (shields.io, HTML) on the badges page.
---
name: powershell-master
description: "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."
---
# PowerShell Master
## 🚨 CRITICAL GUIDELINES
### Windows File Path Requirements
**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:**
- ❌ WRONG: `D:/repos/project/file.tsx`
- ✅ CORRECT: `D:\repos\project\file.tsx`
This applies to:
- Edit tool file_path parameter
- Write tool file_path parameter
- All file operations on Windows systems
### Documentation Guidelines
**NEVER create new documentation files unless explicitly requested by the user.**
- **Priority**: Update existing README.md files rather than creating new documentation
- **Repository cleanliness**: Keep repository root clean - only README.md unless user requests otherwise
- **Style**: Documentation should be concise, direct, and professional - avoid AI-generated tone
- **User preference**: Only create additional .md files when user specifically asks for documentation
---
Complete PowerShell expertise across all platforms for scripting, automation, CI/CD, and cloud management.
---
## 🎯 When to Activate
PROACTIVELY activate for ANY PowerShell-related task:
- ✅ **PowerShell Scripts** - Creating, reviewing, optimizing any .ps1 file
- ✅ **Cmdlets & Modules** - Finding, installing, using any PowerShell modules
- ✅ **Cross-Platform** - Windows, Linux, macOS PowerShell tasks
- ✅ **CI/CD Integration** - GitHub Actions, Azure DevOps, Bitbucket Pipelines
- ✅ **Cloud Automation** - Azure (Az), AWS, Microsoft 365 (Microsoft.Graph)
- ✅ **Module Management** - PSGallery search, installation, updates
- ✅ **Script Debugging** - Troubleshooting, performance, security
- ✅ **Best Practices** - Code quality, standards, production-ready scripts
---
## 📋 PowerShell Overview
### PowerShell Versions & Platforms
**PowerShell 7+ (Recommended)**
- Cross-platform: Windows, Linux, macOS
- Open source, actively developed
- Better performance than PowerShell 5.1
- UTF-8 by default
- Parallel execution support
- Ternary operators, null-coalescing
**Windows PowerShell 5.1 (Legacy)**
- Windows-only
- Ships with Windows
- UTF-16LE default encoding
- Required for some Windows-specific modules
**Installation Locations:**
- **Windows:** `C:\Program Files\PowerShell\7\` (PS7) or `C:\Windows\System32\WindowsPowerShell\v1.0\` (5.1)
- **Linux:** `/opt/microsoft/powershell/7/` or `/usr/bin/pwsh`
- **macOS:** `/usr/local/microsoft/powershell/7/` or `/usr/local/bin/pwsh`
---
## 🔧 Cross-Platform Best Practices
### 1. Path Handling
**DO:**
```powershell
# 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:**
```powershell
# 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
```
### 2. Platform Detection
```powershell
# 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
}
```
### 3. Avoid Aliases in Scripts
```powershell
# 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.
### 4. Text Encoding
```powershell
# 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
```
### 5. Environment Variables (Cross-Platform)
```powershell
# 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
```
### 6. Shell Detection (Windows: PowerShell vs Git Bash)
**CRITICAL:** On Windows, distinguish between PowerShell and Git Bash/MSYS2 environments:
```powershell
# 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
# 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:**
- **PowerShell:** Windows automation, Azure/M365, PSGallery modules, object pipelines
- **Git Bash:** Git operations, Unix tools (sed/awk/grep), POSIX scripts, text processing
**Path Handling Differences:**
- **PowerShell:** `C:\Users\John` or `C:/Users/John` (both work in PS 7+)
- **Git Bash:** `/c/Users/John` (Unix-style, auto-converts to Windows when calling Windows tools)
See `powershell-shell-detection` skill for comprehensive cross-shell guidance.
### 7. Line Endings
```powershell
# 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
```
---
## 📦 Module Management (PSResourceGet & PSGallery)
### PSResourceGet - Modern Package Manager (2025)
**PSResourceGet** is 2x faster than PowerShellGet and actively maintained:
```powershell
# 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
```
### Finding Modules
```powershell
# 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
```
### Installing Modules
```powershell
# 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
```
### Managing Installed Modules
```powershell
# 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
```
### Offline Installation
```powershell
# 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
```
---
## 🌟 Popular PowerShell Modules
### Azure (Az Module 14.5.0)
**Latest:** Az 14.5.0 (October 2025) with zone redundancy and symbolic links
```powershell
# 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 sets
- `Az.Storage` - Storage accounts (zone redundancy support)
- `Az.Network` - Virtual networks, NSGs
- `Az.KeyVault` - Key Vault operations
- `Az.Resources` - Resource groups, deployments
### Microsoft Graph (Microsoft.Graph 2.32.0)
**CRITICAL:** MSOnline and AzureAD modules retired (March-May 2025). Use Microsoft.Graph instead.
```powershell
# 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
```
### PnP PowerShell (SharePoint/Teams)
```powershell
# 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"}
```
### AWS Tools for PowerShell
```powershell
# 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"
```
### Other Popular Modules
```powershell
# 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
```
---
## 🚀 CI/CD Integration
### GitHub Actions
```yaml
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:**
```yaml
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
```
### Azure DevOps Pipelines
```yaml
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:**
```yaml
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'
```
### Bitbucket Pipelines
```yaml
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
```
---
## 💻 PowerShell Syntax & Cmdlets
### Cmdlet Structure
```powershell
# 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 & Data Types
```powershell
# 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
```
### Operators
```powershell
# 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"
```
### Control Flow
```powershell
# 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)
```
### Functions
```powershell
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 & Filtering
```powershell
# 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
```
### Error Handling
```powershell
# 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
```
---
## 🔒 Security Best Practices (2025 Standards)
### Modern Security Framework (JEA + WDAC + Logging)
**2025 Security Requirements:**
1. **JEA** - Just Enough Administration for role-based access
2. **WDAC** - Windows Defender Application Control for script approval
3. **Constrained Language Mode** - For non-admin users
4. **Script Block Logging** - For audit trails
### Just Enough Administration (JEA)
**Required for production environments in 2025:**
```powershell
# 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
```
### Windows Defender Application Control (WDAC)
**Replaces AppLocker for PowerShell script control:**
```powershell
# 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
```
### Constrained Language Mode
**Recommended for all non-admin users:**
```powershell
# 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
)
```
### Script Block Logging
**Enable for security auditing:**
```powershell
# 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
```
### Execution Policy
```powershell
# 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
```
### Credential Management
```powershell
# 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
```
### Input Validation
```powershell
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
)
}
```
### Code Signing (Production)
```powershell
# Get code signing certificate
$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
# Sign script
Set-AuthenticodeSignature -FilePath script.ps1 -Certificate $cert
```
---
## ⚡ Performance Optimization
### PowerShell 7+ Features
```powershell
# 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
```
### Efficient Filtering
```powershell
# 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"}
```
### ArrayList vs Array
```powershell
# 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($_) }
```
---
## 🧪 Testing with Pester
```powershell
# 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
```
---
## 📝 Script Requirements & Versioning
```powershell
# 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
```
---
## 🎓 Common Cmdlets Reference
### File System
```powershell
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)
```
### Process Management
```powershell
Get-Process (ps, gps)
Stop-Process (kill, spps)
Start-Process (start, saps)
Wait-Process
```
### Service Management
```powershell
Get-Service (gsv)
Start-Service (sasv)
Stop-Service (spsv)
Restart-Service (srsv)
Set-Service
```
### Network
```powershell
Test-Connection (ping)
Test-NetConnection
Invoke-WebRequest (curl, wget, iwr)
Invoke-RestMethod (irm)
```
### Object Manipulation
```powershell
Select-Object (select)
Where-Object (where, ?)
ForEach-Object (foreach, %)
Sort-Object (sort)
Group-Object (group)
Measure-Object (measure)
Compare-Object (compare, diff)
```
---
## 🌐 REST API & Web Requests
```powershell
# 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"
```
---
## 🏗️ Script Structure Best Practices
```powershell
<#
.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
}
```
---
## 📚 Additional Resources
### Official Documentation
- PowerShell Docs: https://learn.microsoft.com/powershell
- PowerShell Gallery: https://www.powershellgallery.com
- Az Module Docs: https://learn.microsoft.com/powershell/azure
- Microsoft Graph Docs: https://learn.microsoft.com/graph/powershell
### Module Discovery
```powershell
# 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 System
```powershell
# Update help files (requires internet)
Update-Help -Force -ErrorAction SilentlyContinue
# Update help for specific modules
Update-Help -Module Az -Force
```
---
## 🎯 Quick Decision Guide
**Use PowerShell 7+ when:**
- Cross-platform compatibility needed
- New projects or scripts
- Performance is important
- Modern language features desired
**Use Windows PowerShell 5.1 when:**
- Windows-specific modules required (WSUS, GroupPolicy legacy)
- Corporate environments with strict version requirements
- Legacy script compatibility needed
**Choose Azure CLI when:**
- Simple one-liners needed
- JSON output preferred
- Bash scripting integration
**Choose PowerShell Az module when:**
- Complex automation required
- Object manipulation needed
- PowerShell scripting expertise available
- Reusable scripts and modules needed
---
## ✅ Pre-Flight Checklist for Scripts
Before running any PowerShell script, ensure:
1. ✅ **Platform Detection** - Use `$IsWindows`, `$IsLinux`, `$IsMacOS`
2. ✅ **Version Check** - `#Requires -Version 7.0` if needed
3. ✅ **Module Requirements** - `#Requires -Modules` specified
4. ✅ **Error Handling** - `try/catch` blocks in place
5. ✅ **Input Validation** - Parameter validation attributes used
6. ✅ **No Aliases** - Full cmdlet names in scripts
7. ✅ **Path Handling** - Use `Join-Path` or `[IO.Path]::Combine()`
8. ✅ **Encoding Specified** - UTF-8 for cross-platform
9. ✅ **Credentials Secure** - Never hardcoded
10. ✅ **Verbose Logging** - `Write-Verbose` for debugging
---
## 🚨 Common Pitfalls & Solutions
### Pitfall: Out-GridView Search Broken in 7.5
```powershell
# 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
```
### Pitfall: Case Sensitivity
```powershell
# 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"
}
```
### Pitfall: Execution Policy
```powershell
# Solution: Set for current user
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
# Or bypass for session
powershell.exe -ExecutionPolicy Bypass -File script.ps1
```
### Pitfall: Module Import Failures
```powershell
# Solution: Check module availability and install
if (-not (Get-Module -ListAvailable -Name Az)) {
Install-Module -Name Az -Force -Scope CurrentUser
}
Import-Module -Name Az
```
### Pitfall: Array Concatenation Performance
```powershell
# 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.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!