| 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) orC:\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:
# 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
2. Platform Detection
# 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
# 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 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)
# 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 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:
- 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\JohnorC:/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 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:
# 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
# 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
# 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
# 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
# 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
# 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, deployments
Microsoft Graph (Microsoft.Graph 2.32.0)
CRITICAL: 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
PnP PowerShell (SharePoint/Teams)
# 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
# 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
# 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
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
Azure DevOps Pipelines
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'
Bitbucket Pipelines
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
# 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
# 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
# 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
# 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
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
# 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
# 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:
- JEA - Just Enough Administration for role-based access
- WDAC - Windows Defender Application Control for script approval
- Constrained Language Mode - For non-admin users
- Script Block Logging - For audit trails
Just Enough Administration (JEA)
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
Windows Defender Application Control (WDAC)
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
Constrained Language Mode
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
)
Script Block Logging
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
Execution Policy
# 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
# 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
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)
# 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
# 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
# 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
# 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
# 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
# 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
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
Get-Process (ps, gps)
Stop-Process (kill, spps)
Start-Process (start, saps)
Wait-Process
Service Management
Get-Service (gsv)
Start-Service (sasv)
Stop-Service (spsv)
Restart-Service (srsv)
Set-Service
Network
Test-Connection (ping)
Test-NetConnection
Invoke-WebRequest (curl, wget, iwr)
Invoke-RestMethod (irm)
Object Manipulation
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
# 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
<#
.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
# 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
# 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:
- โ
Platform Detection - Use
$IsWindows,$IsLinux,$IsMacOS - โ
Version Check -
#Requires -Version 7.0if needed - โ
Module Requirements -
#Requires -Modulesspecified - โ
Error Handling -
try/catchblocks in place - โ Input Validation - Parameter validation attributes used
- โ No Aliases - Full cmdlet names in scripts
- โ
Path Handling - Use
Join-Pathor[IO.Path]::Combine() - โ Encoding Specified - UTF-8 for cross-platform
- โ Credentials Secure - Never hardcoded
- โ
Verbose Logging -
Write-Verbosefor debugging
๐จ Common Pitfalls & Solutions
Pitfall: Out-GridView Search Broken in 7.5
# 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
# 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
# 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
# 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
# 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.