powershell-windows-dev

$npx mdskill add microsoft/amplifier-bundle-windows-shell/powershell-windows-dev

Load this skill when: - Working on a Windows platform where PowerShell is the primary shell - Writing PowerShell scripts or commands - Translating Unix/bash scripts to PowerShell - Performing system administration tasks on Windows - Working with Windows-specific features (registry, services, WMI, Active Directory)

SKILL.md

.github/skills/powershell-windows-devView on GitHub ↗
---
skill:
  name: powershell-windows-dev
  version: 1.0.0
  description: Comprehensive PowerShell and Windows development reference — command equivalents, scripting patterns, file operations, and Windows-specific conventions
  authors:
    - name: Microsoft MADE:Explorations Team
---

# PowerShell and Windows Development

## When to Use This Skill

Load this skill when:
- Working on a Windows platform where PowerShell is the primary shell
- Writing PowerShell scripts or commands
- Translating Unix/bash scripts to PowerShell
- Performing system administration tasks on Windows
- Working with Windows-specific features (registry, services, WMI, Active Directory)

## Tool Selection Guide

| Platform | Preferred Shell | Fallback | Notes |
|---|---|---|---|
| Windows (native) | `pwsh` | `bash` (Git Bash/WSL) | Unix tools unavailable natively |
| WSL | `bash` | `pwsh` | Full Linux tools available |
| Linux | `bash` | `pwsh` (if installed) | pwsh available via snap/apt |
| macOS | `bash` | `pwsh` (if installed) | pwsh available via brew |

## File Operations

### Reading Files
```powershell
# Read entire file
Get-Content file.txt

# First N lines (head)
Get-Content file.txt -TotalCount 20

# Last N lines (tail)
Get-Content file.txt -Tail 20

# Specific line range (0-indexed array)
(Get-Content file.txt)[9..19]    # Lines 10-20

# Read as single string (not line array)
Get-Content file.txt -Raw

# Read with encoding
Get-Content file.txt -Encoding UTF8
```

### Writing Files
```powershell
# Write string to file (overwrite)
"content" | Set-Content file.txt

# Append to file
"more content" | Add-Content file.txt

# Write from pipeline
Get-Process | Out-File processes.txt

# Write with specific encoding
"content" | Set-Content file.txt -Encoding UTF8

# Create file if not exists, don't overwrite
if (-not (Test-Path file.txt)) { New-Item file.txt }
```

### File Search and Discovery
```powershell
# Find files by name pattern (like find -name)
Get-ChildItem -Recurse -Filter "*.py"

# Find files by regex name
Get-ChildItem -Recurse | Where-Object { $_.Name -match "test_.*\.py$" }

# Find directories only
Get-ChildItem -Recurse -Directory

# Find files modified in last 24h
Get-ChildItem -Recurse | Where-Object { $_.LastWriteTime -gt (Get-Date).AddDays(-1) }

# Find files larger than 1MB
Get-ChildItem -Recurse | Where-Object { $_.Length -gt 1MB }

# Exclude directories
Get-ChildItem -Recurse -Exclude "node_modules","__pycache__",".git"
```

### Content Search (grep equivalents)
```powershell
# Basic search in file
Select-String -Path "file.txt" -Pattern "error"

# Recursive search in directory
Get-ChildItem -Recurse -Filter "*.py" | Select-String "import asyncio"

# Case-sensitive search (PowerShell is case-insensitive by default)
Select-String -Path "*.py" -Pattern "Error" -CaseSensitive

# Search with context lines (like grep -C)
Select-String -Path "*.py" -Pattern "def mount" -Context 2,2

# Regex search
Select-String -Path "*.log" -Pattern "\d{4}-\d{2}-\d{2}.*ERROR"

# Search and extract matches
Select-String -Path "*.py" -Pattern "version\s*=\s*['\"](.+?)['\"]" |
    ForEach-Object { $_.Matches.Groups[1].Value }

# Count matches (like grep -c)
(Select-String -Path "*.py" -Pattern "TODO").Count

# List files with matches (like grep -l)
Select-String -Path "*.py" -Pattern "import" | Select-Object -Unique Path
```

### Text Processing (sed/awk equivalents)
```powershell
# Replace in file content (like sed 's/old/new/g')
(Get-Content file.txt) -replace 'old', 'new' | Set-Content file.txt

# Replace with regex
(Get-Content file.txt) -replace '\d{4}', 'YEAR' | Set-Content file.txt

# Process line by line (like awk)
Get-Content data.csv | ForEach-Object {
    $fields = $_ -split ','
    "$($fields[0]) - $($fields[2])"
}

# Filter lines (like grep)
Get-Content file.txt | Where-Object { $_ -match 'pattern' }

# Number lines (like nl or cat -n)
$i = 1; Get-Content file.txt | ForEach-Object { "{0,4} {1}" -f $i++, $_ }

# Sort and unique
Get-Content file.txt | Sort-Object -Unique
```

## Process Management

```powershell
# List processes (like ps aux)
Get-Process

# Find specific process
Get-Process -Name "python*"
Get-Process | Where-Object { $_.CPU -gt 10 }

# Kill process by PID
Stop-Process -Id 1234

# Kill process by name
Stop-Process -Name "python" -Force

# Start process in background
Start-Process pwsh -ArgumentList "-Command", "long-running-script.ps1" -NoNewWindow

# Wait for process to exit
$proc = Start-Process pwsh -ArgumentList "-c", "Start-Sleep 5" -PassThru
$proc | Wait-Process -Timeout 10
```

## Environment and System

```powershell
# Get/set environment variables
$env:MY_VAR = "value"
Write-Output $env:MY_VAR
Get-ChildItem Env:                    # List all env vars

# System information
$PSVersionTable                        # PowerShell version
[System.Environment]::OSVersion       # OS version
[System.Environment]::MachineName     # Computer name
[System.Environment]::UserName        # Current user

# Path operations
$env:PATH -split [IO.Path]::PathSeparator    # Split PATH
Join-Path $HOME "Documents" "file.txt"       # Join path segments
[IO.Path]::GetExtension("file.py")           # Get extension
Resolve-Path "~/Documents"                    # Resolve ~ and relative paths

# Check if running as admin
([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
```

## Package Management

```powershell
# Windows Package Manager (winget)
winget search python
winget install Python.Python.3.12
winget upgrade --all

# Chocolatey (if installed)
choco install nodejs
choco upgrade all

# PowerShell modules
Install-Module -Name Az -Scope CurrentUser
Get-InstalledModule
Update-Module -Name Az

# pip (Python) — works the same
pip install package-name
pip install -r requirements.txt
```

## Network Operations

```powershell
# HTTP requests (like curl)
Invoke-WebRequest -Uri "https://api.example.com/data"

# REST API calls (returns parsed JSON directly)
$response = Invoke-RestMethod -Uri "https://api.example.com/data"
$response.items | Format-Table

# Download file (like wget)
Invoke-WebRequest -Uri "https://example.com/file.zip" -OutFile "file.zip"

# POST with JSON body
$body = @{ name = "test"; value = 42 } | ConvertTo-Json
Invoke-RestMethod -Uri "https://api.example.com" -Method Post -Body $body -ContentType "application/json"

# Check port (like nc or telnet)
Test-NetConnection -ComputerName "localhost" -Port 8080
```

## Windows-Specific Operations

### Services
```powershell
Get-Service                              # List all services
Get-Service -Name "wuauserv"            # Specific service
Start-Service -Name "ServiceName"
Stop-Service -Name "ServiceName"
Restart-Service -Name "ServiceName"
```

### Registry
```powershell
# Read registry
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion"

# Set registry value
Set-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Setting" -Value "NewValue"

# Test if key exists
Test-Path "HKLM:\SOFTWARE\MyApp"
```

### Scheduled Tasks
```powershell
Get-ScheduledTask
Get-ScheduledTask -TaskName "TaskName" | Get-ScheduledTaskInfo
```

## Scripting Patterns

### Error Handling
```powershell
try {
    Get-Content "nonexistent.txt" -ErrorAction Stop
} catch {
    Write-Error "Failed: $_"
} finally {
    # Cleanup code
}
```

### Functions
```powershell
function Get-ProjectFiles {
    param(
        [string]$Path = ".",
        [string]$Extension = "*.py",
        [switch]$IncludeTests
    )

    $files = Get-ChildItem -Path $Path -Recurse -Filter $Extension
    if (-not $IncludeTests) {
        $files = $files | Where-Object { $_.FullName -notmatch "test" }
    }
    return $files
}
```

### Conditional Execution
```powershell
# If/else
if (Test-Path $filePath) {
    Get-Content $filePath
} else {
    Write-Warning "File not found: $filePath"
}

# Ternary (PowerShell 7+)
$result = Test-Path $file ? "exists" : "missing"

# Null coalescing (PowerShell 7+)
$value = $env:MY_VAR ?? "default"
```

### Pipeline Best Practices
```powershell
# PowerShell pipelines pass OBJECTS, not text
# This is a fundamental difference from bash

# Bad (bash-style text parsing):
Get-Process | Out-String | Select-String "python"

# Good (object pipeline):
Get-Process | Where-Object Name -like "*python*"

# Object properties are directly accessible
Get-ChildItem *.py | Select-Object Name, Length, LastWriteTime

# Measure and aggregate
Get-ChildItem -Recurse *.py | Measure-Object -Property Length -Sum
```

## Path Conventions

| Convention | Windows | Linux/macOS |
|---|---|---|
| Separator | `\` (also accepts `/`) | `/` |
| Home | `$HOME` or `$env:USERPROFILE` | `$HOME` or `~` |
| Temp | `$env:TEMP` | `/tmp` |
| Current dir | `$PWD` or `.` | `$PWD` or `.` |
| Drive root | `C:\` | `/` |
| Program files | `$env:ProgramFiles` | `/usr/local` |

**Tip**: PowerShell accepts forward slashes on Windows: `Get-Content C:/Users/me/file.txt` works fine.