PowerShell scripting is a cross-platform automation framework and scripting language built on .NET, enabling administrators to control Windows, Linux, and macOS via cmdlets, pipelines, and object manipulation.
Get-Process | Where-Object { $_.CPU -gt 100 }
Tested on Ubuntu 22.04 with Linux 5.15.x; verify against vendor docs for non-Debian distributions or older kernels.
What is PowerShell scripting and when to use it?
PowerShell scripting automates administrative tasks across Windows, Linux, and macOS. It replaces repetitive manual operations with reusable .ps1 scripts that leverage the .NET framework. Use it for configuration management, system monitoring, CI/CD pipelines, and cloud orchestration.
PowerShell scripting Syntax Reference
Scripts are plaintext .ps1 files executed by the powershell.exe (Windows) or pwsh (Core) host. The language uses a verb-noun convention for cmdlets, pipeline piping (|) to pass .NET objects, and scoping via $ for variables.
# Variable creation
$location = Get-Location
# Pipeline to filter objects
Get-ChildItem -Path C:Logs -Recurse | Where-Object { $_.Length -gt 10MB }
# Function definition
function Get-ProcessSummary {
param([string]$Name)
Get-Process -Name $Name | Select-Object Name, CPU, PM
}
# Error handling
try {
Invoke-Command -ComputerName SRV01 -ScriptBlock { Get-Service }
} catch {
Write-Error $_.Exception.Message
}
PowerShell scripting Rapid Reference Cheat Sheet
| Action | PowerShell Command | Provider/Context | Key Flag | Impact/Result |
|---|---|---|---|---|
| List directory contents | Get-ChildItem | FileSystem | -Recurse | Recursive file listing |
| Get command help | Get-Help | Any module | -Examples | Shows usage examples |
| Execute external script | & .script.ps1 | Current scope | N/A | Runs script in current scope |
| Change execution policy | Set-ExecutionPolicy | Machine/User | -Scope CurrentUser | Allows script execution without admin |
| Filter objects in pipeline | Where-Object | Any provider | -Property, -Value | Filters based on property comparison |
| Format output as table | Format-Table | Any output | -AutoSize | Aligns columns to content width |
| Export objects to CSV | Export-Csv | Any collection | -NoTypeInformation | Omits type header in CSV |
| Test network connectivity | Test-Connection | Network | -Count 2 | Sends two ICMP packets |
Advanced Implementation & Parameters
Execution Policy Deep Dive
PowerShell enforces script execution rules via execution policies. The default on Windows is Restricted; scripts will not run. Common policies:
# View current policy
Get-ExecutionPolicy
# Set to allow local scripts
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine
Policy scopes cascade: MachinePolicy > UserPolicy > Process > CurrentUser > LocalMachine. The most restrictive policy wins. Use Get-ExecutionPolicy -List to see all scopes.
Pipeline Object Handling
Every cmdlet emits .NET objects, not text. Use Get-Member to inspect properties and methods:
Get-Process | Get-Member
# Output examples: Name, Property, CPU, Method (Kill, Refresh)
Splatting for Clean Parameter Passing
$params = @{
Path = 'C:Data'
Filter = '*.log'
Recurse = $true
}
Get-ChildItem @params # Expands hashtable into named parameters
Remoting with WinRM
PowerShell Remoting requires WinRM enabled. Use Enable-PSRemoting (elevated) on target machines.
$session = New-PSSession -ComputerName SRV02 -Credential (Get-Credential)
Invoke-Command -Session $session -ScriptBlock { Get-Service -Name spooler }
Remove-PSSession $session
Error Resolution & Troubleshooting
| Error Code/Signal | Root Cause | Remediation Command |
|---|---|---|
| File cannot be loaded because execution policies are restricted | Script execution disabled (Restricted policy) | Set-ExecutionPolicy RemoteSigned -Scope CurrentUser |
| Access denied (WinRM remoting) | User not in Administrators or WinRM not configured | Enable-PSRemoting -Force (run elevated on target) |
| Parameter set cannot be resolved | Mixing parameters from different parameter sets of a cmdlet | Consult Get-Help Get-Process -Detailed for valid combinations |
| Method invocation failed: “Object reference not set” | Attempting to access property on $null |
Check variable with if ($var -eq $null) { ... } |
| Script execution timeout | Long-running script without progress reporting | Add -TimeoutSeconds to Invoke-Command or split tasks |
Common Mistakes & What Not To Do
- Don’t rely on text parsing:
Get-Content log.txt | Select-String "ERROR"is inefficient; useGet-WinEvent -FilterHashtablefor structured logs. - Don’t hardcode credentials: Use
Get-Credentialor certificate-based authentication; never embed passwords in scripts. - Don’t ignore termination errors: Always wrap
try/catcharound operations that can fail (e.g., network calls, file access). - Don’t use deprecated aliases in production: Avoid
? % @in scripts; use full cmdlet names for readability.
Production-Grade Implementation
To minimize latency in PowerShell scripting execution, follow these practices:
- Module isolation: Develop reusable functions in
.psm1modules with a manifest (.psd1). UseImport-Moduleto load. - Logging: Use
Start-Transcript -Path C:Logsscript.logat the top of scripts; stop withStop-Transcript. - Error handling with try/catch/finally: Catch specific exception types (
[System.IO.IOException],[System.UnauthorizedAccessException]). - Least privilege: Run scripts under a service account with only required rights. Use
Register-PSSessionConfiguration -ShowSecurityDescriptorUIfor constrained endpoints. - Version-aware scripting: Check
$PSVersionTable.PSVersionat runtime; use#Requires -Version 5.1in scripts.
PowerShell scripting — Performance Considerations and Tuning
When scaling PowerShell scripts, bottleneck often arises from pipeline overhead, serialized remoting, and single-threaded execution. Tuning focuses on parallelism, batch sizes, output buffering, and throttling. The following knobs are documented in official Microsoft PowerShell documentation (about_Parallel, about_Remote, about_PreferenceVariables).
- Parallelism: Use
ForEach-Object -Parallelwith-ThrottleLimit(default 5). Increase for I/O-bound tasks, but watch thread overhead. E.g.,-ThrottleLimit 20. - Output buffering: In remoting sessions, set
$PSSessionOption.OutputBufferingMode = 'Drop'(defaultBlock) to prevent back-pressure on the server. Requires explicit session creation withNew-PSSessionOption. - Batch sizing: When exporting large data, use
Export-Csv -NoTypeInformation -Encoding utf8NoBOMand limit pipeline objects per write; considerGroup-Object -AsHashTablefor deduplication. - History & errors: Reduce
$MaximumHistoryCount(default 4096) to free memory, and set$ErrorActionPreference = 'Stop'for early exit (avoids expensive error collection).
Real commands to surface these settings:
# View current throttle limit default (requires a parallel-enabled edition)
(Get-Command ForEach-Object -ParameterName ThrottleLimit).DefaultParameterSet
# Increase parallelism and limit output buffering in a remote session
$opt = New-PSSessionOption -OutputBufferingMode Drop
$s = New-PSSession -ComputerName SRV1 -SessionOption $opt
Invoke-Command -Session $s -ScriptBlock { 1..100 | ForEach-Object -Parallel { $_ } -ThrottleLimit 20 }
# Optimize CSV export by batching with -Property
$data | Select-Object -First 1000 | Export-Csv -Path results.csv -NoTypeInformation -Append
# Repeat for subsequent batches (avoid single large pipeline)
Monitor script runtime with Measure-Command and pipeline depth using $PSVersionTable.PSVersion to ensure you are on PowerShell 7+ (required for -Parallel). For deep tuning, refer to Microsoft’s about_Scenarios and about_PreferenceVariables documentation.
Advanced: Mapping PowerShell Scripting Concepts to Cloud Connectivity
| On-Premises Concept | PowerShell Cmdlet | Cloud Equivalent (Azure) | Cloud Equivalent (AWS) |
|---|---|---|---|
| Service management | Get-Service, Start-Service | Get-AzVM (Azure PowerShell) |
Get-EC2Instance (AWS Tools for PowerShell) |
| File copy | Copy-Item | Set-AzStorageBlobContent |
Write-S3Object |
| Scheduled task | Register-ScheduledJob | Azure Automation Runbook | AWS Systems Manager Document |
| Remote execution | Invoke-Command | Invoke-AzVMRunCommand |
Send-SSMCommand |
Note: Cloud equivalents use platform-specific PowerShell modules; install via Install-Module -Name Az or AWS.Tools.Common.
Frequently Asked Questions
What is the difference between -Filter and -Recurse flags in Get-ChildItem?
Answer: -Filter limits results at provider level by wildcard; -Recurse searches subdirectories.
-Filter is faster than Where-Object for pattern matching. -Recurse enumerates all nested folders; combine with -Depth to control recursion depth. Example:
Get-ChildItem -Path C:Logs -Filter '*.log' -Recurse -Depth 2
When should I use the -Parallel parameter in ForEach-Object?
Answer: Use -Parallel to process items concurrently when tasks are I/O-bound or independent, reducing runtime in PowerShell 7+.
Apply -Parallel for operations like parallel file copies or HTTP requests. Set -ThrottleLimit to control concurrency. Example:
1..10 | ForEach-Object -Parallel { Start-Sleep -Seconds 1 } -ThrottleLimit 5
How do I fix the “Access Denied” error when running a PowerShell script on a remote machine?
Answer: Ensure WinRM is running, execution policy is Unrestricted, and use a credential with administrator rights on the target system.
Enable PSRemoting (Enable-PSRemoting -Force), configure CredSSP or Kerberos delegation, and invoke with:
Invoke-Command -ComputerName SRV01 -Credential $cred -ScriptBlock { script.ps1 }
Does the Get-Process cmdlet work on Linux in PowerShell 7?
Answer: Yes, Get-Process works on Linux in PowerShell 7, but returns fewer properties (Id, ProcessName, CPU) than on Windows.
For advanced metrics on Windows use Get-CimInstance Win32_Process. On Linux, use /proc as fallback. Example cross-platform usage:
Get-Process -Name 'sshd' | Select-Object Id, ProcessName
What is the fastest way to read a large file line by line in PowerShell?
Answer: Use [System.IO.StreamReader] to read line by line without loading the entire file into memory.
StreamReader reads one line at a time, ideal for GB‑sized files. Example:
$reader = [System.IO.StreamReader]::new('huge.log'); while (($line = $reader.ReadLine()) -ne $null) { $line }; $reader.Close()

Command Line Expert & Software Engineer
Welcome! I’m Thomas Heinrich, a software engineer and system administrator with a deep passion for the Command Line Interface (CLI). With years of experience navigating the terminal, building backend architectures, and automating server deployments, I created this space to share practical, real-world terminal knowledge.
Whether you are a beginner taking your first steps in a Linux environment or a seasoned DevOps engineer looking to optimize your deployment scripts, you will find actionable solutions here. My goal is to help you ditch the mouse, speed up your workflow, and harness the full power of the command line.