PowerShell Basics You Actually Need
Most people approach PowerShell thinking it is just a Windows command prompt with extra steps. It is not. It is an object-oriented shell that passes .NET objects between commands instead of text. This changes everything about how you write scripts. The difference between success and failure usually comes down to understanding what the pipeline actually carries. I spent years maintaining batch files before switching to PowerShell about six years ago. The transition was painful. One specific problem I hit regularly was trying to parse error output from programs that wrote to stderr instead of stdout. In cmd.exe you just redirected all output with 2>&1. In PowerShell the error streams are separate. The correct syntax is `Start-Process myapp.exe 2>&1`. Without that ampersand you get nothing but a confusing error message.Windows Powershell Cheat Sheet
The cheat sheet people bookmark usually covers basic cmdlets. Get-Process shows running programs. Stop-Process kills them. Get-Service displays services and their states. These work fine for quick checks. The real value comes when you combine them. Here is a practical example that I use weekly: This finds processes using more than 100 CPU seconds and sorts them by usage. The `$_` variable represents the current object in the pipeline. Beginners often forget the underscore or type `$` twice. Both approaches are wrong. File operations in PowerShell follow a consistent pattern. Copy-Item copies files. Move-Item moves them. Remove-Item deletes them. The `-Recurse` flag handles directories. The `-Force` flag shows hidden files. Without these flags you waste time clicking through folder dialogs.
```powershell Get-ChildItem C:\logs -Filter *.txt -Recurse | Where-Object { $_.Length -gt 1MB } | Remove-Item -WhatIf ```The `-WhatIf` parameter shows what would happen without actually doing it. I use this before any bulk deletion. It prevents the kind of mistakes that require restore points or backups.
String Handling That Works
String manipulation in PowerShell has changed between versions. Version 5.1 uses different operators than version 7. The `-replace` operator uses regex by default. The `-like` operator uses wildcards. Mixing them up produces wrong results every time. I learned this the hard way when migrating a script from Windows Server 2019 to a newer system. A simple string replacement that worked on the old server produced garbage output on the new one. The issue was an empty capture group in the regex. The fix was adding explicit non-capturing groups with `(?:`. ```powershell $date = Get-Date $formatted = $date.ToString('yyyy-MM-dd') $clean = $formatted -replace '-', '' Write-Output $clean ```This formats the current date and removes dashes. The output is `20240115`. Simple. Reliable. No localization issues.
Get the Full Details

Error Handling That Prevents Tears
Error handling separates scripts from production code. The `try-catch-finally` block works in PowerShell. The `-ErrorAction` parameter controls error behavior. Setting it to `SilentlyContinue` hides errors. Setting it to `Stop` treats non-terminating errors as fatal. I encountered a specific problem when processing API responses that returned null values. The script threw exceptions on every empty response. The workaround was using the null-coalescing operator with `??`. In PowerShell 7 this works naturally. In version 5.1 you need `if ($value -ne $null)`. ```powershell try { $result = Invoke-RestMethod -Uri 'https://api.example.com/data' -ErrorAction Stop } catch [System.Net.WebException] { Write-Error "Network error: $($_.Exception.Message)" } finally { Write-Host "Processing complete" } ```The `finally` block runs regardless of success or failure. Use it for cleanup tasks like closing connections or releasing resources. I always include it when working with external services.
Advanced Techniques You Should Know
The pipeline in PowerShell can handle parallel execution with `-Parallel`. This feature arrived in PowerShell 7. Before that you used background jobs with `Start-Job`. The difference in performance is usually 3x to 5x faster depending on your CPU count. I found a counter-intuitive issue when processing large CSV files. The `Import-Csv` cmdlet loaded everything into memory. For files over 500MB this caused out-of-memory exceptions. The workaround was using `OpenRead` with a text reader and parsing line by line. This reduced memory usage from 2GB to about 50MB. ```powershell Get-Content largefile.csv | ForEach-Object -Parallel { $_.Split(',') | ConvertTo-Hashtable } -ThrottleLimit 10 ```The `-ThrottleLimit` parameter controls parallel workers. Setting it too high causes resource contention. Ten workers usually balances speed and stability on most systems.