Windows Run Commands

Everything launchable from Win + R, Command Prompt, or PowerShell. Also work from Task Manager → Run new task (check "with administrative privileges" for elevated).

System & Diagnostics

CommandOpensWhy you care
msconfigSystem ConfigurationBoot options, Safe Boot toggle, selective startup for troubleshooting
msinfo32System InformationFull hardware/driver/BIOS inventory — export with File → Export for tickets
dxdiagDirectX DiagnosticsGPU, driver versions, display info; Save All Information for vendor support
resmonResource MonitorPer-process disk/network/memory — find what's hammering the disk
perfmonPerformance MonitorCounters + Data Collector Sets for long-running perf baselines
taskmgrTask ManagerStartup tab, service PIDs (match with netstat -ano)
eventvwr.mscEvent ViewerSystem/Application logs; filter by Event ID (6008 = unexpected shutdown, 41 = kernel-power)
winverAbout WindowsExact build number for compatibility/patching questions
cleanmgrDisk Cleanupcleanmgr /sageset:1 then /sagerun:1 for scripted cleanup
mrtMalicious Software Removal ToolQuick built-in malware scan
sigverifFile Signature VerificationFind unsigned drivers
mdschedWindows Memory DiagnosticRAM test on next boot — results in Event Viewer (MemoryDiagnostics-Results)

Management Consoles (.msc)

CommandOpensWhy you care
compmgmt.mscComputer ManagementOne-stop: events, shares, users, disks, services
services.mscServicesStartup type, recovery actions, Log On As accounts
devmgmt.mscDevice ManagerDriver rollback, hidden devices (View → Show hidden)
diskmgmt.mscDisk ManagementPartitions, drive letters, extend/shrink volumes
taskschd.mscTask SchedulerPersistence checks during IR — always inspect \Microsoft\Windows too
gpedit.mscLocal Group PolicyLocal policy on Pro+ (not Home)
secpol.mscLocal Security PolicyPassword/lockout/audit policy, user rights assignment
lusrmgr.mscLocal Users & GroupsLocal admin audit (not on Home)
certlm.mscCertificates — Local MachineMachine cert store (use certmgr.msc for current user)
wf.mscWindows Defender Firewall (Advanced)Inbound/outbound rules, logging, connection security
fsmgmt.mscShared FoldersOpen files and sessions on a file server
printmanagement.mscPrint ManagementDrivers, ports, deployed printers
wmimgmt.mscWMI ControlRepair WMI namespace security
rsop.mscResultant Set of PolicyWhat GPOs actually applied (or gpresult /h out.html)

Server / Domain Consoles (RSAT or on the server)

CommandOpens
dsa.mscActive Directory Users & Computers
dssite.mscAD Sites & Services
domain.mscAD Domains & Trusts
gpmc.mscGroup Policy Management
dnsmgmt.mscDNS Manager
dhcpmgmt.mscDHCP Manager
adsiedit.mscADSI Edit — raw AD attribute editing, be careful

Control Panel Applets (.cpl)

CommandOpensWhy you care
ncpa.cplNetwork ConnectionsFastest path to NIC properties / static IP
appwiz.cplPrograms & FeaturesUninstall list; optionalfeatures for Windows Features
sysdm.cplSystem PropertiesRename PC, domain join, remote settings, page file (Advanced)
firewall.cplFirewall (basic)Quick profile status; use wf.msc for rules
inetcpl.cplInternet OptionsProxy settings (Connections → LAN settings), cert trust
powercfg.cplPower OptionsAlso see powercfg /batteryreport and powercfg /energy
timedate.cplDate & TimeKerberos breaks past 5 min skew — check this first on auth errors
main.cplMouse
mmsys.cplSoundDefault devices, per-app troubleshooting
desk.cplDisplay Settings
intl.cplRegion

Quick Actions & Shell Shortcuts

CommandDoes
mstscRemote Desktop — mstsc /v:server01 /admin for console session
netplwizUser Accounts dialog (auto-login checkbox lives here)
regeditRegistry Editor — export keys before editing
shell:startupCurrent user Startup folder
shell:common startupAll-users Startup folder
%temp%User temp folder — safe to purge contents
\\server\shareOpen UNC path directly
osk / magnify / charmapOn-screen keyboard / Magnifier / Character Map
control userpasswords2Same as netplwiz
ms-settings:windowsupdateJump straight to a Settings page (ms-settings: URIs)

Tip: Ctrl+Shift+Enter in the Run box or Start search launches elevated.

DISM / SFC / System Repair

The exact repair sequence, offline variants, and where the logs live. All commands need an elevated prompt.

The Standard Repair Order (memorize this)

DISM repairs the component store that SFC pulls from — so if the store is corrupt, SFC alone will fail. Run DISM first, then SFC, then reboot.

:: 1. Quick check — reads flags only, seconds
DISM /Online /Cleanup-Image /CheckHealth

:: 2. Deeper scan — checks store for corruption, no repair (few minutes)
DISM /Online /Cleanup-Image /ScanHealth

:: 3. Repair — pulls known-good files from Windows Update (10-30 min)
DISM /Online /Cleanup-Image /RestoreHealth

:: 4. Now repair protected system files from the (now healthy) store
sfc /scannow

:: 5. Reboot, then re-run sfc /scannow to confirm clean

Don't panic if RestoreHealth sits at 62.3% for a long time — that's normal.

RestoreHealth Without Internet / WSUS-Blocked

Point DISM at a known-good install.wim from matching-build ISO media (mounted as X: here).

:: Find the right index in the WIM first
DISM /Get-WimInfo /WimFile:X:\sources\install.wim

:: Repair using index 1, blocking Windows Update as a fallback source
DISM /Online /Cleanup-Image /RestoreHealth /Source:WIM:X:\sources\install.wim:1 /LimitAccess

If the ISO has install.esd instead: /Source:ESD:X:\sources\install.esd:1. Build must match the installed OS (check winver).

Offline Repair (from WinRE / boot media)

:: From Recovery command prompt — target the offline Windows install (often D: in WinRE, verify with dir)
DISM /Image:D:\ /Cleanup-Image /RestoreHealth /Source:WIM:X:\sources\install.wim:1 /LimitAccess

sfc /scannow /offbootdir=D:\ /offwindir=D:\Windows

Component Store Cleanup (reclaim disk on servers)

:: See if cleanup is worthwhile
DISM /Online /Cleanup-Image /AnalyzeComponentStore

:: Remove superseded updates
DISM /Online /Cleanup-Image /StartComponentCleanup

:: Aggressive: also removes uninstall ability for current updates
DISM /Online /Cleanup-Image /StartComponentCleanup /ResetBase

/ResetBase means you can never uninstall currently-installed updates. Fine on stable servers, think twice right after Patch Tuesday.

Disk & Boot Repair

:: File system check — /f fixes errors, /r also scans for bad sectors (slow)
chkdsk C: /f /r

:: Boot repair from WinRE
bootrec /fixmbr
bootrec /fixboot
bootrec /scanos
bootrec /rebuildbcd

:: Modern UEFI BCD rebuild (S = system/EFI partition letter after mounting)
bcdboot C:\Windows /s S: /f UEFI

Where the Logs Are

LogPath
SFC / CBS%windir%\Logs\CBS\CBS.log — search for "[SR]" lines
DISM%windir%\Logs\DISM\dism.log
Setup / upgradeC:\$WINDOWS.~BT\Sources\Panther\setupact.log
Windows UpdatePowerShell: Get-WindowsUpdateLog (builds a readable log on the desktop)
:: Pull just the SFC results out of CBS.log
findstr /c:"[SR]" %windir%\Logs\CBS\CBS.log > "%userprofile%\Desktop\sfcdetails.txt"

Other Repair Tools Worth Remembering

:: Reset Windows Update components (services + rename SoftwareDistribution)
net stop wuauserv & net stop bits & net stop cryptsvc
ren %systemroot%\SoftwareDistribution SoftwareDistribution.old
ren %systemroot%\System32\catroot2 catroot2.old
net start cryptsvc & net start bits & net start wuauserv

:: In-place upgrade repair: mount matching ISO, run setup.exe, keep files+apps.
:: Fixes what DISM/SFC can't, without wiping the machine.

Diskpart / Storage

Diskpart is interactive and unforgiving — it does not ask "are you sure." Always list and select before any destructive verb, and confirm the disk number every single time. All commands need an elevated prompt.

The Golden Rule

Diskpart acts on whatever is "selected." If you select the wrong disk, clean wipes it with zero confirmation and no recycle bin. The #1 cause of accidental data loss with diskpart is running clean against the system disk or a plugged-in backup drive. Verify the size and label in list disk / detail disk before touching anything.

Inspect First (always)

diskpart                     :: enters the diskpart> prompt
list disk                    :: all physical disks + sizes — identify target by SIZE
select disk 1                :: nothing works until something is selected
detail disk                  :: model, volumes on it — CONFIRM this is the right one
list partition               :: partitions on selected disk
list volume                  :: all volumes + drive letters + filesystem across all disks
select volume 3
detail volume
exit                         :: leave diskpart

Wipe & Repartition a Disk (e.g. prep a USB or reused drive)

diskpart
list disk
select disk 2                :: ← TRIPLE CHECK. This is about to be erased.
detail disk                  :: confirm size/model matches the drive you intend

clean                        :: removes all partitions/formatting (fast)
:: clean all  ← zeros the ENTIRE disk, hours on big drives, for secure wipe/decommission

convert gpt                  :: or 'convert mbr' for legacy/BIOS boot
create partition primary
format fs=ntfs quick label="DATA"    :: drop 'quick' for a full format (slow, bad-sector scan)
assign letter=E
exit

clean all is the secure-erase option and can run for hours on a large HDD. Use it for decommissioning; use plain clean for a quick repartition.

Make a Bootable USB (Windows install media, manually)

diskpart
list disk
select disk 2                :: the USB stick — verify by size (e.g. 32 GB)
clean
create partition primary
select partition 1
active                       :: MBR only; skip for pure-UEFI GPT media
format fs=fat32 quick        :: FAT32 for UEFI boot (files must be <4GB)
:: For install.wim >4GB use fs=ntfs, or split the wim with dism /Split-Image
assign
exit

Fix / Assign Drive Letters

diskpart
list volume
select volume 4              :: the volume missing a letter
assign letter=F
:: remove a letter (hide a volume):  remove letter=F
exit

If a whole disk shows "offline" in Disk Management: select disk N then online disk, and clear read-only with attributes disk clear readonly.

Extend / Shrink Volumes

diskpart
list volume
select volume 2
extend                       :: grow into adjacent unallocated space (all of it)
extend size=10240            :: grow by exactly 10 GB (MB units)
shrink desired=20480         :: free up ~20 GB of unallocated space
exit

GUI equivalent lives in diskmgmt.msc — right-click the volume → Extend/Shrink. Diskpart wins for scripting or when the GUI greys the option out.

Clear the "Read-Only" / Write-Protected Attribute

:: Classic fix for "The disk is write-protected" on USB drives
diskpart
list disk
select disk 2
attributes disk clear readonly
:: per-volume version: select volume N → attributes volume clear readonly
exit

Scripted Diskpart (for RMM / automation)

:: Put commands in a text file, then run non-interactively:
:: diskpart /s C:\scripts\prep-disk.txt

:: prep-disk.txt contents:
select disk 2
clean
convert gpt
create partition primary
format fs=ntfs quick label=DATA
assign letter=E

A hardcoded select disk N in a script is dangerous — disk numbers change based on what's plugged in. For anything repeatable, prefer PowerShell Storage cmdlets below, which can filter by size/serial/bus type.

PowerShell Storage Cmdlets (the modern, safer way) PS

Get-Disk
Get-Partition -DiskNumber 1
Get-Volume                              # filesystem, size, health, drive letter
Get-PhysicalDisk | Select-Object DeviceId, FriendlyName, MediaType, HealthStatus

# Full clean + provision, filterable (safer target selection than a bare number)
Get-Disk 2 | Clear-Disk -RemoveData -Confirm:$false
Initialize-Disk -Number 2 -PartitionStyle GPT
New-Partition -DiskNumber 2 -UseMaximumSize -AssignDriveLetter |
  Format-Volume -FileSystem NTFS -NewFileSystemLabel 'DATA' -Confirm:$false

# Resize
Resize-Partition -DriveLetter E -Size 200GB
Get-PartitionSupportedSize -DriveLetter E   # min/max it can be resized to

# SMART / health quick check
Get-PhysicalDisk | Get-StorageReliabilityCounter |
  Select-Object DeviceId, Wear, ReadErrorsTotal, Temperature

Other Storage Tools

CommandDoes
chkdsk C: /f /rFix filesystem errors + scan bad sectors (schedules on reboot for the system drive)
defrag C: /OOptimize — auto-TRIMs SSDs, defrags HDDs
fsutil volume diskfree C:Free space, scriptable
fsutil dirty query C:Is the volume flagged dirty (needs chkdsk)?
manage-bde -statusBitLocker state per drive
manage-bde -unlock E: -pwUnlock an encrypted drive with password
vssadmin list shadowsList Volume Shadow Copies (restore points / backup snapshots)
wbadmin get versionsWindows Server Backup catalog
mountvolMount points and volume GUIDs (find the EFI partition: mountvol S: /s)

Admin Toolbox

The grab-bag of native Windows commands that don't fit neatly elsewhere but you reach for constantly — process management, tasks, drivers, activation, files.

Processes & Services (CMD-side)

tasklist                         :: all processes + PIDs + memory
tasklist /svc                    :: which services run in each PID (svchost breakdown)
tasklist /fi "memusage gt 500000"  :: processes using >500 MB
taskkill /im chrome.exe /f       :: kill by name, forcefully
taskkill /pid 4820 /f /t         :: kill PID + its child processes (/t = tree)

sc query wuauserv                :: service state
sc queryex type=service state=all   :: everything, with PIDs
sc config Spooler start=disabled :: change startup type (disabled/demand/auto/delayed-auto)
sc stop Spooler & sc start Spooler
sc qc Spooler                    :: config: binary path, dependencies, log-on account
sc failure Spooler reset=86400 actions=restart/60000/restart/60000/run/1000  :: recovery actions

Scheduled Tasks (CLI)

schtasks /query /fo table /v          :: all tasks, verbose (IR persistence sweep)
schtasks /query /tn "\Microsoft\Windows\Defrag\ScheduledDefrag"  :: one task
schtasks /run /tn "TaskName"          :: run now
schtasks /end /tn "TaskName"

:: Create a daily 3 AM task running a script as SYSTEM
schtasks /create /tn "Nightly Cleanup" /tr "powershell -File C:\scripts\cleanup.ps1" ^
  /sc daily /st 03:00 /ru SYSTEM /rl highest

schtasks /delete /tn "TaskName" /f
# PowerShell equivalent — richer, use for anything scripted
Get-ScheduledTask | Where-Object State -eq 'Running'
Get-ScheduledTask -TaskName '*update*' | Get-ScheduledTaskInfo   # last/next run + result

Drivers

driverquery /v /fo table         :: all installed drivers, verbose
driverquery /si                  :: signed status

pnputil /enum-drivers            :: enumerate third-party driver packages in the store
pnputil /add-driver C:\drivers\net.inf /install   :: stage + install a driver
pnputil /delete-driver oem12.inf /uninstall /force :: remove a bad driver package

:: DISM driver ops (also work on offline images with /Image:)
DISM /Online /Get-Drivers /Format:Table
DISM /Online /Add-Driver /Driver:C:\drivers /Recurse

Windows Activation & Licensing

slmgr /dlv                       :: detailed license state (channel, activation ID)
slmgr /xpr                       :: is it activated + expiry
slmgr /ipk XXXXX-XXXXX-XXXXX-XXXXX-XXXXX   :: install a product key
slmgr /ato                       :: activate now (online)
slmgr /skms kms.corp.local & slmgr /ato    :: point to a KMS host then activate
slmgr /cpky                      :: clear key from registry (after activation, for hygiene)

:: OEM key baked into firmware
wmic path softwarelicensingservice get OA3xOriginalProductKey
:: (PowerShell) (Get-CimInstance SoftwareLicensingService).OA3xOriginalProductKey

File Operations Worth Knowing

where python                     :: like Linux 'which' — where's this exe on PATH
fc file1.txt file2.txt           :: compare two files
takeown /f C:\path /r /d y       :: take ownership recursively (locked/orphaned files)
icacls C:\path                   :: view NTFS permissions
icacls C:\path /grant Admins:F /t :: grant full control recursively
icacls C:\path /reset /t         :: reset perms to inherited
mklink /d C:\link C:\real\target :: directory symlink (/j = junction, /h = hardlink)
attrib -r -h -s file             :: clear read-only/hidden/system flags
xcopy /e /i /h /k src dst        :: legacy recursive copy (robocopy is better — see PowerShell page)
compact /c /s:C:\logs            :: NTFS compress a folder tree

System Control

shutdown /r /t 0                 :: reboot now
shutdown /s /t 60 /c "Patching"  :: shutdown in 60s with message
shutdown /a                      :: abort a pending shutdown
shutdown /r /o /t 0              :: reboot into Advanced Startup (WinRE)
shutdown /r /m \\PC01 /t 0       :: reboot a remote machine
shutdown /g /t 0                 :: reboot + reopen registered apps

systeminfo                       :: full system report (also shows hotfixes, boot time, RAM)
systeminfo | findstr /c:"System Boot Time"
gpupdate /force && gpresult /r   :: reapply policy and confirm
wmic bios get serialnumber       :: service tag / serial for warranty lookups
:: (PowerShell) Get-CimInstance Win32_BIOS | Select SerialNumber

Clipboard, Env, Misc

ipconfig /all | clip             :: pipe any output straight to clipboard
type file.txt | clip
echo %PATH%                      :: view an env var (CMD)
setx TOOLS "C:\tools" /m         :: set a PERSISTENT system env var (/m = machine-wide)
set                              :: list all env vars (current session)
assoc .log                       :: file-type association
ftype txtfile                    :: what program opens that type
color 0a                         :: green-on-black console, because why not

setx sets persistent vars but does NOT affect the current window — open a new prompt to see them. Plain set is session-only.

PowerShell Essentials

The commands you reach for daily, plus the discovery trio that makes everything else findable.

The Discovery Trio — learn anything from inside the shell

# What command does X?
Get-Command *service*
Get-Command -Module ExchangeOnlineManagement

# How do I use it? (-Online opens the web docs)
Get-Help Get-Service -Examples
Get-Help Get-Service -Online

# What properties/methods does this object actually have?
Get-Service | Get-Member

Get-Member is the answer to "why doesn't my Select-Object show anything" 90% of the time — you guessed a property name that doesn't exist.

Pipeline Fundamentals

# Filter left, format right. Where-Object filters, Select-Object shapes.
Get-Service | Where-Object Status -eq 'Running' | Select-Object Name, StartType

# Sort and take top N (find disk hogs)
Get-ChildItem C:\ -Recurse -ErrorAction SilentlyContinue |
  Sort-Object Length -Descending | Select-Object -First 20 FullName, @{n='MB';e={[math]::Round($_.Length/1MB,1)}}

# ForEach-Object for per-item actions
Get-Content .\servers.txt | ForEach-Object { Test-Connection $_ -Count 1 -Quiet }

# Export anything to CSV for tickets/reports
Get-Process | Sort-Object CPU -Descending | Select-Object -First 15 |
  Export-Csv C:\temp\top-cpu.csv -NoTypeInformation

Execution Policy & Running Scripts

# Sensible default for your own machine (local scripts run, downloaded need signing)
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser

# One-off bypass without changing policy (great for RMM deployments)
powershell.exe -ExecutionPolicy Bypass -File .\deploy.ps1

# Unblock a downloaded script (removes Zone.Identifier ADS)
Unblock-File .\script.ps1

Execution policy is a safety belt, not a security boundary — it stops accidents, not attackers.

System Info & Health One-Liners

# Last boot time (was it really rebooted?)
(Get-CimInstance Win32_OperatingSystem).LastBootUpTime

# OS, build, architecture
Get-ComputerInfo | Select-Object OsName, OsVersion, OsBuildNumber, CsSystemType

# Installed hotfixes, newest first
Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 10

# Free disk space, all drives
Get-CimInstance Win32_LogicalDisk -Filter "DriveType=3" |
  Select-Object DeviceID, @{n='FreeGB';e={[math]::Round($_.FreeSpace/1GB,1)}}, @{n='TotalGB';e={[math]::Round($_.Size/1GB,1)}}

# Recent unexpected shutdowns / kernel-power events
Get-WinEvent -FilterHashtable @{LogName='System'; Id=6008,41} -MaxEvents 10

# Pending reboot check (common keys)
Test-Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\RebootRequired'

Services, Processes, Local Accounts

Get-Service Spooler | Restart-Service -Verbose
Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 10
Stop-Process -Name notepad -Force

# Local admin audit — who's in the Administrators group?
Get-LocalGroupMember -Group 'Administrators'

# Create local admin (printer/kiosk/break-glass scenarios)
$p = Read-Host -AsSecureString 'Password'
New-LocalUser 'la-support' -Password $p -PasswordNeverExpires
Add-LocalGroupMember -Group 'Administrators' -Member 'la-support'

Remoting

# Enable on the target (WinRM, port 5985/5986)
Enable-PSRemoting -Force

# Interactive session
Enter-PSSession -ComputerName SERVER01

# Run against many machines at once
Invoke-Command -ComputerName SRV01,SRV02 -ScriptBlock { Get-Service Spooler }

# Copy a file over the remoting channel (no SMB needed)
$s = New-PSSession SERVER01
Copy-Item .\tool.exe -Destination C:\temp\ -ToSession $s

Modules, Profile, Logging

Install-Module ExchangeOnlineManagement -Scope CurrentUser
Get-Module -ListAvailable
Update-Module

# Your profile script — aliases/functions that load every session
notepad $PROFILE

# Record everything in a session (great for change records)
Start-Transcript C:\temp\session.log
Stop-Transcript

Strings, Files, Web

# grep for Windows
Select-String -Path C:\logs\*.log -Pattern 'error' -Context 1,2

# tail -f equivalent
Get-Content C:\logs\app.log -Tail 20 -Wait

# REST calls (auto-parses JSON into objects)
Invoke-RestMethod https://api.github.com/repos/PowerShell/PowerShell/releases/latest |
  Select-Object tag_name, published_at

# Download a file
Invoke-WebRequest -Uri $url -OutFile C:\temp\installer.msi

# Robocopy — the real file-move workhorse (mirror, retry once, log)
robocopy \\old\share \\new\share /MIR /R:1 /W:1 /LOG:C:\temp\move.log /TEE

/MIR deletes files at the destination that don't exist at the source. Triple-check direction before running.

Networking CLI

Windows-focused with PowerShell equivalents. Ordered roughly by how a connectivity troubleshoot actually flows: local config → DNS → path → sockets.

ARP Cache cmd

:: Show the full ARP cache (IP-to-MAC mappings this host has learned)
arp -a

:: Show cache for one interface only (-N takes the INTERFACE's IP)
arp -a -N 192.168.1.50

:: Delete entire cache (forces re-resolution — needs admin)
arp -d *

:: Delete one entry / add a static entry
arp -d 192.168.1.1
arp -s 192.168.1.1 00-1a-2b-3c-4d-5e
# PowerShell equivalent — filterable objects
Get-NetNeighbor -AddressFamily IPv4 | Where-Object State -ne 'Unreachable'
Remove-NetNeighbor -InterfaceIndex 12 -Confirm:$false

Duplicate MACs across different IPs, or the gateway's MAC suddenly changing, are classic ARP-spoofing/MITM indicators — worth knowing for both IR and your CCNA.

IP Configuration & DNS Client

ipconfig /all            :: full config: DHCP server, lease, DNS servers, MAC
ipconfig /release        :: drop DHCP lease
ipconfig /renew          :: request new lease
ipconfig /flushdns       :: clear DNS resolver cache
ipconfig /displaydns     :: view cached DNS records
ipconfig /registerdns    :: re-register A/PTR with DNS (fixes stale AD DNS records)
# PowerShell equivalents
Get-NetIPConfiguration -Detailed
Get-NetAdapter | Where-Object Status -eq 'Up'
Get-DnsClientCache
Clear-DnsClientCache
Get-DnsClientServerAddress

DNS Lookups

nslookup contoso.com                    :: A record via default DNS
nslookup contoso.com 8.8.8.8            :: query a specific server (isolates "is it MY dns?")
nslookup -type=mx contoso.com           :: mail routing
nslookup -type=txt contoso.com          :: SPF and verification records
nslookup -type=srv _ldap._tcp.corp.local  :: find domain controllers
nslookup 8.8.8.8                        :: reverse (PTR) lookup
# PowerShell — richer output, scriptable
Resolve-DnsName contoso.com -Type MX
Resolve-DnsName contoso.com -Server 1.1.1.1 -DnsOnly

Path & Reachability

ping -t 192.168.1.1          :: continuous (Ctrl+C to stop, Ctrl+Break for stats)
ping -l 1472 -f 8.8.8.8      :: MTU test: 1472 + 28 header = 1500; -f = don't fragment
ping -4 host / ping -6 host  :: force IPv4 / IPv6
tracert 8.8.8.8              :: hop-by-hop path
pathping 8.8.8.8             :: tracert + per-hop loss stats over time (better for "it's slow")
# The single most useful connectivity test in PowerShell — TCP port check
Test-NetConnection mail.contoso.com -Port 443
Test-NetConnection 10.0.0.5 -Port 3389 -InformationLevel Detailed
Test-NetConnection 8.8.8.8 -TraceRoute

Sockets & Listening Ports

netstat -ano                     :: all connections + listening, numeric, with PID
netstat -ano | findstr :443      :: who's using 443?
netstat -anob                    :: include process NAME (needs admin)
tasklist | findstr <PID>         :: map PID from netstat to a process
# PowerShell — join connections to process names in one shot
Get-NetTCPConnection -State Listen |
  Select-Object LocalAddress, LocalPort, @{n='Process';e={(Get-Process -Id $_.OwningProcess).Name}} |
  Sort-Object LocalPort

Routing Table

route print                                          :: full table (0.0.0.0 = default route)
route print -4                                       :: IPv4 only
route add 10.50.0.0 mask 255.255.0.0 192.168.1.254   :: temporary route (gone after reboot)
route add 10.50.0.0 mask 255.255.0.0 192.168.1.254 -p  :: -p = persistent
route delete 10.50.0.0
Get-NetRoute -AddressFamily IPv4 | Sort-Object DestinationPrefix
New-NetRoute -DestinationPrefix '10.50.0.0/16' -NextHop 192.168.1.254 -InterfaceIndex 12

netsh Grab Bag

:: The classic stack-reset pair for "internet is broken" (reboot after)
netsh int ip reset
netsh winsock reset

:: Saved Wi-Fi networks + reveal a stored password (admin)
netsh wlan show profiles
netsh wlan show profile name="OfficeWiFi" key=clear

:: Firewall profile state on/off (troubleshooting only — turn it back on)
netsh advfirewall show allprofiles
netsh advfirewall set allprofiles state off

:: Interface config without the GUI
netsh interface ip show config
netsh interface ip set address "Ethernet" static 192.168.1.50 255.255.255.0 192.168.1.1
netsh interface ip set address "Ethernet" dhcp

:: Port forward on a Windows box (listen 8080 → forward to 80 on another host)
netsh interface portproxy add v4tov4 listenport=8080 connectaddress=10.0.0.5 connectport=80
netsh interface portproxy show all

portproxy entries persist across reboots and are a known persistence trick — check netsh interface portproxy show all during IR.

Misc Worth Keeping

getmac /v                                  :: MAC addresses with adapter names
nbtstat -A 192.168.1.20                    :: NetBIOS name from an IP
net use Z: \\server\share /persistent:yes  :: map a drive
net use * /delete                          :: kill all mapped drives/SMB sessions
net session                                :: who's connected to THIS machine over SMB (admin)
klist purge                                :: flush Kerberos tickets (fixes group-membership lag)
w32tm /query /status                       :: time sync source and offset
w32tm /resync                              :: force time sync

Port Reference

The ones that show up in firewall rules, CCNA questions, and 2 AM incident calls.

Core Infrastructure

PortProtoServiceNotes
20/21TCPFTP data / controlCleartext — should be dead; use SFTP
22TCPSSH / SFTP / SCP
23TCPTelnetCleartext — finding it open is a finding
25TCPSMTP (server-to-server)ISPs often block outbound from clients
53TCP/UDPDNSUDP for queries, TCP for zone transfers & large responses
67/68UDPDHCP server / client
80TCPHTTP
110TCPPOP3995 = POP3S
123UDPNTPKerberos dies without it
143TCPIMAP993 = IMAPS
161/162UDPSNMP / SNMP trapsv3 or don't
443TCPHTTPSAlso QUIC/HTTP3 on UDP 443
465/587TCPSMTP submission (implicit TLS / STARTTLS)587 is the standard client submission port
514UDPSyslog6514 for TLS syslog
500/4500UDPIPsec IKE / NAT-TSite-to-site VPN staples
1194UDPOpenVPN
51820UDPWireGuard (default)

Windows / AD Environment

PortProtoServiceNotes
88TCP/UDPKerberos
135TCPRPC endpoint mapperPlus dynamic 49152–65535 for RPC itself
137–139TCP/UDPNetBIOSLegacy; disable where possible
389TCP/UDPLDAP636 = LDAPS
445TCPSMBNever expose to the internet. Ever.
3268/3269TCPGlobal Catalog / GC over SSL
3389TCP/UDPRDPVPN or gateway in front, always
5985/5986TCPWinRM HTTP / HTTPSPowerShell remoting
9100TCPRaw printing (JetDirect)Your printer deployment scripts' best friend

Databases & Apps

PortService
1433Microsoft SQL Server
3306MySQL / MariaDB
5432PostgreSQL
6379Redis
27017MongoDB
8080 / 8443Alt HTTP/HTTPS (proxies, Tomcat, admin UIs)
5060/5061SIP / SIP-TLS (VoIP)
8006Proxmox VE web UI

Event IDs & Incident Response

The Windows Event IDs that actually matter during triage and IR, plus the first-hour live-response commands. Security log events require an elevated context and appropriate audit policy enabled.

Authentication & Account Events (Security log)

IDMeaningWatch for
4624Successful logonLogon Type: 2=console, 3=network, 4=batch, 5=service, 7=unlock, 8=cleartext, 9=RunAs, 10=RDP, 11=cached
4625Failed logonSpikes = brute force / password spray. Sub-status codes tell you why (0xC000006A=bad pw, 0xC0000064=no such user)
4634 / 4647Logoff / user-initiated logoffSession duration correlation
4648Logon using explicit credentialsRunAs / lateral movement with alternate creds
4672Admin/special privileges assigned at logonWho's getting SeDebug, SeBackup, etc. — high-value account use
4720 / 4726User account created / deletedAttacker persistence via new accounts
4728 / 4732 / 4756Member added to security-enabled groupPrivilege escalation — esp. Domain Admins / Enterprise Admins
4740Account locked outLogged on the PDC emulator — names the source computer
4768 / 4769Kerberos TGT / service ticket requested4769 with weak encryption = Kerberoasting indicator
4771Kerberos pre-auth failedAS-REP / password guessing against AD

Execution, Persistence & Tampering

IDLogMeaning
4688SecurityProcess created (enable cmdline auditing to capture args — huge for hunting)
4697SecurityService installed — classic PsExec / malware persistence
7045SystemNew service installed (System-log counterpart to 4697)
4698 / 4702SecurityScheduled task created / updated
1102SecurityAudit log cleared — attackers covering tracks. Alert on this always.
104SystemEvent log cleared (System log)
4104PS/OperationalPowerShell script block logging — deobfuscated code the attacker ran
400 / 600Windows PowerShellEngine start / provider start — PS execution evidence
1116 / 1117Defender/OperationalMalware detected / action taken
4719SecuritySystem audit policy changed — someone disabling logging

Stability & Boot (System log)

IDMeaning
41Kernel-Power — system rebooted without clean shutdown (crash, power loss, hard hang)
6008Previous shutdown was unexpected
1074Clean shutdown/restart initiated — names the process/user that triggered it
6005 / 6006Event log service started / stopped = boot / shutdown markers
7000 / 7001Service failed to start / dependency failed
7034 / 7031Service crashed unexpectedly / terminated + recovery
51 / 7 / 11Disk errors (disk source) — failing drive warning signs
153 / 129Storage/adapter resets — SAN/HBA or cabling issues

Querying Events Fast (PowerShell)

# FilterHashtable is the ONLY fast way — never pipe Get-WinEvent to Where-Object on big logs
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddHours(-24)}

# Failed logons grouped by source account (spray detection)
Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddDays(-1)} |
  ForEach-Object { $_.Properties[5].Value } | Group-Object | Sort-Object Count -Descending

# New services in the last week (7045)
Get-WinEvent -FilterHashtable @{LogName='System'; Id=7045; StartTime=(Get-Date).AddDays(-7)} |
  Select-Object TimeCreated, Message

# Remote query against another host
Get-WinEvent -ComputerName SRV01 -FilterHashtable @{LogName='Security'; Id=4740} -MaxEvents 20
:: CMD equivalent with wevtutil (works everywhere, no PS needed)
wevtutil qe Security /q:"*[System[(EventID=4625)]]" /c:20 /rd:true /f:text
wevtutil cl Security          :: clear a log (generates a 1102 — don't do this in prod casually)
wevtutil el                   :: list all log names

First-Hour Live Response (triage a possibly-compromised host)

Work top-to-bottom. Capture output to files (append | Out-File C:\ir\name.txt). Don't reboot — you'll lose volatile evidence.

# 1. Who's logged on / active sessions
query user
quser /server:SRV01

# 2. Network connections + owning process (exfil / C2)
netstat -anob
Get-NetTCPConnection -State Established |
  Select LocalPort,RemoteAddress,RemotePort,@{n='P';e={(Get-Process -Id $_.OwningProcess).Name}}

# 3. Running processes with full paths + command lines
Get-CimInstance Win32_Process | Select-Object ProcessId, Name, CommandLine, ExecutablePath

# 4. Autostart / persistence — the big three
Get-CimInstance Win32_StartupCommand | Select Name, Command, Location
schtasks /query /fo list /v
Get-Service | Where-Object Status -eq 'Running' | Select Name, DisplayName

# 5. Recently created executables (dropper artifacts)
Get-ChildItem C:\Users\*\AppData -Recurse -Include *.exe,*.ps1,*.bat -EA SilentlyContinue |
  Where-Object LastWriteTime -gt (Get-Date).AddDays(-3) | Select FullName, LastWriteTime

# 6. Local admin membership (did they add themselves?)
Get-LocalGroupMember Administrators

# 7. Firewall / portproxy persistence checks
netsh interface portproxy show all
Get-NetFirewallRule -Enabled True -Direction Inbound | Select DisplayName, Action

Containment Actions (once you've confirmed)

# Network-isolate WITHOUT killing your remote session: block all except your admin IP.
# (Better: isolate via EDR — Defender/Blackpoint — which keeps the EDR channel open.)
New-NetFirewallRule -DisplayName "IR-Block-Out" -Direction Outbound -Action Block -RemoteAddress Any

# Disable a compromised local account (don't delete — preserve evidence)
Disable-LocalUser -Name compromiseduser

# Kill a malicious process by PID
Stop-Process -Id 4820 -Force

# Force-logoff an RDP session
logoff <sessionID> /server:SRV01

# AD side: disable account + revoke Kerberos + reset password
Disable-ADAccount jsmith
Set-ADAccountPassword jsmith -Reset -NewPassword (Read-Host -AsSecureString)
# Cloud side: Revoke-MgUserSignInSession (see Entra page)

Order matters: preserve evidence (memory/disk image if the case warrants) before you start killing processes and clearing artifacts. When in doubt on a real incident, isolate and escalate rather than "cleaning up" — remediation can destroy the forensic timeline.

Sysinternals for IR (run live: live.sysinternals.com)

ToolUse
AutorunsTHE persistence auditor — every autostart location in one view, VirusTotal-integrated
ProcmonReal-time file/registry/process/network activity — filter heavily or drown
ProcexpProcess Explorer — parent/child tree, VT hashes, "what has this file open"
TCPViewLive connections GUI (netstat that updates)
PsExecRemote execution (also what attackers use — hence 7045/4697 hunting)
SigcheckVerify signatures + VT lookup on files: sigcheck -vt -e C:\Windows\Temp
Handle / ListDLLsWhat has a file locked / injected DLLs

Active Directory / Entra ID

On-prem AD PowerShell, DC health, GPO, and the Microsoft Graph module for Entra. Requires RSAT (ActiveDirectory module) for the on-prem cmdlets.

User Lookups & Fixes (the daily ones)

# Everything about one user
Get-ADUser jsmith -Properties * | Select-Object DisplayName, Enabled, LockedOut,
  PasswordExpired, PasswordLastSet, LastLogonDate, EmailAddress, MemberOf

# Find locked-out accounts, then unlock
Search-ADAccount -LockedOut | Select-Object Name, SamAccountName
Unlock-ADAccount jsmith

# Reset a password + force change at next logon
Set-ADAccountPassword jsmith -Reset -NewPassword (Read-Host -AsSecureString 'New pw')
Set-ADUser jsmith -ChangePasswordAtLogon $true

# Disabled, expired, or stale accounts (offboarding audits)
Search-ADAccount -AccountDisabled
Search-ADAccount -AccountExpired
Search-ADAccount -AccountInactive -TimeSpan 90.00:00:00 -UsersOnly

Where did the lockout come from? Check Event ID 4740 on the PDC emulator — it names the calling computer.

Groups & Computers

Get-ADGroupMember 'Domain Admins' -Recursive | Select-Object Name, SamAccountName
Add-ADGroupMember 'VPN Users' -Members jsmith
Get-ADPrincipalGroupMembership jsmith | Select-Object Name   # groups a user is IN

# Stale computer objects (not seen in 90 days)
Get-ADComputer -Filter {LastLogonTimeStamp -lt $((Get-Date).AddDays(-90).ToFileTime())} `
  -Properties LastLogonTimeStamp | Select-Object Name

DC Health & Replication

dcdiag /v                     :: full DC health check
dcdiag /test:dns              :: DNS-specific tests
repadmin /replsummary         :: replication health at a glance — check the fail column
repadmin /showrepl            :: per-partner replication status
repadmin /syncall /AdeP       :: force replication, all partners, all partitions
netdom query fsmo             :: who holds the five FSMO roles
nltest /dsgetdc:corp.local    :: which DC is this client actually using

Group Policy

gpupdate /force                       :: reapply all policy now
gpresult /h C:\temp\gp.html           :: readable report of what applied and why
gpresult /r /scope:computer           :: quick console summary
Invoke-GPUpdate -Computer PC01 -Force # remote gpupdate (GroupPolicy module)
Get-GPOReport -All -ReportType Html -Path C:\temp\all-gpos.html  # document every GPO

Entra ID — Microsoft Graph PowerShell Graph

The AzureAD and MSOnline modules are retired — Microsoft Graph PowerShell is the supported path.

Install-Module Microsoft.Graph -Scope CurrentUser

# Connect with only the scopes you need
Connect-MgGraph -Scopes 'User.Read.All','Group.Read.All'

Get-MgUser -Filter "startsWith(displayName,'John')" -Property DisplayName,UserPrincipalName,AccountEnabled
Get-MgUser -UserId jsmith@contoso.com -Property SignInActivity |
  Select-Object -ExpandProperty SignInActivity     # last sign-in (needs AuditLog.Read.All)

# Group membership
Get-MgGroupMember -GroupId <guid> -All

# Revoke sessions during offboarding/compromise (forces re-auth everywhere)
Revoke-MgUserSignInSession -UserId jsmith@contoso.com

Hybrid Join / Device State

dsregcmd /status    :: THE hybrid-join diagnostic. Key fields:
::   AzureAdJoined: YES/NO      DomainJoined: YES/NO
::   AzureAdPrt: YES  ← no PRT = SSO/CA problems
whoami /all         :: current token: groups, privileges, SID
klist               :: current Kerberos tickets

M365 / Exchange Online

Exchange Online PowerShell, mail flow investigation, and the admin portal map.

Admin Portal Map (bookmark these)

PortalURL
M365 Adminadmin.microsoft.com
Entra IDentra.microsoft.com
Exchange Adminadmin.exchange.microsoft.com
Intuneintune.microsoft.com
Defender / Securitysecurity.microsoft.com
Purview (compliance)purview.microsoft.com
Teams Adminadmin.teams.microsoft.com
SharePoint Adminyourtenant-admin.sharepoint.com
Azureportal.azure.com
Service Healthadmin.microsoft.com → Health → Service health

Connect

Install-Module ExchangeOnlineManagement -Scope CurrentUser
Connect-ExchangeOnline -UserPrincipalName admin@contoso.com

# Purview / compliance cmdlets (Compliance Search etc.)
Connect-IPPSSession -UserPrincipalName admin@contoso.com

Mailboxes — the daily requests

# Mailbox size + item count
Get-MailboxStatistics jsmith | Select-Object DisplayName, TotalItemSize, ItemCount

# All mailboxes over ~45GB (approaching 50GB standard quota)
Get-Mailbox -ResultSize Unlimited | Get-MailboxStatistics |
  Where-Object {$_.TotalItemSize.Value.ToBytes() -gt 45GB} | Select-Object DisplayName, TotalItemSize

# Convert to shared mailbox (offboarding — frees the license once converted)
Set-Mailbox jsmith -Type Shared

# Full Access + Send As (the standard delegate combo)
Add-MailboxPermission shared@contoso.com -User jsmith -AccessRights FullAccess -AutoMapping $true
Add-RecipientPermission shared@contoso.com -Trustee jsmith -AccessRights SendAs

# Who has access to this mailbox?
Get-MailboxPermission shared@contoso.com | Where-Object {$_.User -notlike 'NT AUTHORITY\*'}

# Forwarding audit — a top BEC persistence check
Get-Mailbox -ResultSize Unlimited |
  Where-Object {$_.ForwardingAddress -or $_.ForwardingSmtpAddress} |
  Select-Object DisplayName, ForwardingAddress, ForwardingSmtpAddress, DeliverToMailboxAndForward

# Inbox rules on one mailbox (BEC check #2 — look for delete/move-to-RSS rules)
Get-InboxRule -Mailbox jsmith | Select-Object Name, Enabled, ForwardTo, RedirectTo, DeleteMessage

Message Trace ("where did the email go?")

# Last 10 days live trace
Get-MessageTrace -RecipientAddress jsmith@contoso.com -StartDate (Get-Date).AddDays(-5) -EndDate (Get-Date) |
  Select-Object Received, SenderAddress, Subject, Status

# Drill into why a message got the status it did
Get-MessageTrace -MessageTraceId <id> -RecipientAddress jsmith@contoso.com | Get-MessageTraceDetail

# Older than 10 days → historical search (results in ~1-4 hrs, CSV emailed/downloadable)
Start-HistoricalSearch -ReportTitle 'Sept trace' -ReportType MessageTrace `
  -StartDate 2026-06-01 -EndDate 2026-06-15 -RecipientAddress jsmith@contoso.com

Statuses: Delivered, FilteredAsSpam (check quarantine at security.microsoft.com → Email & collaboration → Review → Quarantine), Failed (read the detail), Pending.

Transport Rules & Quarantine

Get-TransportRule | Select-Object Name, State, Priority
Get-TransportRule 'Block exe attachments' | Format-List Description

Get-QuarantineMessage -RecipientAddress jsmith@contoso.com -PageSize 50
Release-QuarantineMessage -Identity <identity> -ReleaseToAll

Compliance / Purview Quick Hits

# Litigation hold (needs Exchange Online Plan 2 or add-on)
Set-Mailbox jsmith -LitigationHoldEnabled $true

# Content search + purge (phishing removal) — run in Connect-IPPSSession
New-ComplianceSearch -Name 'Phish-0716' -ExchangeLocation All `
  -ContentMatchQuery 'subject:"Invoice overdue" AND received:2026-07-15'
Start-ComplianceSearch 'Phish-0716'
Get-ComplianceSearch 'Phish-0716' | Select-Object Status, Items
New-ComplianceSearchAction -SearchName 'Phish-0716' -Purge -PurgeType SoftDelete

Purge removes mail from user mailboxes tenant-wide. Confirm hit count and sample the results before running the action.

Email Auth Records (SPF / DKIM / DMARC)

# Verify from any machine
Resolve-DnsName contoso.com -Type TXT | Where-Object Strings -match 'spf'
Resolve-DnsName selector1._domainkey.contoso.com -Type CNAME
Resolve-DnsName _dmarc.contoso.com -Type TXT

# Enable DKIM for a domain in EXO
Get-DkimSigningConfig contoso.com
New-DkimSigningConfig -DomainName contoso.com -Enabled $true

SPF for pure-M365 tenants: v=spf1 include:spf.protection.outlook.com -all. Validate the whole stack at MXToolbox (see Links page).

Intune / Autopilot

Device-side diagnostics, log locations, and enrollment troubleshooting — the parts you can't do from the portal.

Force a Sync

# On the device (fastest): Settings → Accounts → Access work or school
# → click the account → Info → Sync

# Or restart the Intune Management Extension to force Win32 app re-eval
Restart-Service IntuneManagementExtension

# Or from the portal: intune.microsoft.com → Devices → [device] → Sync

Log & Registry Locations (memorize the first one)

WhatWhere
Win32 app installs (IME)C:\ProgramData\Microsoft\IntuneManagementExtension\Logs\IntuneManagementExtension.log
App detection resultsSame folder — AppWorkload.log on newer clients
MDM event logEvent Viewer → Applications and Services → Microsoft → Windows → DeviceManagement-Enterprise-Diagnostics-Provider → Admin
Enrollment registryHKLM\SOFTWARE\Microsoft\Enrollments
Policy CSP stateHKLM\SOFTWARE\Microsoft\PolicyManager\current\device
Autopilot profile cacheC:\Windows\ServiceState\wmansvc\AutopilotDDSZTDFile.json

Read IME logs with CMTrace or the newer Support Center OneTrace — plain Notepad works but you lose the highlighting.

Diagnostics Collection

:: One-shot diagnostic bundle — attach to vendor/escalation tickets
mdmdiagnosticstool.exe -area DeviceEnrollment;DeviceProvisioning;Autopilot -zip C:\temp\mdm-diag.zip

:: Join/enrollment state (same tool as hybrid join troubleshooting)
dsregcmd /status

The portal can also pull this remotely: device → Collect diagnostics.

Autopilot Hash Collection

# From a running machine — uploads directly to the tenant (needs Graph consent)
Install-Script Get-WindowsAutopilotInfo -Force
Get-WindowsAutopilotInfo -Online

# Offline to CSV instead (import at intune.microsoft.com → Devices → Enrollment → Windows Autopilot → Devices)
Get-WindowsAutopilotInfo -OutputFile C:\temp\hash.csv

# From OOBE: Shift+F10 opens a command prompt, then:
powershell -ExecutionPolicy Bypass
Install-Script Get-WindowsAutopilotInfo -Force
Get-WindowsAutopilotInfo -Online

Win32 App Packaging

# Wrap installers into .intunewin with the Content Prep Tool
IntuneWinAppUtil.exe -c C:\source -s setup.exe -o C:\output

# Typical silent-install command lines to try, in order:
setup.exe /S          # NSIS / Inno-style
setup.exe /quiet /norestart
msiexec /i app.msi /qn /norestart

Content Prep Tool: github.com/microsoft/Microsoft-Win32-Content-Prep-Tool. Detection rules beat "install succeeded" exit codes — prefer file-version or registry detection.

Enrollment Troubleshooting Quick Checklist

1. dsregcmd /status — AzureAdJoined YES? PRT present?
2. Licensing — user has Intune license assigned?
3. Enrollment restrictions — intune.microsoft.com → Devices → Enrollment → restrictions blocking personal/Windows?
4. MDM scope — Entra → Mobility (MDM/MAM) → Microsoft Intune → user scope includes the user?
5. Event log — DeviceManagement-Enterprise-Diagnostics-Provider → Admin for the actual error code
6. Error code lookup — search the hex code (e.g. 0x80180014 = enrollment blocked by restrictions)

Linux Essentials

Debian/Ubuntu-flavored (matches your Proxmox/Ubuntu stack). systemd throughout.

Services & Logs (systemd)

systemctl status nginx           # state + last log lines
sudo systemctl restart nginx
sudo systemctl enable --now nginx  # enable at boot AND start now
systemctl list-units --failed    # anything broken?

journalctl -u nginx -f           # follow one service's log live
journalctl -u nginx --since "1 hour ago"
journalctl -b -p err             # errors since this boot
journalctl --disk-usage          # journal eating your disk?

Networking

ip a                             # interfaces + addresses (replaces ifconfig)
ip r                             # routing table (default route on top)
ss -tulpn                        # listening sockets + owning process (replaces netstat)
resolvectl status                # which DNS servers systemd-resolved is using
ping -c 4 8.8.8.8
curl -I https://site.com         # headers only — quick "is the web server alive"
curl -v telnet://10.0.0.5:443    # poor man's port test
sudo tcpdump -i eth0 port 443 -nn  # packet capture (add -w cap.pcap for Wireshark)

# Netplan (Ubuntu server IP config) — /etc/netplan/*.yaml
sudo netplan try                 # applies with auto-rollback if you lose connectivity
sudo netplan apply

Disk, Memory, Performance

df -h                            # filesystem usage
du -sh /var/* | sort -rh | head  # what's eating /var
free -h                          # memory (look at 'available', not 'free')
lsblk                            # block devices / partitions tree
htop                             # interactive top (apt install htop)
iostat -xz 2                     # disk I/O pressure (sysstat package)
ncdu /                           # interactive disk usage explorer — install it, thank yourself later

Packages (apt)

sudo apt update && sudo apt upgrade -y
apt search nginx
apt show nginx                   # version, deps, description
sudo apt install nginx
sudo apt remove --purge nginx    # remove + config files
sudo apt autoremove              # clean orphaned deps
apt list --upgradable
dpkg -l | grep nginx             # is it installed?
dpkg -L nginx                    # what files did the package put where?

Files, Permissions, Search

ls -la                           # -rwxr-xr-- = owner rwx, group r-x, other r--
sudo chown www-data:www-data /var/www/site -R
chmod 644 file                   # rw-r--r-- (config files)
chmod 755 script.sh              # rwxr-xr-x (executables/dirs)
chmod 600 ~/.ssh/id_ed25519      # private keys: owner-only or ssh refuses them

find /var/log -name "*.log" -mtime -1        # logs modified in last day
find / -size +500M -type f 2>/dev/null       # big files
grep -rin 'error' /var/log/nginx/            # recursive, case-insensitive, line numbers
tail -f /var/log/syslog
tar -czvf backup.tar.gz /etc/nginx/          # create gzip archive
tar -xzvf backup.tar.gz -C /tmp/restore      # extract to a path

Users & SSH

sudo adduser deploy
sudo usermod -aG sudo deploy     # grant sudo
groups deploy
sudo passwd deploy

# Key auth — do this once, never type passwords again
ssh-keygen -t ed25519 -C "you@workstation"
ssh-copy-id deploy@10.0.0.5

# Hardening basics in /etc/ssh/sshd_config, then: sudo systemctl restart ssh
#   PasswordAuthentication no
#   PermitRootLogin no

Firewall (ufw) & Cron

sudo ufw allow 22/tcp            # ALLOW SSH BEFORE ENABLING or you lock yourself out
sudo ufw allow 80,443/tcp
sudo ufw enable
sudo ufw status verbose

crontab -e                       # edit current user's cron jobs
# ┌min ┬hour ┬day ┬month ┬weekday
# 0    2     *    *      *        /usr/local/bin/backup.sh   ← daily 2 AM
# */15 *     *    *      *        /path/check.sh             ← every 15 min
sudo crontab -l -u root          # view root's crontab (also an IR persistence check)

Docker

Container lifecycle, compose workflow, and cleanup. Modern syntax: docker compose (space), not docker-compose.

Containers — daily lifecycle

docker ps                        # running containers
docker ps -a                     # include stopped (find the crashed one)
docker logs -f --tail 100 app    # follow logs, last 100 lines
docker exec -it app bash         # shell inside (try 'sh' if bash missing)
docker restart app
docker stop app && docker rm app
docker inspect app               # full config JSON — IPs, mounts, env
docker stats                     # live CPU/mem per container
docker top app                   # processes inside the container

Compose — the real workflow

docker compose up -d             # start stack in background
docker compose down              # stop + remove containers (volumes survive)
docker compose down -v           # ALSO deletes named volumes — data gone
docker compose logs -f app       # logs for one service in the stack
docker compose ps
docker compose restart app

# The standard update cycle
docker compose pull && docker compose up -d

# Rebuild after changing a Dockerfile
docker compose up -d --build

down -v destroys volume data. Know which flag you're typing.

Images, Volumes, Networks

docker images
docker pull nginx:1.27           # pin versions in production, never :latest
docker rmi old-image

docker volume ls
docker volume inspect app_data   # find the host path (Mountpoint)

docker network ls
docker network inspect bridge    # which containers are on it, their IPs

Run Flags Worth Memorizing

docker run -d \
  --name app \
  --restart unless-stopped \      # survives reboots; 'always' restarts even after manual stop
  -p 8080:80 \                    # host:container
  -v app_data:/var/lib/app \      # named volume
  -v /host/config:/etc/app:ro \   # bind mount, read-only
  -e TZ=America/Detroit \
  --env-file .env \
  nginx:1.27

Cleanup & Disk Recovery

docker system df                 # what's using space
docker system prune              # stopped containers, dangling images, unused networks
docker system prune -a           # also removes ALL unused images (big reclaim, big re-pull)
docker volume prune              # unused volumes — check twice
docker builder prune             # build cache

Debugging a Container That Won't Start

docker logs app                        # 1. what did it say before dying
docker inspect app --format '{{.State.ExitCode}} {{.State.Error}}'   # 2. exit code (137 = OOM-killed/SIGKILL)
docker events --since 10m              # 3. what the daemon saw
docker run --rm -it --entrypoint sh image:tag   # 4. bypass entrypoint, poke around inside

Git

Daily flow, branching, and — most importantly — the undo table.

Daily Flow

git status
git add -A                       # stage everything (or 'git add -p' to review hunks)
git commit -m "Add printer deployment script"
git push
git pull                         # fetch + merge; 'git pull --rebase' for linear history
git log --oneline --graph --all  # readable history
git diff                         # unstaged changes; '--staged' for what's about to commit

Branching

git switch -c feature/dashboard-api   # create + move to new branch
git switch main
git branch -a                         # all branches incl. remote
git merge feature/dashboard-api       # merge INTO current branch
git branch -d feature/dashboard-api   # delete merged branch (-D forces)
git push -u origin feature/dashboard-api  # first push of a new branch

The Undo Table (bookmark mentally)

SituationFix
Unstage a filegit restore --staged file
Discard uncommitted changes to a filegit restore file destroys work
Fix last commit message / add forgotten filegit commit --amend
Undo last commit, keep changes stagedgit reset --soft HEAD~1
Undo last commit, discard changesgit reset --hard HEAD~1 destroys work
Undo a commit that's already pushedgit revert <hash> — new commit, safe on shared branches
"I lost a commit"git reflog then git reset --hard <hash> — reflog sees everything

Never reset --hard or force-push on a branch other people use. revert is the shared-branch tool.

Stash — park work mid-task

git stash push -m "wip: hubspot auth"
git stash list
git stash pop                    # apply latest + remove from stash
git stash apply stash@{1}        # apply specific, keep in stash

Setup & .gitignore

git config --global user.name  "Your Name"
git config --global user.email "you@systems-x.com"
git config --global init.defaultBranch main

# .gitignore essentials for your stack
# .env
# *.log
# __pycache__/
# venv/
# node_modules/
# *.secrets.json

# Already committed a file you meant to ignore? Untrack without deleting:
git rm --cached .env && git commit -m "Stop tracking .env"

A secret that has EVER been committed is in history forever unless you rewrite it (git filter-repo) — and you should rotate the credential regardless.

Proxmox / NGINX

Homelab and small-MSP staples: Proxmox VE CLI (qm for VMs, pct for containers) and the NGINX reverse-proxy config you'll copy-paste most.

Proxmox — VMs (qm)

qm list                          # all VMs on this node + status + IDs
qm status 100
qm start 100 / qm shutdown 100 / qm stop 100   # stop = hard power-off
qm reboot 100
qm config 100                    # full VM config (disks, NICs, resources)
qm set 100 -memory 8192          # change RAM live-ish (needs reboot for some)
qm set 100 -cores 4

# Snapshots
qm snapshot 100 pre-update --description "before patching"
qm listsnapshot 100
qm rollback 100 pre-update
qm delsnapshot 100 pre-update

# Clone (template → new VM)
qm clone 9000 105 --name web05 --full
qm migrate 100 node2 --online    # live-migrate in a cluster

Proxmox — LXC Containers (pct)

pct list
pct start 200 / pct stop 200
pct enter 200                    # drop into the container's shell (no SSH needed)
pct exec 200 -- apt update       # run one command inside
pct config 200
pct set 200 -memory 2048
pct snapshot 200 clean
pct clone 200 201 --hostname test

Proxmox — Storage, Cluster, Updates

pvesm status                     # storage pools + usage
pvesh get /nodes                 # API from CLI — query anything the GUI shows
pvecm status                     # cluster quorum + node membership
pvecm nodes

# Backups (vzdump)
vzdump 100 --storage local --mode snapshot --compress zstd
qmrestore /path/to/dump.vma.zst 110   # restore VM as new ID 110

# Updates (community/no-subscription: comment enterprise repo first)
apt update && apt dist-upgrade
# Enterprise repo lives in /etc/apt/sources.list.d/pve-enterprise.list

On a no-subscription homelab node, disable the pve-enterprise repo (it 401s) and add the pve-no-subscription repo, or apt update throws errors every time.

NGINX — Service & Config Basics

nginx -t                         # TEST config before reloading — always do this first
sudo systemctl reload nginx      # apply config with zero downtime (vs restart)
sudo nginx -s reload             # same, direct signal
nginx -T                         # dump the FULL merged config (all includes resolved)
nginx -V                         # compiled-in modules + version

# Config layout (Debian/Ubuntu):
#   /etc/nginx/nginx.conf            main
#   /etc/nginx/sites-available/      your site configs live here
#   /etc/nginx/sites-enabled/        symlinks to enabled sites
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
# Logs: /var/log/nginx/access.log  and  error.log

NGINX — Reverse Proxy (the config you'll reuse constantly)

# /etc/nginx/sites-available/app — proxy to a Docker container on :3000
server {
    listen 80;
    server_name app.example.com;
    return 301 https://$host$request_uri;   # force HTTPS
}
server {
    listen 443 ssl http2;
    server_name app.example.com;

    ssl_certificate     /etc/letsencrypt/live/app.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/app.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # WebSocket support (needed for many dashboards/apps)
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

Missing the X-Forwarded-* headers is the #1 cause of "app thinks everyone is 127.0.0.1" and broken HTTPS redirects behind the proxy.

NGINX — TLS with Let's Encrypt (Certbot)

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d app.example.com -d www.app.example.com   # auto-edits your config
sudo certbot certificates        # list certs + expiry
sudo certbot renew --dry-run     # test auto-renewal (real renewal is a systemd timer)
systemctl list-timers | grep certbot

NGINX — Quick Troubleshooting

SymptomCheck
nginx -t failsIt prints the exact file:line. Usually a missing ; or unclosed {
502 Bad GatewayUpstream is down or wrong port — curl http://127.0.0.1:3000 to test the backend directly
504 Gateway TimeoutBackend too slow — raise proxy_read_timeout, or the app is hung
403 ForbiddenFile perms or root/index misconfig; check error.log
Config change ignoredYou edited sites-available but the symlink in sites-enabled points elsewhere, or forgot to reload
SELinux (RHEL) blocks proxysetsebool -P httpd_can_network_connect 1
sudo tail -f /var/log/nginx/error.log   # the answer is almost always here