⚡ execute & doctor
Run a single ADscan command non-interactively, and run a fast pre-engagement health check.
Two commands make ADscan scriptable from the shell, without opening the interactive workbench:
adscan execute <verb>— run one REPL command non-interactively (smoke tests, demos, scripting).adscan doctor— a fast GREEN/RED health check that confirms the environment works before a scan.
Both run fully non-interactively: every prompt resolves to a safe default, so they are safe in CI, pipelines, and unattended runs.
adscan doctor
A one-shot smoke test. It runs the key validations and prints a single per-check pass/fail panel so you can confirm "everything works" before (or at the start of) an engagement.
# Unauthenticated reachability check
adscan doctor -d corp.local --dc-ip 10.0.0.1
# Add credentials to also validate authentication and the posture probe
adscan doctor -d corp.local --dc-ip 10.0.0.1 -u alice -p 'Password1'
# Segmented network: the DNS server is a separate host from the DC
adscan doctor -d corp.local --dc-ip 10.0.0.1 --dns-server 10.0.9.53On a segmented network where the AD-zone DNS server is a different host from the domain controller, pass --dns-server IP. The DNS-resolution check then validates against that host instead of the DC, so doctor does not report a false DNS failure when the DC does not serve DNS. See Segmented networks.
What it checks:
| Check | What it confirms |
|---|---|
| Runtime preflight | Tools, system packages, and DNS configuration are in place. |
| DNS resolution | The domain resolves and its domain controllers are located. |
| DC connectivity | The DC answers on the AD ports (53 / 88 / 389 / 445). |
| Authentication | The supplied credential binds against the DC (skipped without -u/-p). |
| Enabled users | A lightweight count of enabled user accounts (sizing input; needs credentials). |
| Enabled computers | A lightweight count of enabled computer accounts (sizing input; needs credentials). |
| Trust relationships | The source domain's trusts, listed by name (needs credentials). |
| Posture probe | The DC is reachable and its hardening posture is recorded. |
The exit code is 0 only when every applicable check passed, so doctor is usable as a gate in scripts. Checks that do not apply (for example, authentication with no credentials) are reported as SKIP and never fail the run. The enabled counts and trust relationships are informational — they describe the environment for scoping and never fail the run.
The enabled user/computer counts are deliberately a fast paged query, not a full graph build, so the preflight stays a few seconds even on a large domain.
By default doctor uses an ephemeral workspace that is removed on exit. It never writes to a named workspace unless you pass one.
Machine-readable output
--json replaces the human matrix with a single JSON object on stdout — the same structure the ADscan platform's preflight consumes:
adscan doctor -d corp.local --dc-ip 10.0.0.1 -u alice -p 'Password1' --json{
"domain": "corp.local",
"dc_ip": "10.0.0.1",
"passed": true,
"checks": [
{ "name": "DNS resolution", "status": "pass", "detail": "...", "value": null, "items": null },
{ "name": "Enabled users", "status": "info", "detail": "1482", "value": 1482, "items": null },
{ "name": "Trust relationships", "status": "info", "detail": "...", "value": null, "items": ["child.corp.local"] }
]
}Every check carries a name, a status (pass, fail, skip, or info), and a one-line detail. The sizing rows also fill value with the count, and the trust row fills items with the trusted domain names. passed is false only when a check actually failed — skip and info never flip it — and the exit code is the same either way, so you can branch on whichever is easier to read in your pipeline.
Validate connection (web platform)
The same preflight is available in the ADscan platform as Validate connection on the Create New Scan form. Enter the domain, DC IP, username, and password, then run the check before launching the scan. It returns:
- A pass/fail matrix for DNS resolution, DC connectivity, and authentication.
- Directory sizing — the enabled user and computer counts, which are the inputs for engagement scoping.
- The domain's trust relationships, listed by name.
The result shows a clear verdict ("Ready to scan" or "Resolve issues before scanning"). It is read-only — it does not modify the target, create a scan, or write to a workspace — and it never blocks the form: you can launch the scan whether or not you run it first.
adscan execute
Run a single REPL command from the shell. execute establishes the minimum session context the command needs — workspace, domain, credentials, DNS, and posture — then invokes the command and exits.
# List the commands available to execute
adscan execute --list
# Resolve DNS / locate the DCs for a domain
adscan execute check_dns -d corp.local --dc-ip 10.0.0.1
# Kerberoast (authenticates, then auto-cracks)
adscan execute kerberoast -d corp.local --dc-ip 10.0.0.1 -u alice -p 'Password1'
# AS-REP roast
adscan execute asreproast -d corp.local --dc-ip 10.0.0.1 -u alice -p 'Password1'
# Inspect the hardening posture (passthrough after `--`)
adscan execute posture -d corp.local --dc-ip 10.0.0.1 -- show
# Re-run one attack path from a workspace a previous scan left behind
adscan execute attack_paths -d corp.local --dc-ip 10.0.0.1 \
--workspace engagement-1 -- svc_backupSession flags
execute accepts the standard session flags and forwards everything after the verb (or after --) verbatim to the command:
| Flag | Purpose |
|---|---|
-d, --domain | Target domain. |
--dc-ip | PDC / DC IP for the target domain. |
--dns-server | AD-zone DNS server, when it is a separate host from the DC on a segmented network. Feeds name resolution only; --dc-ip stays the auth target. |
-u, --username | Auth username (for commands that authenticate). |
-p, --password | Auth password or hash. |
-w, --workspace | Named workspace to persist into. Omit for an ephemeral temp workspace. |
-i, --interface | Network interface (for myip auto-config). |
--keep-workspace | Keep an auto-created ephemeral workspace on exit. |
The command after execute parses its own arguments the same way it does inside the interactive shell. The session flags (-d, --dc-ip, …) set the context, and -d reaches the command whether or not you repeat the domain after --, so -- svc_backup and -- corp.local svc_backup are equivalent. To pass arguments straight to the command, place them after --. The one exception is posture, whose first argument is the action (-- show, -- probe, -- clear) rather than the domain.
Workspaces: ephemeral by default
- No
--workspace→ an ephemeral temp workspace is created and removed on exit (use--keep-workspaceto retain it). This is the default for quick smoke tests, so a trivial check never pollutes a real workspace. --workspace <name>→ results persist in that named workspace and are available to the rest of ADscan and the platform. Use this when you want to keep the loot (for example,execute kerberoast --workspace engagement-1).
Available verbs and prerequisites
adscan execute --list prints the current set with auto-generated help, read from the same allowlist the runner enforces. The current set:
| Verb | Needs | What it does |
|---|---|---|
check_dns | domain | Resolve a domain's DNS / locate its domain controllers. |
posture | domain | Inspect, probe, or clear the hardening posture for a domain. |
enum_trusts | domain, creds | Enumerate domain trusts (parent/child, external, forest). |
kerberoast | domain, creds | Request SPN service tickets and auto-crack the hashes. |
asreproast | domain, creds | Roast accounts with Kerberos pre-auth disabled. |
smb_shares | domain, creds | Enumerate SMB shares and effective access. |
search_adcs | domain, creds | Enumerate ADCS templates and ESC findings. |
users | domain, prior scan | Write the user inventories for a collected domain: enabled users, control exposure, and the accounts that enable domain compromise. |
attack_paths | domain, creds | Compute and execute attack paths from a collected workspace. |
reset_attack_path_statuses | domain | Reset a domain's stored attack-path statuses to the theoretical baseline. |
Not every REPL command is available to execute. Session-only commands (such as exit or set) are intentionally excluded, as is anything ADscan will not run unattended. Mistype a verb and it suggests the closest real one instead of failing blankly.
Verbs that read a workspace a scan already filled
users, attack_paths, and reset_attack_path_statuses work on data a previous scan collected, so they need the named --workspace that scan wrote to — either scan into --workspace <name> from the start, or pass --keep-workspace on the adscan ci run so the workspace survives. Pointed at an empty or ephemeral workspace, they stop with a message telling you to run adscan ci first rather than crashing.
attack_paths re-runs a single path against that workspace instead of repeating the whole scan. Two things shape how you call it:
- Execution is offered only from a start principal ADscan already owns. When that principal's credential is already stored in the workspace, you do not need to re-supply
-u/-p. - Only paths still marked
theoreticalare executed, so a path you already attempted is skipped until you re-arm it. A run where every path was skipped for this reason says so, names the outcomes it found, and prints the reset command.
# Re-arm the domain's paths, then run one again from an owned account
adscan execute reset_attack_path_statuses -d corp.local --dc-ip 10.0.0.1 \
--workspace engagement-1
adscan execute attack_paths -d corp.local --dc-ip 10.0.0.1 \
--workspace engagement-1 -- svc_backup
# Or run every owned start principal
adscan execute attack_paths -d corp.local --dc-ip 10.0.0.1 \
--workspace engagement-1 -- ownedkerberoast and asreproast request RC4 (etype 23) tickets, which are faster to crack but raise Defender for Identity alerts ("Kerberoasting / AS-REP Roasting attack suspected"). Coordinate with the client's security team or document the expected engagement noise.