Top PowerShell Commands for Windows Server Sysadmins
Practical guide to the most useful PowerShell commands for administering Windows Server: service management, users, events, networking, processes, and real-world automation.
Administering Windows Server through the graphical interface works fine until you need to perform the same operation across twenty machines, or repeat a task every night without anyone clicking. That is where PowerShell stops being optional and becomes the Windows sysadmin’s main tool. Cmdlets are consistent, return structured objects instead of text, and cover virtually the entire surface of the operating system.
This guide gathers the PowerShell commands that sysadmins actually use day to day: service management, local and Active Directory accounts, event log reading, network diagnostics, processes, the file system, and scheduled automation. The focus is on commands that replace GUI actions with a single executable, auditable line.
Estimated execution time: 20 to 30 minutes to try every example on a test server. The commands work on Windows Server 2019, 2022, and 2025 with either Windows PowerShell 5.1 or PowerShell 7.
Prerequisites
Windows Server 2019/2022/2025 with PowerShell 5.1 or 7 installed, an account with administrative privileges (member of the Administrators group), and access to the server via console, RDP, or WinRM. For Active Directory commands, the RSAT-AD-PowerShell module must be present.
5.1 7.4 LTS RemoteSigned Administrator Open PowerShell as administrator (right-click the start menu icon and choose “Windows PowerShell (Admin)” or “Terminal (Admin)”). The commands listed below assume that elevated session.
Service and process management
Services and processes are the starting point for most diagnostics. The
cmdlets here replace services.msc and Task Manager for any non-interactive
operation.
List every service and filter by state:
Get-Service | Where-Object Status -eq 'Running'
Get-Service | Where-Object Status -eq 'Stopped' | Where-Object StartType -eq 'Automatic'The second line shows services that should be running but are stopped — one of the most useful diagnostics after a troubled boot.
Start, stop, or restart a service:
Start-Service -Name "Spooler"
Stop-Service -Name "Spooler" -Force
Restart-Service -Name "W3SVC" -ForceThe -Force flag also takes down dependent services. To check
dependencies first, use Get-Service -Name "W3SVC" -DependentServices.
List processes consuming the most CPU or memory:
Get-Process | Sort-Object CPU -Descending | Select-Object -First 10
Get-Process | Sort-Object WorkingSet -Descending | Select-Object -First 10 | Format-Table Name, Id, @{N='RAM(MB)';E={[math]::Round($_.WorkingSet/1MB,1)}}The second command formats the WorkingSet column (resident memory) in rounded MB, avoiding the need to read raw bytes.
Kill a stuck process by PID or name:
Stop-Process -Id 4528 -Force
Stop-Process -Name "notepad" -ForceKilling critical Windows processes (lsass, csrss, wininit) forces an
immediate reboot. Always check Get-Process -Id $pid before applying
-Force.
Users, groups, and Active Directory
For standalone (workgroup) servers, the LocalAccounts cmdlets are enough.
In a domain, import the ActiveDirectory module that ships with RSAT.
Local account management:
New-LocalUser -Name "operator" -Password (Read-Host -AsSecureString "Password") -FullName "NOC Operator"
Add-LocalGroupMember -Group "Administrators" -Member "operator"
Get-LocalUser | Where-Object Enabled -eq $true
Disable-LocalUser -Name "former-employee"Read-Host -AsSecureString prevents the password from appearing in
history or transcripts.
Common Active Directory operations:
Import-Module ActiveDirectory
Get-ADUser -Filter "Enabled -eq \$true" -Properties LastLogonDate | Sort LastLogonDate
Get-ADUser -Filter "PasswordLastSet -lt (Get-Date).AddDays(-90)" -Properties PasswordLastSet
Unlock-ADAccount -Identity "jsmith"
Set-ADAccountPassword -Identity "jsmith" -Reset -NewPassword (Read-Host -AsSecureString)The first filter identifies active users by last logon date — useful for cleaning up orphaned accounts. The second lists who has had a password unchanged for over 90 days.
On large domains, use -LDAPFilter instead of -Filter when the query
involves non-indexed attributes. LDAPFilter pushes the work to the
domain controller instead of filtering client-side.
Events, logs, and auditing
Get-WinEvent is the modern way to read Windows logs. It accepts structured
filters (hashtable) that are orders of magnitude faster than filtering with
Where-Object afterward.
List the 50 most recent errors from the system log:
Get-WinEvent -FilterHashtable @{LogName='System'; Level=2} -MaxEvents 50 |
Format-Table TimeCreated, Id, ProviderName, Message -AutoSize -WrapLevel=2 is Error, Level=3 is Warning, Level=4 is Information. Always
prefer hashtable over Get-WinEvent -LogName System | Where Level -eq 2.
Find logon failures (event 4625) in the last 24 hours:
Get-WinEvent -FilterHashtable @{
LogName = 'Security'
Id = 4625
StartTime = (Get-Date).AddDays(-1)
} | Select-Object TimeCreated, @{N='Account';E={$_.Properties[5].Value}}, @{N='IP';E={$_.Properties[19].Value}}Indexed properties depend on the event — for 4625, index 5 is the attempted account name and index 19 is the source IP.
Export a log to an .evtx file for offline analysis:
wevtutil epl Security C:\backup\security-2026-05-29.evtx
wevtutil cl SecurityThe second line clears the log after the backup. On servers with aggressive auditing, this rotation prevents the log from filling up and silently dropping records.
Networking and diagnostics
The networking cmdlets replace ipconfig, netsh, route, and part of
netstat with structured output that you can chain in scripts.
Interface and routing inspection:
Get-NetIPAddress -AddressFamily IPv4 | Format-Table InterfaceAlias, IPAddress, PrefixLength
Get-NetRoute -AddressFamily IPv4 | Sort-Object RouteMetric | Select -First 10
Get-DnsClientServerAddress -AddressFamily IPv4To change the IP, use New-NetIPAddress combined with Remove-NetIPAddress
on the old address in the same session — doing this through the GUI during
RDP silently drops your connection.
Test connectivity and ports with Test-NetConnection:
Test-NetConnection -ComputerName "8.8.8.8" -Port 443
Test-NetConnection -ComputerName "dc.domain.local" -Port 389 -InformationLevel DetailedThis is the direct replacement for ping + telnet. The -Detailed flag
shows latency, route, and DNS resolution in the same output.
List active TCP connections (netstat replacement):
Get-NetTCPConnection -State Established |
Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, OwningProcess,
@{N='Process';E={(Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue).Name}}Cross-referencing OwningProcess with Get-Process is the kind of
operation that netstat does not do natively without -b and elevated
privilege.
File system and backup
Find large or recent files:
Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue |
Where-Object Length -gt 500MB |
Sort-Object Length -Descending |
Select-Object FullName, @{N='SizeGB';E={[math]::Round($_.Length/1GB,2)}} -First 20-ErrorAction SilentlyContinue ignores protected folders (System Volume
Information, $Recycle.Bin) without flooding the terminal with errors.
Compress a folder for backup with a checksum:
Compress-Archive -Path C:\inetpub\wwwroot -DestinationPath D:\backup\web-2026-05-29.zip -CompressionLevel Optimal
Get-FileHash D:\backup\web-2026-05-29.zip -Algorithm SHA256The SHA-256 hash confirms integrity when the file is transferred to remote storage.
Verification
To confirm that your session has privileges and the right modules loaded:
[Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent() | Select-Object @{N='Admin';E={$_.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)}}
Get-Module -ListAvailable ActiveDirectory, ServerManager, NetTCPIP | Format-Table Name, Version
$PSVersionTable.PSVersion
The first command returns True if the session is elevated. The second
lists the critical modules available. The third shows the exact PowerShell
version — useful when a script fails on one server but runs on another.
Next steps
From these commands, the natural path is to build scheduled scripts for recurring tasks (log rotation, configuration snapshots, patch verification) and centralize execution through PowerShell Remoting instead of RDP. A few directions to go deeper:
- Desired State Configuration (DSC) to keep declarative configuration across multiple servers
- PowerShell remoting with JEA (Just Enough Administration) to give restricted access to operators without making them full admins
- PSReadLine and oh-my-posh modules to make the CLI more productive in long sessions
- Centralized logs via Windows Event Forwarding to correlate events across servers
If you are putting these scripts into production, a Hostini Windows VPS already ships with PowerShell 7 installed, RDP open, and on-demand snapshots — making it easy to test destructive automations without fear of breaking the main server.
Frequently asked questions
What is the difference between Windows PowerShell 5.1 and PowerShell 7?
Windows PowerShell 5.1 ships built-in with Windows Server 2016+, uses .NET Framework, and has full coverage of legacy modules (ServerManager, ActiveDirectory). PowerShell 7 is cross-platform, runs on .NET 8, is faster, and gains new features like ternary operators and parallel pipelines. On a server, keep 5.1 as the default and install 7 side by side when you need it.
How do I run a PowerShell script if I get an execution policy error?
Run `Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned` to allow local scripts and require signing on downloaded scripts. For a one-off ad-hoc script, use `powershell.exe -ExecutionPolicy Bypass -File C:\scripts\my.ps1`. Avoid `Unrestricted` in production — it opens a gap for unsigned scripts to run without confirmation.
Do Get-EventLog and Get-WinEvent do the same thing?
No. Get-EventLog is the legacy cmdlet, reads only classic logs (System, Application, Security), and is slower. Get-WinEvent uses the modern ETW API, reads both classic logs and analytical channels of the Windows Event Log, supports XPath filters, and is dramatically faster on large logs. Use Get-WinEvent in any new script.
How do I run PowerShell remotely between servers in the same domain?
Enable WinRM with `Enable-PSRemoting -Force` on the target server. Then run `Invoke-Command -ComputerName srv02 -ScriptBlock { Get-Service }` or open a persistent session with `Enter-PSSession srv02`. In a domain, Kerberos authentication is automatic. For machines outside the domain, configure TrustedHosts or use HTTPS with a certificate.
Why is the PowerShell pipeline slower than cmd in large loops?
The pipeline passes full .NET objects between cmdlets, not text. In loops with millions of iterations that adds up. Solutions: use `.ForEach()` instead of `ForEach-Object` when the collection fits in memory, avoid unnecessary `Select-Object`, and prefer `[System.IO.File]::ReadAllLines()` for very large files instead of `Get-Content`.
How do I schedule a PowerShell script to run daily?
Use Task Scheduler via cmdlets: `Register-ScheduledTask -TaskName "Backup" -Trigger (New-ScheduledTaskTrigger -Daily -At 3am) -Action (New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-NoProfile -File C:\scripts\backup.ps1") -RunLevel Highest -User "SYSTEM"`. Always use `-NoProfile` to avoid loading user profiles and standardize logs with `Start-Transcript`.