# Windows Internals & PowerShell Automation: Taming the Beast

**Author:** kelexine  
**Date:** 2025-12-10  
**Category:** Windows  
**Tags:** Windows, PowerShell, Automation, Scripting, DevOps  
**URL:** https://kelexine.is-a.dev/blog/windows-powershell-automation

---

# Windows: The Other Side

Look, I get it. If you're reading my blog, you're probably a Linux enthusiast. But here's the truth: Windows runs on billions of machines, and knowing how to automate it is a superpower.

I've spent years building Windows automation tools—from tiny11 builders to enterprise deployment scripts. This is everything I've learned about bending Windows to my will.

## Why PowerShell?

PowerShell isn't bash. Stop trying to use it like bash. Once you embrace its object-oriented nature, it becomes incredibly powerful.

```powershell
# In bash: text manipulation hell
ps aux | grep nginx | awk '{print $2}' | xargs kill

# In PowerShell: objects all the way down
Get-Process nginx | Stop-Process
```

The key insight: **everything in PowerShell is an object**. When you pipe data, you're not passing text—you're passing structured objects with properties and methods.

## PowerShell Fundamentals

### The Verb-Noun Convention

Every cmdlet follows `Verb-Noun` naming:

```powershell
Get-Process      # Get info about processes
Stop-Service     # Stop a service
Set-Location     # Change directory (cd is an alias)
New-Item         # Create a file or folder
Remove-Item      # Delete stuff
Copy-Item        # Copy stuff
```

### Discovering Commands

```powershell
# Find all commands with "Process" in the name
Get-Command *Process*

# Get help (with examples!)
Get-Help Get-Process -Examples

# See all properties of an object
Get-Process | Get-Member

# See what a command would do without doing it
Stop-Service nginx -WhatIf
```

## Working with the System

### Process Management

```powershell
# List all processes
Get-Process

# Filter by name
Get-Process -Name "chrome", "firefox"

# Find processes using lots of memory
Get-Process | Where-Object { $_.WorkingSet64 -gt 500MB } | 
    Sort-Object WorkingSet64 -Descending |
    Select-Object Name, @{N='MemoryMB';E={[math]::Round($_.WorkingSet64/1MB,2)}}

# Kill a process
Stop-Process -Name "notepad" -Force

# Start a process
Start-Process notepad.exe
Start-Process "https://kelexine.is-a.dev"  # Opens in browser!
```

### Service Control

```powershell
# List all services
Get-Service

# Get services with specific status
Get-Service | Where-Object Status -eq "Running"

# Start/Stop/Restart
Start-Service -Name "wuauserv"
Stop-Service -Name "spooler" -Force
Restart-Service -Name "nginx"

# Set startup type
Set-Service -Name "DiagTrack" -StartupType Disabled
```

### Working with the Registry

The registry is Windows' configuration database. PowerShell treats it like a filesystem:

```powershell
# Navigate registry like a drive
Set-Location HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion

# Read a value
Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" -Name ProductName

# Write a value (requires admin)
Set-ItemProperty -Path "HKCU:\Software\MyApp" -Name "Setting" -Value "enabled"

# Create a new key
New-Item -Path "HKCU:\Software\MyApp" -Force

# Delete a key
Remove-Item -Path "HKCU:\Software\MyApp" -Recurse
```

## File System Operations

```powershell
# Create directory
New-Item -ItemType Directory -Path "C:\Projects\NewFolder"

# Create file with content
"Hello, World!" | Out-File "C:\Projects\hello.txt"

# Read file
Get-Content "C:\Projects\hello.txt"
$content = Get-Content "C:\Projects\config.json" | ConvertFrom-Json

# Copy with progress
Copy-Item -Path "C:\Source\*" -Destination "D:\Backup\" -Recurse -Verbose

# Find files
Get-ChildItem -Path "C:\" -Filter "*.log" -Recurse -ErrorAction SilentlyContinue |
    Where-Object { $_.LastWriteTime -lt (Get-Date).AddDays(-30) }
```

## Windows Features & Components

```powershell
# List all Windows features
Get-WindowsOptionalFeature -Online

# Enable a feature
Enable-WindowsOptionalFeature -Online -FeatureName "Microsoft-Windows-Subsystem-Linux" -NoRestart

# Disable a feature
Disable-WindowsOptionalFeature -Online -FeatureName "WindowsMediaPlayer"

# DISM in PowerShell
Get-WindowsCapability -Online | Where-Object Name -like "*RSAT*"
```

## Remote Administration

```powershell
# Enable WinRM (on target machine)
Enable-PSRemoting -Force

# Create a session
$session = New-PSSession -ComputerName "SERVER01" -Credential (Get-Credential)

# Run remote command
Invoke-Command -Session $session -ScriptBlock {
    Get-Process | Where-Object CPU -gt 100
}

# Copy files to remote machine
Copy-Item -Path "C:\Scripts\deploy.ps1" -Destination "C:\Scripts\" -ToSession $session

# Close session
Remove-PSSession $session
```

## Scripting Best Practices

### Script Template

```powershell
#Requires -Version 5.1
#Requires -RunAsAdministrator

[CmdletBinding()]
param(
    [Parameter(Mandatory = $true)]
    [string]$ComputerName,
    
    [Parameter(Mandatory = $false)]
    [switch]$Force
)

$ErrorActionPreference = "Stop"

function Write-Log {
    param([string]$Message)
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    "$timestamp - $Message" | Tee-Object -FilePath "$PSScriptRoot\script.log" -Append
}

try {
    Write-Log "Starting script execution..."
    # Your code here
    Write-Log "Script completed successfully"
}
catch {
    Write-Log "ERROR: $($_.Exception.Message)"
    throw
}
```

## Conclusion

PowerShell isn't just a shell—it's a complete automation framework. Whether you're managing a single machine or a fleet of servers, these tools let you do in minutes what would take hours manually.

> Yes, I still prefer Linux. But when I have to work with Windows, PowerShell makes it almost tolerable.

---

**Resources**:
- [PowerShell Documentation](https://docs.microsoft.com/en-us/powershell/)
- [PowerShell Gallery](https://www.powershellgallery.com/)

---

*This content is available at [kelexine.is-a.dev/blog/windows-powershell-automation](https://kelexine.is-a.dev/blog/windows-powershell-automation)*
