Emergency server help: get in touch

PowerShell Cheat Sheet for Windows Server Admins

PowerShell cheat sheet for Windows Server admins: services, Get-WinEvent filters, networking, firewall, disks, updates, local users, Active Directory, remoting and tasks.

Published 9 min read

Short answer: Most Windows Server admin work in PowerShell comes down to a small set of cmdlets: Get-Service/Restart-Service for services, Get-WinEvent -FilterHashtable for event logs, Test-NetConnection and Resolve-DnsName for networking, Get-NetFirewallRule for the firewall, Get-Volume and Get-HotFix for disks and updates, and Get-ADUser/Search-ADAccount for Active Directory. Pipe results into Where-Object, Select-Object and Export-Csv, and add -WhatIf before anything that changes state.

We ran these commands on our Windows lab on 7 October 2026: a Windows Server 2025 Standard domain controller (build 26100, Windows PowerShell 5.1) for the test domain contoso.com, and a domain-joined Windows 11 Pro client (build 22631). Read-only cmdlets ran as shown. Cmdlets that change state (Restart-Service, Unlock-ADAccount, New-NetFirewallRule and similar) ran with -WhatIf only. The remoting cmdlets and Register-ScheduledTask were syntax-checked only, because they have no -WhatIf and our lab sessions cannot open remote sessions.

Help and discovery

CommandWhat it does
Get-Help Get-WinEvent -ExamplesUsage examples (after help is downloaded)
Get-Help Get-WinEvent -OnlineOpens the Microsoft Learn page in a browser
Update-HelpDownloads local help files (run as administrator, needs internet)
Get-Command -Noun ServiceEvery cmdlet that works on services
Get-Command *firewall*Search by wildcard
Get-Command -Module ActiveDirectoryEverything in a module (151 commands on our DC)
Get-Service W32Time | Get-MemberProperties and methods of the objects a cmdlet returns

On our fresh Server 2025 DC, Get-Help showed only the syntax and no examples, because Windows ships without the full help files. Run Update-Help once, or use -Online. Get-Member is the one to remember: it tells you which property names you can filter and sort on.

Services and processes

CommandWhat it does
Get-Service W32Time, WinRM, DNSStatus and start type of named services
Get-Service | Where-Object { $_.StartType -eq 'Automatic' -and $_.Status -ne 'Running' }Automatic services that are not running
Restart-Service W32TimeRestart a service (add -WhatIf to preview)
Stop-Service Spooler / Start-Service SpoolerStop or start
Set-Service RemoteRegistry -StartupType DisabledChange the start type
Get-CimInstance Win32_Service -Filter "Name='WinRM'"Service account and binary path
Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 5Top memory users
Get-Process lsass -IncludeUserNameProcess owner (needs an elevated session)
Stop-Process -Name notepadKill by name (or -Id)
PS> Get-Service W32Time, WinRM, NTDS, DNS | Format-Table Name, Status, StartType

Name     Status StartType
----     ------ ---------
DNS     Running Automatic
NTDS    Running Automatic
W32Time Running Automatic
WinRM   Running Automatic

PS> Restart-Service W32Time -WhatIf
What if: Performing the operation "Restart-Service" on target "Windows Time (W32Time)".

The “automatic but stopped” filter is a quick health check after a reboot. On our DC it listed services such as wuauserv and sppsvc, which Windows starts when needed and stops again when idle. Only investigate the ones you recognise as always-on.

Event logs with Get-WinEvent -FilterHashtable

-FilterHashtable filters inside the event log service, so it is much faster than piping every event to Where-Object. Level 1 is Critical, 2 Error, 3 Warning.

# Errors and critical events in the System log, last 24 hours
Get-WinEvent -FilterHashtable @{LogName='System'; Level=1,2; StartTime=(Get-Date).AddDays(-1)}

# Failed logons (4625) in the last 7 days, counted
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddDays(-7)} |
    Measure-Object

# Account lockouts (4740, on a DC) with user and source computer
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4740} -MaxEvents 10 |
    Select-Object TimeCreated,
        @{n='User';  e={$_.Properties[0].Value}},
        @{n='Source';e={$_.Properties[1].Value}}

# Shutdowns and restarts: 1074 = who restarted, 6006 = log stopped, 6005 = log started
Get-WinEvent -FilterHashtable @{LogName='System'; Id=1074,6005,6006} -MaxEvents 6

# Log sizes and record counts
Get-WinEvent -ListLog System, Security, Application

On our DC, the lockout query found a real lockout we had caused while testing:

TimeCreated          User Source
-----------          ---- ------
10/6/2026 2:19:21 PM erin WINCLIENT

For 4625 on Server 2025, the failed account name is $_.Properties[5].Value and the source IP is $_.Properties[19].Value (we checked the positions against the event XML). On our DC, most of 622 failures in a week had - as the IP, which means a local or Kerberos-related failure rather than a network logon. Our guides on tracing lockouts with event 4740 and RDP connection event IDs go deeper.

Networking and firewall

CommandWhat it does
Get-NetIPAddress -AddressFamily IPv4IP addresses per interface
Get-NetIPConfigurationIP, gateway and DNS servers in one view
Get-DnsClientServerAddress -AddressFamily IPv4Which DNS servers the host uses
Test-NetConnection 203.0.113.10 -Port 443Ping plus a TCP port test (replaces telnet)
Test-NetConnection example.com -Port 80 -InformationLevel QuietReturns just True or False, for scripts
Test-NetConnection 203.0.113.10 -TraceRouteTraceroute
Resolve-DnsName example.com -Type MX -Server 1.1.1.1DNS query against a chosen server
Resolve-DnsName _ldap._tcp.dc._msdcs.contoso.com -Type SRVFind domain controllers through DNS
Get-NetTCPConnection -State ListenListening ports with owning process ID (like netstat -ano)
Get-NetFirewallProfileFirewall on/off per profile, default action, log path
Get-NetFirewallRule -DisplayGroup 'Remote Desktop'Rules in a built-in group
Get-NetFirewallRule -DisplayName 'Remote Desktop - User Mode (TCP-In)' | Get-NetFirewallPortFilterPorts a rule covers
Get-NetFirewallRule -Enabled True -Direction Inbound -Action AllowAll active inbound allow rules (163 on our DC)

Map listening ports to process names in one line:

Get-NetTCPConnection -State Listen |
    Sort-Object LocalPort -Unique |
    Select-Object LocalPort, OwningProcess,
        @{n='Process'; e={(Get-Process -Id $_.OwningProcess).Name}}
LocalPort OwningProcess Process
--------- ------------- -------
       53          4092 dns
       88           992 lsass
      389           992 lsass
      445             4 System
     3389          1324 svchost
     5985             4 System

(Trimmed to the domain controller ports.) Port 5985 is WinRM over HTTP. It shows as System (PID 4) because WinRM listens through HTTP.sys, the kernel HTTP driver. To add a rule for one source address, preview it first:

New-NetFirewallRule -DisplayName 'Allow SQL 1433 from app' -Direction Inbound `
    -Protocol TCP -LocalPort 1433 -RemoteAddress 203.0.113.10 -Action Allow -WhatIf

Remove -WhatIf to create it. To roll back, Disable-NetFirewallRule -DisplayName 'Allow SQL 1433 from app' keeps the rule but switches it off. For domain-wide rules, use Windows Firewall through Group Policy instead of per-server rules.

Disks, updates and files

CommandWhat it does
Get-VolumeDrive letters, file system, size, free space, health
Get-PSDrive -PSProvider FileSystemUsed and free space per drive letter
Get-DiskPhysical disks, partition style (GPT/MBR), status
Get-HotFix | Sort-Object InstalledOn -DescendingInstalled updates, newest first
Get-HotFix -Id KB5122870Is one update installed?
Get-ComputerInfo -Property OsName, OsVersion, OsLastBootUpTimeOS version and last boot
Get-ChildItem C:\Logs -Recurse -File | Sort-Object Length -Descending | Select-Object -First 10Largest files under a folder
Get-Content C:\Logs\app.log -Tail 50 -WaitLast 50 lines, then follow (like tail -f)
Select-String -Path C:\Logs\*.log -Pattern 'error'Search inside files (like grep)
Get-FileHash file.iso -Algorithm SHA256Checksum of a download
Get-Acl C:\Share | Select-Object -ExpandProperty AccessNTFS permissions on a folder
PS> Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 3

HotFixID  Description     InstalledOn
--------  -----------     -----------
KB5122870 Security Update 10/6/2026 12:00:00 AM
KB5122871 Security Update 10/6/2026 12:00:00 AM
KB5126052 Update          10/6/2026 12:00:00 AM

Get-HotFix reads the Win32_QuickFixEngineering class. Microsoft’s documentation for that class says updates supplied by Windows Installer (MSI) or the Windows Update site are not returned, so check the Windows Update history too when an update seems to be missing.

Before you run Remove-Item -Recurse on a log or temp folder, run the same command with -WhatIf and read the list. There is no recycle bin for files deleted from PowerShell.

Local users and groups

CommandWhat it does
Get-LocalUserLocal accounts, enabled state, last logon
Get-LocalGroupMember -Group AdministratorsWho is a local admin, including domain groups
Add-LocalGroupMember -Group 'Remote Desktop Users' -Member 'CONTOSO\bob'Grant RDP to a domain user
Disable-LocalUser -Name GuestDisable a local account

On our Windows 11 client, Get-LocalGroupMember -Group Administrators returned CONTOSO\Domain Admins (source ActiveDirectory) and the local Administrator. On the domain controller the same command failed with Group Administrators was not found., and Get-LocalUser listed domain accounts. A DC has no local account database, so use the AD cmdlets there.

Active Directory basics

These need the ActiveDirectory module (on a DC, or RSAT on an admin machine).

CommandWhat it does
Get-ADUser bob -Properties LastLogonDate, PasswordLastSet, LockedOutOne user with extra properties
Get-ADUser -Filter 'Enabled -eq $false' -SearchBase 'OU=Lab,DC=contoso,DC=com'Disabled users in an OU
Get-ADUser -Filter "Name -like 'a*'"Wildcard search
Search-ADAccount -LockedOut -UsersOnlyCurrently locked accounts
Unlock-ADAccount -Identity erinUnlock (preview with -WhatIf)
Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 -UsersOnlyNo logon in 90 days, including never logged on
Search-ADAccount -PasswordNeverExpires -UsersOnlyAccounts with non-expiring passwords
Get-ADGroupMember 'Server-Admins' -RecursiveMembers including nested groups
Get-ADPrincipalGroupMembership bobGroups a user belongs to
Get-ADComputer -Filter * -Properties OperatingSystemComputers and their OS
Get-ADDefaultDomainPasswordPolicyLockout threshold and password rules

-Recursive makes a real difference. In our lab, the Server-Admins group contains only the group IT-Admins:

PS> Get-ADGroupMember 'Server-Admins' | Format-Table SamAccountName, objectClass
SamAccountName objectClass
-------------- -----------
IT-Admins      group

PS> Get-ADGroupMember 'Server-Admins' -Recursive | Format-Table SamAccountName, objectClass
SamAccountName objectClass
-------------- -----------
alice          user
bob            user

A filter such as Get-ADUser -Filter 'LastLogonDate -lt $cut' skips accounts that have never logged on, because their LastLogonDate is empty. In our lab that query returned 0 users, while Search-ADAccount -AccountInactive returned 10. Use Search-ADAccount, or check for empty values separately, before you disable stale accounts.

More query patterns are in 25 Get-ADUser examples.

Remoting, output and scheduled tasks

Remoting (syntax checked; needs WinRM enabled on the target and Kerberos or explicit credentials):

Enter-PSSession -ComputerName srv01                 # interactive shell on one server
Invoke-Command -ComputerName srv01, srv02 -ScriptBlock { Get-Service W32Time }
Invoke-Command -ComputerName srv01 -FilePath C:\Scripts\check.ps1 -Credential (Get-Credential)
Test-WSMan -ComputerName srv01                      # is WinRM reachable?

If Test-WSMan fails with “WinRM cannot complete the operation”, WinRM is off or blocked by the firewall on the target. That is what we got from our DC to the client, which is one reason the remoting rows are only syntax-checked. Invoke-Command runs in parallel against many computers (32 at a time by default; change it with -ThrottleLimit).

Shaping and exporting output:

CommandWhat it does
Where-Object Status -eq 'Running'Filter objects
Select-Object Name, Status, StartTypePick columns
Sort-Object Name / Group-Object StatusSort or count by value
Export-Csv C:\Reports\services.csv -NoTypeInformationSave to CSV (the switch matters on 5.1)
Out-GridViewSortable, filterable window (desktop sessions only)

Microsoft’s documentation says Out-GridView does not work on Server Core or Nano Server, because it needs a user interface. In our SSH session it showed nothing at all, so use Export-Csv in scripts and remote sessions.

Scheduled tasks:

Get-ScheduledTask | Where-Object TaskPath -notlike '\Microsoft\*'      # your own tasks
Get-ScheduledTask -TaskName 'Nightly cleanup' | Get-ScheduledTaskInfo  # last run and result

$a = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -File C:\Scripts\cleanup.ps1'
$t = New-ScheduledTaskTrigger -Daily -At 3am
$p = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
Register-ScheduledTask -TaskName 'Nightly cleanup' -Action $a -Trigger $t -Principal $p

We ran the three New-ScheduledTask* lines on the client to check the objects. Register-ScheduledTask has no -WhatIf, so we did not run it. In Get-ScheduledTaskInfo, a LastTaskResult of 0 means success, and 267011 (0x41303) means the task has not run yet.

Official documentation: Get-WinEvent · Get-ADUser · Test-NetConnection · Requirements for remote commands

Related: Get-ADUser PowerShell Examples: 25 Queries for Active Directory · AD Account Lockout Source: Event 4740 Tracing · Locked Out AD Users Report: PowerShell Script with Lockout Source · Windows Firewall Group Policy: 5 Steps to Deploy Secure Rules · Export AD Users to CSV: PowerShell Script with Last Logon

Frequently asked questions

How do I check if a port is open in PowerShell?

Use Test-NetConnection with -Port, for example Test-NetConnection 203.0.113.10 -Port 443. TcpTestSucceeded shows True if the port accepted a connection. Add -InformationLevel Quiet to get only True or False.

What is the PowerShell equivalent of netstat -ano?

Get-NetTCPConnection. Use -State Listen for listening ports and look up the OwningProcess ID with Get-Process -Id to see the program name.

How do I find locked out users in Active Directory?

Run Search-ADAccount -LockedOut -UsersOnly. To find where the lockout came from, query event 4740 in the Security log of the domain controller holding the PDC emulator role.

Why is Get-WinEvent -FilterHashtable faster than Where-Object?

The hashtable filter is applied by the event log service, so only matching events are returned. Where-Object receives every event first and then throws most of them away.

Do these commands work in PowerShell 7?

Most do. The cmdlets here come from Windows modules such as NetTCPIP, NetSecurity, ScheduledTasks and ActiveDirectory, which also load in PowerShell 7 on Windows. Test in your own environment, because a few older modules need the Windows PowerShell compatibility layer.

Free website test

Is your website set up right?

Check SSL, security headers, redirects, robots.txt, sitemap, llms.txt and security.txt in one test. It takes about 30 seconds.