sc

The Windows Service Control command — query, control, create, and configure services — as a defender's reference, with the service-based persistence and lateral-movement patterns to detect. Click any command to copy it.

Start here

Syntax — mind the spaces

sc talks to the Service Control Manager. The one thing that trips everyone up: every option is name= value with a space after the equals sign and none before it. Services have a short service name (what you pass to sc) and a longer display name (what you see in services.msc) — they're often different. Pairs with the net, wmic, and Registry sheets.

sc create X binPath= "c:\x.exe"The spacing rule in one line: binPath= then a space then the value. binPath ="c:\x.exe" or binPath="c:\x.exe" will fail or misparse.
sc query vs sc.exe queryIn PowerShell, sc is an alias for Set-Content — use sc.exe explicitly there, or you'll overwrite a file.
service name ≠ display namesc commands take the short service name (e.g. Spooler), not the display name (Print Spooler). Use sc getkeyname / sc getdisplayname to convert.
Backs onto the registryEverything sc does is written under HKLM\SYSTEM\CurrentControlSet\Services — so a service change is also a registry change (Sysmon 12/13).

Read

Query & inspect

sc queryAll active services (running or paused), with state and type. The quick "what's running" read.
sc query state= allEvery service including stopped ones — the full inventory. (Remember the space after state=.)
sc query SpoolerOne service's current state, type, and exit codes.
sc queryex SpoolerExtended query — adds the PID and flags. The PID lets you pivot to tasklist / Process Explorer.
sc qc SpoolerQuery config — the big one: BINARY_PATH_NAME, start type, service account (SERVICE_START_NAME), and dependencies. Where you spot a bad binary path.
sc qc Spooler 8192Same, with a larger buffer — needed when a very long binPath gets truncated (long paths can hide the real command).
sc qdescription SpoolerThe service's description text — a blank or junk description on a "legit-sounding" service is a small flag.
sc enumdepend SpoolerServices that depend on this one — know the blast radius before you stop it.
sc getkeyname "Print Spooler"Display name → service (key) name. sc getdisplayname Spooler goes the other way.
sc query type= driver state= allKernel/file-system drivers, not just Win32 services — a malicious driver loads here too. type= service for the usual ones.

Control

Start, stop & pause

sc start SpoolerStart a stopped service now.
sc stop SpoolerStop a running service. Watch for this against security services (AV/EDR, WinDefend, event log) — defense evasion.
sc pause Spooler / sc continue SpoolerPause and resume, for services that support it.
sc control Spooler 255Send a custom control code to a service — rarely needed, occasionally abused to trigger service-specific behavior.

Change

Create, modify & delete

The high-signal section. Creating or re-pointing a service is a top persistence and lateral-movement technique — treat these as events to investigate, not just admin noise.

sc create Svc binPath= "c:\x.exe" start= autoCreate a new service. start= is boot/system/auto/demand/disabled. An auto-start service pointing at an odd binary = persistence. Logs as Event 7045.
sc create Svc binPath= "cmd /c ..." type= ownA service whose binPath is cmd, powershell, or a script — not a real service binary — is almost always malicious. The service "fails to start" but the payload already ran.
sc config Spooler binPath= "c:\evil.exe"Re-point an existing service's binary — hijacking a legit service for persistence while keeping its trusted name. Compare sc qc output to a baseline.
sc config Svc start= disabledChange start type. Disabling a defensive service (then it never comes back after reboot) is an evasion move.
sc config Svc obj= "LocalSystem"Change the account a service runs as (obj=) and its password (password=). A service flipped to LocalSystem is a privilege-escalation tell.
sc delete SvcRemove a service entirely — remediation, or an attacker cleaning up after a psexec-style run. Export the key first.
sc create Svc type= kernel binPath= "c:\drv.sys"Register a kernel driver service — the setup step for a malicious or vulnerable-driver (BYOVD) load. High-signal.

The baseline move: sc query state= all and sc qc for each service, saved to a file, gives you a known-good list. Diff against it — a new service, a changed binPath, or a start type flipped to auto/disabled is what you're hunting.

Config

Security & recovery

sc sdshow SpoolerShow the service's security descriptor (SDDL) — who can start, stop, or reconfigure it. A weak ACL here is a privilege-escalation path.
sc sdset Svc "D:(A;;...)"Set the security descriptor. Abused to hide a service by denying read/query to everyone, or to grant control to a low-priv user.
sc qprivs SpoolerThe privileges the service requests. sc privs sets them.
sc failure Svc reset= 86400 actions= restart/5000Recovery actions on crash. A run program failure action is a sneaky persistence spot — a payload that runs when the service "fails".
sc qfailure SvcRead the configured failure/recovery actions — check for a surprise "run program" action.
sc sidtype Svc unrestrictedService SID type. Mostly informational, occasionally relevant to how a service is scoped.

Fleet

Remote hosts

sc \\SRV01 query state= allRun any sc command against a remote host (needs rights + the Remote Registry / RPC reachable).
sc \\SRV01 qc SpoolerRead a remote service's config — triage a suspect host without logging in.
sc \\SRV01 create Svc binPath= "..."Create a service on a remote machine — classic remote-exec / lateral movement (what PsExec does under the hood). Alert on remote 7045.
sc \\SRV01 stop WinDefendStopping or disabling a defensive service on a remote host — a red-team / intrusion hallmark.

Put it together

SOC one-liners

Quick reads against a live box. For the richer object output, the PowerShell equivalents are Get-Service and Get-CimInstance Win32_Service.

sc query state= all | findstr /i "SERVICE_NAME"A flat list of every service's short name — pipe it, diff it against a baseline.
for /f "tokens=2" %s in ('sc query state^= all ^| findstr SERVICE_NAME') do @sc qc %s | findstr BINARY_PATH_NAMEDump every service's binary path in one pass — then eyeball for temp, appdata, users, cmd, or powershell.
Get-CimInstance Win32_Service | ? {$_.PathName -match 'temp|appdata|users|\\public'} | Select Name,PathName,StartNameThe PowerShell version — services whose binary sits in a user-writable path. A strong persistence flag.
Get-CimInstance Win32_Service | ? {$_.PathName -match 'cmd|powershell|wscript|rundll32'}Services running an interpreter instead of a real service exe — almost always suspect.
sc qc WinDefend && sc query WinDefendConfirm Defender (and your EDR's service) is configured and actually running — attackers disable, don't always delete.
Get-Service | ? {$_.StartType -eq 'Disabled' -and $_.Name -match 'Defend|Sense|EventLog'}Security/logging services set to Disabled — evasion, caught in one line.

Detection, restated: service install logs as Security 4697 and System 7045; start-type changes as 7040; sc.exe itself in a command line (4688 / Sysmon 1) with create, config binPath=, or \\ is the thing to alert on — especially from an odd parent.