PowerShell one-liners for sysadmins
These are the commands admins paste daily. One rule governs the whole sheet and it is the reason the wording above each command says verified: everything here runs as written in Windows PowerShell 5.1 and PowerShell 7 on Windows. CIM, the registry and the built-in modules cover nearly every row — the two exceptions are marked in the table itself: the Security-log row (logon events) runs elevated with auditing enabled, and the Active Directory row needs the AD module (RSAT) or a domain controller.
Three conventions keep the table short. Drive-type filters (DriveType=3) restrict inventory queries, @{n=...;e={...}} turns raw bytes into readable numbers, and everything that changes a machine shows its -WhatIf first so the destructive commands never surprise you — details below the table.
One-liners by task
| Task | Command | Output hints |
|---|---|---|
| Disk space, rounded GB | Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" | Select-Object DeviceID, @{n="SizeGB";e={[math]::Round($_.Size/1GB,1)}}, @{n="FreeGB";e={[math]::Round($_.FreeSpace/1GB,1)}} | One row per local fixed disk; DriveType=4 for mapped network drives, no filter for everything |
| Largest files under a path | Get-ChildItem -Path C:\ -Recurse -File -ErrorAction SilentlyContinue | Sort-Object Length -Descending | Select-Object -First 10 FullName, @{n="MB";e={[math]::Round($_.Length/1MB)}} | Slow over a full volume; narrow -Path, tune -First. Permission errors are skipped silently |
| Files older than 30 days | Get-ChildItem -Path C:\Users\demo\Downloads -Recurse -File -ErrorAction SilentlyContinue | Where-Object LastWriteTime -lt (Get-Date).AddDays(-30) | Select-Object FullName, LastWriteTime | The age window is the only knob: -lt + AddDays(-30) gets everything untouched for a month; add -First 20 after -ErrorAction to cap output |
| Files changed in the last 24 hours | Get-ChildItem -Path C:\Users\demo\Documents -Recurse -File -ErrorAction SilentlyContinue | Where-Object LastWriteTime -gt (Get-Date).AddHours(-24) | Select-Object FullName, LastWriteTime | Mirror of the age row: -gt with AddHours(-24) means newer than a day; swap in AddDays(-3) for a longer window |
| Folder size in MB | [math]::Round((Get-ChildItem -Path C:\Users\demo\Downloads -Recurse -File -ErrorAction SilentlyContinue | Measure-Object Length -Sum).Sum / 1MB, 1) | One number, no records; Measuring -Sum folds the whole scan into a single pipe object |
| Copy a folder tree | Copy-Item -Path C:\src\web\* -Destination C:\dst\web -Recurse -Force | The wildcard copies the contents of web into the destination folder; without it, Copy-Item names the new folder after the source |
| Zip a folder | Compress-Archive -Path C:\src\web -DestinationPath C:\dst\web-backup.zip -Force | -Force overwrites an existing archive; .zip only — other formats need external tools |
| Unzip an archive | Expand-Archive -Path C:\dst\web-backup.zip -DestinationPath C:\dst\web-restored -Force | Requires the .zip of the compression row; -Force merges into an existing release |
| Running services | Get-Service | Where-Object Status -eq "Running" | Sort-Object Name | Select-Object Name, DisplayName | For a statistical view: Get-Service | Group-Object Status | Select-Object Name, Count |
| Services set to auto-start | Get-Service | Where-Object StartType -eq "Automatic" | Select-Object Name, StartType, Status | StartType shows the configured mode, not the current state |
| Auto services that are not running | Get-Service | Where-Object { $_.StartType -eq "Automatic" -and $_.Status -ne "Running" } | Select-Object Name, DisplayName, Status | The script-block form is required when you compare two properties; this is the 'quietly failed startup' catch-all |
| Change a service startup type | Set-Service -Name Spooler -StartupType Automatic -WhatIf | Admin required; drop -WhatIf to apply. Values: Automatic, AutomaticDelayedStart, Manual, Disabled |
| Top-memory processes | Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 10 Name, Id, @{n="MemMB";e={[math]::Round($_.WorkingSet64/1MB)}} | Swap WorkingSet64 for CPU to sort by processor time |
| Stop a process safely | Stop-Process -Name notepad -WhatIf | -WhatIf shows exactly what would be killed; by PID: Stop-Process -Id 2748 -WhatIf |
| Up network adapters | Get-NetAdapter | Where-Object Status -eq "Up" | Select-Object Name, InterfaceDescription, LinkSpeed, MacAddress | Windows-only module; Get-NetAdapterStatistics gives traffic counters under the same filter |
| IPv4 addresses per adapter | Get-NetIPAddress -AddressFamily IPv4 | Where-Object InterfaceAlias -notlike "*Loopback*" | Select-Object InterfaceAlias, IPAddress, PrefixLength | Use -AddressFamily IPv6 for the v6 side; -notlike keeps the loopback out |
| Flush the DNS cache | Clear-DnsClientCache | The PowerShell twin of ipconfig /flushdns; silent on success |
| Look up a name | Resolve-DnsName example.com | Select-Object Name, Type, IPAddress | Reads the same resolver as nslookup; append -Type MX, -Type TXT for other record types |
| Port reachability test | Test-NetConnection -ComputerName example.com -Port 443 -InformationLevel Detailed | Look for TcpTestSucceeded: True plus Latency; Windows-only in PowerShell 7 |
| Listening ports and their process | Get-NetTCPConnection -State Listen | Select-Object LocalAddress, LocalPort, @{n="Proc";e={(Get-Process -Id $_.OwningProcess).ProcessName}} | The netstat -ano equivalent; -OwningProcess maps the port to its PID |
| Connections to one remote port | Get-NetTCPConnection -RemotePort 443 -ErrorAction SilentlyContinue | Select-Object LocalAddress, LocalPort, RemoteAddress, RemotePort, State | Filtering on the remote side is what shows 'who on this box talks to 443'; no match is empty output, not an error |
| UDP listeners | Get-NetUDPEndpoint | Select-Object LocalAddress, LocalPort, OwningProcess | netstat's UDP lines are text; this is the object view, and Get-NetTCPConnection cannot see UDP at all |
| Quick ping test | Test-Connection -ComputerName srv01 -Count 1 -Quiet | True/False only — the row for scripts; Test-NetConnection adds TCP when you need both |
| Recent errors in the System log | Get-WinEvent -FilterHashtable @{LogName="System"; Level=2,3} -MaxEvents 20 | Select-Object TimeCreated, Id, ProviderName, LevelDisplayName | Level 2 is Error, 3 Warning; widen a single record with Format-List * |
| Errors only, Application log | Get-WinEvent -FilterHashtable @{LogName="Application"; Level=2} -MaxEvents 20 | Select-Object TimeCreated, Id, ProviderName | Level=2 drops the warnings noise; Level=1,2,3 covers critical/error/warning |
| Events since a given time | Get-WinEvent -FilterHashtable @{LogName="System"; StartTime=(Get-Date).AddDays(-1)} -MaxEvents 20 | Select-Object TimeCreated, Id, ProviderName | StartTime is an accepted FilterHashtable key — the 'what broke this morning' query; System log needs no elevation |
| Shutdown and restart history | Get-WinEvent -FilterHashtable @{LogName="System"; Id=1074} -MaxEvents 10 | Select-Object TimeCreated, @{n="Type";e={$_.Properties[4].Value}} | 1074 logs who requested the shutdown; Properties[4] is the event's Type field (restart, shutdown, ...) — use -Credential for remote hosts |
| Logon events | Get-WinEvent -FilterHashtable @{LogName="Security"; Id=4624} -MaxEvents 20 | Select-Object TimeCreated, @{n="User";e={$_.Properties[5].Value}}, @{n="LogonType";e={$_.Properties[8].Value}} | Security reads need elevation and logon auditing enabled; LogonType 10 is RDP (2 interactive, 3 network) |
| Last boot and uptime | Get-CimInstance Win32_OperatingSystem | Select-Object LastBootUpTime, @{n="UpDays";e={[int]((Get-Date)-$_.LastBootUpTime).TotalDays}} | LastBootUpTime is CIM datetime; cast [datetime] where a date comparison needs it |
| Uptime in one line | $up=(Get-Date)-(Get-CimInstance Win32_OperatingSystem).LastBootUpTime; "{0}d {1}h {2}m" -f $up.Days, $up.Hours, $up.Minutes | Same source as the last-boot row, packed into a single short string; the -f format operator is what rounds it |
| Pending reboot check | @(Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending"; Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired") -contains $true | True when either the component-servicing or the Windows Update key marks a restart pending; both are documented checks |
| Logon sessions on this machine | quser | quser.exe runs from PowerShell; page through a terminal server with quser /SERVER:srv01 |
| Local users | Get-LocalUser | Select-Object Name, Enabled, LastLogon, PrincipalSource | Local accounts only — domain users never appear; PrincipalSource says Local vs Active Directory (Windows 10/Server 2016+) |
| Local group members | Get-LocalGroupMember -Group Administrators | Select-Object Name, ObjectClass, PrincipalSource | -Group or -Name name the group; nested groups show ObjectClass Group, members show User |
| Enabled domain users | Get-ADUser -Filter "Enabled -eq $true" -Properties LastLogonDate | Select-Object SamAccountName, LastLogonDate | ActiveDirectory module required (RSAT on clients, or run on a domain controller); LastLogonDate is time-zone converted, LastLogon is not |
| Printers | Get-Printer | Select-Object Name, DriverName, PortName, PrinterStatus | PrinterStatus is the spooler's view of the queue — the quick 'which printer is broken' read |
| Scheduled tasks ready to run | Get-ScheduledTask | Where-Object State -eq "Ready" | Select-Object TaskName, TaskPath, State | Ready is the enabled-and-eligible state; TaskPath is the library folder the task lives in |
| Installed hotfixes | Get-HotFix -ErrorAction SilentlyContinue | Sort-Object InstalledOn -Descending | Select-Object HotFixID, Description, InstalledOn | Windows Update / WU history patches; stream it off a remote box with -ComputerName srv01 |
| Installed software | Get-ItemProperty "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*","HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" | Where-Object DisplayName | Select-Object DisplayName, DisplayVersion, Publisher | Sort-Object DisplayName | Full walkthrough in /guides/powershell-list-installed-software/ |
| Export any listing to CSV | Get-Service | Where-Object Status -eq "Running" | Export-Csv -NoTypeInformation -Path .\running-services.csv | Pipe from the start of any row here; -NoTypeInformation keeps 5.1 files clean |
Running commands safely
Stop-Process -Name notepad -WhatIf
Remove-Item -Path C:\Users\demo\AppData\Local\Temp\* -Recurse -WhatIf
Set-Service -Name Spooler -StartupType Disabled -WhatIf
Restart-Computer -WhatIf
The two safety levers in PowerShell terms
- -WhatIf
- prints what the command would do and does nothing — supported by Stop-Process, Remove-Item, Set-Service, Restart-Computer and most modifying cmdlets
- -Confirm / $ConfirmPreference
- asks before acting; pipe Get-Command to a filter over the Parameters dictionary to list which cmdlets of a module support -WhatIf
- ValidateSet
- restricts a parameter's accepted values before anything runs — Set-Service -StartupType rejects anything outside Automatic, AutomaticDelayedStart, Manual, Disabled
- Read-only rule
- inventory cmdlets (Get-*) never change the machine: Get-CimInstance, Get-Service, Get-Process, Get-WinEvent and the Get-Net* family are safe to run anywhere
Set-Service, Stop-Process, Remove-Item — need an elevated prompt, and so do Stop-Process -Force on other users' processes. Test on a lab box when the target is a fleet: -WhatIf proves the pipeline, and -Confirm protects the first run. For one pattern across many machines, wrap the row in Invoke-Command -ComputerName srv01, srv02 -ScriptBlock { ... }.Notes on the rows
When a row needs more than one read
Get-CimInstanceis the current-world cmdlet — use it over the retiredGet-WmiObject; syntax and output are identical in 5.1 and 7.Test-NetConnection,Get-NetAdapter,Get-NetIPAddress,Get-NetTCPConnectioncome from Windows-native modules and do not exist under PowerShell 7 on Linux.- The logon row reads the
Securitylog, which is a built-in, non-elevated-visible log: an elevated prompt and enabled Logon auditing are both required, and a machine without such events returns no matches instead of an error. The reboot-history row (ID 1074) stays in theSystemlog, where an ordinary prompt can read it. - The Active Directory row needs the
ActiveDirectorymodule — RSAT on a workstation, or a domain controller. TheLocalAccountsrows (Get-LocalUser,Get-LocalGroupMember) are in-box but Windows-only, and not available in 32-bit PowerShell on a 64-bit machine. - Pending-reboot detection has no current WMI class (
Win32_RebootPendingis not real). The practical check is the Component Based Servicing key:Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending', plus the files-rename key underCurrentVersion\WindowsUpdate\Auto Update.
FAQ
How do I test a command without running it?
Add -WhatIf. It works on Stop-Process, Remove-Item, Set-Service, Restart-Computer and most cmdlets that modify the machine — the output tells you exactly what would have happened. For parameter validation, ValidateSet attributes catch bad values before anything runs: Set-Service -StartupType rejects any string outside Automatic, AutomaticDelayedStart, Manual and Disabled. The safe habit: two dashes before the first real run (-WhatIf, then -Confirm).
Do these one-liners require administrator rights?
Only the write rows. Get-CimInstance, Get-Service, Get-Process, Get-WinEvent, Get-NetAdapter, Get-NetIPAddress, Clear-DnsClientCache, Test-NetConnection and Export-Csv all run from a normal prompt. Set-Service, Stop-Process -Force on other users' processes, Remove-Item of system paths and the DISM-style cleanup need elevation.
Can I run the same commands against many computers at once?
Yes, with Invoke-Command when WinRM is reachable: Invoke-Command -ComputerName srv01, srv02 -ScriptBlock { Get-Service | Where-Object Status -eq 'Running' }. The -ComputerName parameter of Get-WinEvent also works for event logs without PowerShell remoting, and Get-WinEvent with a plain CIM or registry query goes through the same CIM wiring.
Why is Get-CimInstance used and not Get-WmiObject?
Get-WmiObject is the legacy WMI wrapper: retained in 5.1, not available in PowerShell 7. Get-CimInstance uses CIM (WS-Man) and works identically in 5.1 and 7, which is why every inventory command in this sheet uses it. For the same classes (Win32_LogicalDisk, Win32_OperatingSystem, Win32_Service) the output is the same; the console format differs slightly.
Related tools
- IPv4 subnet calculator — break any CIDR block into network, range, broadcast and usable hosts.
- IP range to CIDR — turn an arbitrary address range into its minimal covering CIDR blocks.
- VLSM calculator — split a block into right-sized subnets by host requirements.