Why PowerShell Matters
PowerShell isn't just a Windows shell -- it's a full automation platform that every Windows system administrator should master. With 15+ years in IT, I've seen the transition from batch files and VBScript to PowerShell, and the difference is night and day. PowerShell gives you programmatic access to everything: Active Directory, Hyper-V, file systems, the registry, WMI, and more.
If you're spending more than 5 minutes on a repetitive task, there's a PowerShell way to automate it. Period.
Getting Started with AD PowerShell
The ActiveDirectory module is installed by default on Domain Controllers. For remote management, install the RSAT tools on your workstation:
Install-WindowsFeature RSAT-AD-Tools
Essential AD commands every admin should know:
Get-ADUser -Filter * -Properties DisplayName,Email,LastLogonDate-- List all users with key propertiesGet-ADUser -Filter {Enabled -eq $false} -Properties LastLogonDate-- Find disabled accountsGet-ADUser -Filter {LastLogonDate -lt (Get-Date).AddDays(-90)}-- Find users who haven't logged on in 90 daysNew-ADUser -Name "John Doe" -SamAccountName "jdoe" -Enabled $true-- Create a new userSet-ADUser -Identity "jdoe" -Description "Marketing Dept"-- Update user attributesDisable-ADAccount -Identity "jdoe"-- Disable an accountGet-ADGroupMember "Domain Admins"-- List members of a security groupNew-ADOrganizationalUnit -Name "Departments" -ProtectedFromAccidentalDeletion $true-- Create a protected OU
Hyper-V Automation
The Hyper-V PowerShell module lets you manage VMs programmatically. This is invaluable for homelab automation:
Get-VM-- List all VMs with status, CPU, and memory allocationStart-VM -Name "DC01"-- Start a VMStop-VM -Name "DC01" -TurnOff-- Force stop a VMCheckPoint-VM -Name "DC01" -SnapshotName "BeforeUpdate"-- Create a checkpoint before maintenanceNew-VM -Name "WebServer" -MemoryStartupBytes 4GB -VhdPath "D:\VMs\WebServer.vhdx"-- Create a new VMSet-VMProcessor -VMName "WebServer" -Count 4-- Assign CPU coresGet-VMSwitch-- List virtual switchesNew-VMSwitch -Name "InternalSwitch" -SwitchType Internal-- Create an internal virtual switch
Combine these with scheduled tasks for automated VM maintenance. For example, stop all non-essential VMs at 10 PM and start them at 6 AM:
Get-VM | Where-Object {$_.Name -notlike "DC*" -and $_.Name -notlike "FS*"} | Stop-VM -TurnOff
File System and Disk Management
PowerShell makes file system operations fast and scriptable:
Get-ChildItem -Path "C:\Logs" -Recurse | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)}-- Find files older than 30 daysGet-ChildItem -Path "D:\Backups" | Sort-Object Length -Descending | Select-Object -First 10-- List largest backup filesGet-Volume-- Check disk space across all volumesGet-PSDrive -PSProvider FileSystem | Where-Object {$_.Free / 1GB -lt 50}-- Find drives with less than 50GB freeCompress-Archive -Path "C:\Data\OldFiles" -DestinationPath "D:\Archive\OldFiles.zip"-- Compress old files
System Information and Monitoring
Get-CimInstance Win32_Processor-- CPU detailsGet-CimInstance Win32_ComputerSystem-- System model, RAM, manufacturerGet-CimInstance Win32_OperatingSystem-- OS version, build, boot timeGet-CimInstance Win32_Service | Where-Object {$_.State -eq "Stopped"}-- Stopped servicesGet-EventLog -LogName System -EntryType Error -Newest 20-- Recent system errorsGet-Process | Sort-Object WorkingSet -Descending | Select-Object -First 10-- Top 10 memory-consuming processes
Useful Automation Scripts
Automated user offboarding:
Disable-ADAccount -Identity $username
Set-ADUser -Identity $username -AccountNotDelegated $true
Add-ADGroupMember -Identity "Password Reset Operators" -Members $username
Move-ADObject -Identity (Get-ADUser $username).DistinguishedName -TargetPath "OU=Disabled,DC=corp,DC=local"
Weekly stale account report:
Get-ADUser -Filter {Enabled -eq $true} -Properties LastLogonDate | Where-Object {$_.LastLogonDate -lt (Get-Date).AddDays(-60)} | Select-Object Name,LastLogonDate,EmailAddress | Export-Csv -Path "C:\Reports\StaleAccounts.csv"
VM health check:
Get-VM | Select-Object Name,State,CPUUsage,MemoryAssigned,Status | Format-Table
PowerShell Best Practices
- Use parameter splatting -- For commands with many parameters, use a hashtable:
$params = @{Name="John";SamAccountName="jdoe"}; New-ADUser @params - Pipeline everything -- PowerShell's strength is piping objects between cmdlets.
Get-ADUser | Where-Object | Select-Object | Export-Csv - Use -WhatIf and -Confirm -- Test destructive commands safely before running them
- Write functions, not just scripts -- Functions can be imported, piped, and reused. Scripts are one-off
- Use try/catch for error handling -- Don't let failed commands break your script. Use
try { } catch { Write-Error } - Comment your code -- Even simple scripts need documentation for the next person (which might be you in 6 months)