On this page
- How reg treats access and privilege
- Addressing model
- Key paths
- The value-name positional
- Value literals and types
- Global options
- Reading
- reg get <key> [value]
- reg ls <key>
- reg tree <key>
- reg info <key>
- Writing
- reg set <key> <value> <data>
- reg new <key>
- reg del <key> [value]
- Masking and hiding
- reg mask <key> [value] / reg unmask <key> [value]
- reg hide <key> / reg unhide <key>
- Layers
- reg layer ls
- reg layer new <name>
- reg layer set <name>
- reg layer del <name>
- Security descriptors
- reg sd <key>
- Symlinks
- reg link <key> <target>
- Watching
- reg watch <key>
- Batch, export, backup, and restore
- reg apply <file>
- reg export <key> [file]
- reg backup <key> <file>
- reg restore <key> <file>
- Output formats
- Exit status
- See also
reg
reg is the command-line interface to the live registry — the running LCS store, reached through the registry system calls. Where regman reads shipped documentation and tells you what a key means, reg talks to the kernel and reads or writes what a key is. It is the everyday tool for scripting configuration: querying effective values, writing to layers, masking and hiding, managing security descriptors, watching for change, and taking backups.
reg <command> [options] <key> [value] [data]
reg is the read/write half of the registry toolset and regman is the lookup half. The division is exact:
| To… | Use… |
|---|---|
| Read or change what a value is set to, on this machine, right now | reg |
| Look up what a value means — its type, default, valid range, when it applies | regman |
Consult regman first to learn the legal range for a knob, then use reg set to write a value inside it. reg never checks a value's meaning and regman never touches the live store; they are complementary.
How reg treats access and privilege
Every reg operation goes through the kernel's access check against the single key it opens — the same access-control path as any other protected object, with no traversal check on the parent keys. reg performs no identity or membership checks of its own: it does not refuse a privileged operation up front. It attempts the operation and reports faithfully whatever the kernel returns. An operation that needs a privilege you lack (creating a link, a positive-precedence layer, a backup or restore, reading a SACL) simply fails with access denied (exit 3) rather than being blocked by the tool. A single reg command may legitimately span privilege tiers.
Addressing model
Almost every subcommand shares one addressing scheme: a key path positional, and an optional value name positional. Understanding the split is most of understanding reg.
Key paths
The key is a positional path argument. Both / and \ are accepted as separators — neither character is legal inside an LCS key component, so there is no ambiguity, and you may use whichever your shell quotes most comfortably:
reg get Machine/System/KMES
reg get 'Machine\System\KMES' # identical
A leading separator is optional and ignored (/Machine/X is the same as Machine/X). Paths are compared case-insensitively. The first component is the hive:
| Path | Meaning |
|---|---|
Machine\… |
The machine hive — system-wide configuration. |
Users\<SID>\… |
A specific principal's hive. |
CurrentUser\… |
A kernel alias, rewritten to the caller's own Users\<SID>\ at the syscall boundary. |
On output, reg displays paths with a backslash by default. --sep=/ (or REG_SEP=/) switches display to forward slash for that invocation; this affects display only, never how a path is parsed.
The value-name positional
The value name is a separate positional argument — it is never folded into the key path. This is deliberate: an LCS value name may itself contain / or \ (which a key component may not), so keeping them apart removes all ambiguity.
reg get Machine/System/KMES BufferCapacity
# └──── key path ─────┘ └── value ──┘
The presence or absence of the value argument selects what the command targets:
- No value argument ⇒ the command targets the key itself — its metadata, its values as a set, its security descriptor, its children.
- A value argument ⇒ the command targets that one named value.
- The default value (the empty-name value) is addressed by the literal token
@in the value-name position, mirroring.regconvention:reg get Machine\App @.
This split applies uniformly to get, set, del, mask, and unmask.
Value literals and types
On set (and in a batch), the value's data is a single token whose registry type is either forced by a type: prefix or inferred from its shape. The registry value types and their literal syntax:
| Prefix | Registry type | Data syntax |
|---|---|---|
sz: |
REG_SZ |
UTF-8 string (rest of token, verbatim). |
expand: |
REG_EXPAND_SZ |
UTF-8 string, %VAR% left unexpanded on disk. |
dword: |
REG_DWORD |
42 or 0x2A; must fit u32. |
dword-be: |
REG_DWORD_BIG_ENDIAN |
42 or 0x2A; must fit u32. |
qword: |
REG_QWORD |
42 or 0x2A; must fit u64. |
multi: |
REG_MULTI_SZ |
Comma-separated; \, escapes a literal comma. |
hex: / bin: |
REG_BINARY |
Hex bytes; :, -, and space separators are ignored. |
link: |
REG_LINK |
An absolute key path (a symlink target). |
none: |
REG_NONE |
No data (token must be empty after the prefix). |
When the substring before the first : is not a recognised keyword (for example http://host), the token is not treated as typed and inference applies:
| Token shape | Inferred type |
|---|---|
all decimal digits, fits u32 |
REG_DWORD |
all decimal digits, fits u64 but not u32 |
REG_QWORD |
0x… hex, ≤ 8 significant hex digits |
REG_DWORD |
0x… hex, ≤ 16 significant hex digits |
REG_QWORD |
| anything else (including empty) | REG_SZ |
Inference is intentionally broad, so any all-digit token becomes a number — a PIN, a zip code, or 007 becomes a REG_DWORD and loses its textual form. To force a string, prefix it with sz: (sz:007 stores the string 007; sz:dword:42 stores the literal string dword:42). Because the coercion is a known footgun, reg set always echoes the resolved type on success, so a surprising conversion is never silent even under --quiet.
Global options
Every subcommand accepts the following. Each behavioural toggle also has an environment-variable equivalent, so it can be set per-invocation (the flag) or once per shell or script (the variable). The flag wins over the variable, which wins over the built-in default.
| Option | Env var | Effect |
|---|---|---|
--json |
REG_JSON=1 |
Emit structured JSON instead of human text. watch emits JSON-lines. |
-v, --verbose |
REG_VERBOSE=1 |
More detailed output. |
-q, --quiet |
— | Suppress non-essential output. (A surprising type coercion is still reported.) |
--sep=CHAR |
REG_SEP |
Path display separator: \ (default) or /. |
--help |
— | Print help for the command and exit 0. |
--version |
— | Print the version and exit 0. |
Mutating subcommands additionally accept:
| Option | Env var | Effect |
|---|---|---|
--layer NAME |
REG_LAYER |
Target layer for the write (default: the base layer). |
-y, --yes |
REG_ASSUME_YES=1 |
Skip the confirmation prompt on a destructive command. |
Destructive commands (del -r, restore, layer del) prompt for confirmation when standard input is a terminal, and auto-proceed when it is not — so interactive use is guarded while scripts are never blocked. Set -y/--yes or REG_ASSUME_YES=1 to skip the prompt explicitly.
Reading
reg get <key> [value]
Read the effective (resolved) value. With a value, prints that value's data; with no value, lists the key's effective values (the default @ value first, then named values sorted case-insensitively) — a shorthand for ls --values-only.
| Option | Effect |
|---|---|
-L, --layers |
Annotate the value with the layer it resolved from and its sequence number. |
--raw |
Write the value's raw bytes to standard output verbatim — for piping REG_BINARY data. |
--no-follow |
Operate on a symlink key itself rather than following it to its target. |
The single-value default form prints data bare (no quotes; one element per line for REG_MULTI_SZ) so it pipes cleanly. -L shows the winning layer's provenance:
$ reg get Machine\System\KMES BufferCapacity
4194304
$ reg get Machine\App Theme -L
Theme = REG_SZ "dark" (layer: policy, seq 7)
Only the winning value is shown; the full shadowed stack beneath it is not yet exposed by any client ABI (the -L flag will render the whole stack unchanged once that primitive lands). See Layers for what "effective" resolves against.
reg ls <key>
One-level listing of a key's immediate subkeys and values.
| Option | Effect |
|---|---|
-l, --long |
Long form: for subkeys, child and value counts; for values, type and byte size. |
--keys-only |
List subkeys only. |
--values-only |
List values only. |
$ reg ls Machine\System\KMES -l
BufferCapacity = REG_QWORD 4194304 (8 bytes)
MaxEventSize = REG_DWORD 65536 (4 bytes)
reg tree <key>
Recursively list the subkey tree rooted at key.
| Option | Effect |
|---|---|
--depth N |
Limit recursion to N levels. |
--values |
Include each node's values, not just its keys. |
$ reg tree Machine\System --depth 2
reg info <key>
Print a key's metadata: leaf name, subkey and value counts, last-write time, hive generation, security-descriptor size, and the volatile and symlink flags.
| Option | Effect |
|---|---|
--no-follow |
Inspect a symlink key itself rather than its target. |
$ reg info Machine\System\KMES
path Machine\System\KMES
name KMES
subkeys 0
values 4
last_write_ns 1717243800000000000
hive_generation 42
sd_size 164
volatile false
symlink false
Writing
reg set <key> <value> <data>
Create or update a value. The value name (or @) and the data token are both required. Writes are tagged with --layer (default: base). See value literals for the data syntax.
| Option | Effect |
|---|---|
--layer NAME |
Write into layer NAME instead of the base layer. |
-p, --parents |
Create any missing ancestor keys. |
--expected-seq N |
Compare-and-swap guard: apply only if the value's current sequence is N; a mismatch exits 6 without writing. |
$ reg set Machine\App Build 4096
set Machine\App Build = REG_DWORD 4096 (layer: base)
$ reg set Machine\App Servers multi:alpha,beta --layer policy
--expected-seq supports lock-free read-modify-write: read the value with -L to learn its sequence, then write back with --expected-seq set to that number; if another writer changed it in between, your write fails cleanly instead of clobbering theirs.
reg new <key>
Create a key with no values. Reports whether the key was created or already existed.
| Option | Effect |
|---|---|
--layer NAME |
Create the key in layer NAME. |
-p, --parents |
Create any missing ancestor keys. |
--volatile |
Create a volatile (RAM-only) key that does not survive a reboot. |
$ reg new Machine\App\Cache --volatile
created Machine\App\Cache (layer: base)
reg del <key> [value]
Delete a value, or a key. (Alias: delete.)
With a value, deletes this layer's entry for that value only — lower-layer entries resurface, because a per-layer delete is not a tombstone (use mask for that). With no value, deletes the key, which must be empty unless -r is given.
| Option | Effect |
|---|---|
--layer NAME |
Delete from layer NAME. |
-r, --recursive |
Delete the key and all its descendants (walks and removes children). |
-y, --yes |
Skip the confirmation prompt (recursive deletes prompt on a terminal). |
$ reg del Machine\App Legacy
deleted value Legacy from Machine\App
$ reg del Machine\App\Temp -r
Recursively delete key Machine\App\Temp and all its contents? [y/N] y
deleted Machine\App\Temp (3 keys)
See Deleting keys and values for how a per-layer delete differs from a tombstone.
Masking and hiding
These commands expose LCS's tombstone and hide primitives, which mask lower-precedence state rather than removing a layer's own entry — the distinction that makes layers revertible. The layer is chosen with --layer (default: base).
reg mask <key> [value] / reg unmask <key> [value]
mask sets a tombstone: a per-value marker in the target layer that hides that value from all layers below it. unmask clears it.
| Option | Effect |
|---|---|
--layer NAME |
The layer that carries the tombstone. |
--all |
Blanket tombstone: mask all lower-layer values on the key (no value argument). |
A value is required unless --all is given.
$ reg mask Machine\App ApiKey --layer policy
set tombstone on Machine\App ApiKey (layer: policy)
$ reg mask Machine\App --all --layer policy
set blanket tombstone on Machine\App (layer: policy)
reg hide <key> / reg unhide <key>
hide installs a HIDDEN path entry in the target layer, masking the key's existence in that layer and below. unhide removes that layer's path entry, letting the key reappear.
| Option | Effect |
|---|---|
--layer NAME |
The layer that hides (or unhides) the key. |
$ reg hide Machine\App\Debug --layer policy
hid Machine\App\Debug (layer: policy)
Layers
reg layer ls
List layers with name, precedence, enabled state, and (informational) owner SID, ordered by descending precedence.
| Option | Effect |
|---|---|
-l, --long |
Long form. |
$ reg layer ls
policy prec=100 enabled owner=S-1-5-32-544
base prec=0 enabled
reg layer new <name>
Create a layer by writing its metadata key under Machine\System\Registry\Layers\.
| Option | Effect |
|---|---|
--precedence N |
Precedence (higher wins). A precedence above 0 requires SeTcbPrivilege; the tool attempts it and reports any denial. |
--owner SID |
Record an informational owner SID. |
--disabled |
Create the layer disabled. |
$ reg layer new policy --precedence 100 --owner S-1-5-32-544
created layer policy (precedence 100, enabled)
reg layer set <name>
Modify an existing layer's metadata.
| Option | Effect |
|---|---|
--precedence N |
Change the precedence. |
--enable / --disable |
Enable or disable the layer. |
--owner SID |
Change the informational owner SID. |
reg layer del <name>
Delete a layer — removes its metadata key; LCS tears down the layer's entries. Prompts for confirmation on a terminal.
$ reg layer del policy
Delete layer policy and all its entries? [y/N] y
deleted layer policy
Managing per-process private layer views is out of scope for reg; see private hives and layers.
Security descriptors
reg sd <key>
Show or set a key's security descriptor as SDDL, using the same codec as the sd tool, so its output is consistent. With no scope flags, the default is owner + group + DACL (a SACL requires the privileged ACCESS_SYSTEM_SECURITY right).
| Option | Effect |
|---|---|
--set SDDL |
Apply the given SDDL. Without it, sd prints the current descriptor. |
--owner |
Scope to the owner. |
--group |
Scope to the group. |
--dacl |
Scope to the DACL. |
--sacl |
Scope to the SACL (needs ACCESS_SYSTEM_SECURITY). |
$ reg sd Machine\App
O:BAG:BAD:(A;;KA;;;BA)(A;;KR;;;WD)
$ reg sd Machine\App --set 'O:BAG:BAD:(A;;KA;;;BA)' --owner --dacl
set security descriptor on Machine\App
A security-descriptor change takes effect on future opens only (existing handles keep the access mask they were granted). Security changes are not layered and are not undone by layer removal — they mutate the key object directly. See Access control on keys.
Symlinks
reg link <key> <target>
Create a symlink key pointing at the absolute target key path. This creates a key with the immutable symlink flag and a default REG_LINK value holding the target. Requires KEY_CREATE_LINK and SeTcbPrivilege/Administrator; the tool attempts it and reports any denial.
| Option | Effect |
|---|---|
--layer NAME |
Create the link key in layer NAME. |
$ reg link Machine\App\CurrentConfig Machine\App\Config\v3
linked Machine\App\CurrentConfig -> Machine\App\Config\v3 (layer: base)
get and info follow symlinks to their target by default; pass --no-follow to inspect the link key itself. See Advanced: registry links.
Watching
reg watch <key>
Arm a change watch and stream one event per change until interrupted (or until --count events). Each event faithfully means "something under the filter changed — re-read"; reg does not decode the change records' contents. With --json, emits one JSON object per line.
| Option | Effect |
|---|---|
--subtree |
Watch descendant keys too, not just this key. |
--filter LIST |
Comma-separated subset of value, subkey, sd (default: all). |
--count N |
Exit after N events. |
$ reg watch Machine\System\KMES --subtree --filter value
changed: Machine\System\KMES
changed: Machine\System\KMES
See Watching for changes for why a service watches instead of polling.
Batch, export, backup, and restore
Two paths move a subtree around: export/apply are the portable, reviewable path (a diffable text or JSON document); backup/restore are the exact, privileged path (an opaque kernel snapshot).
reg apply <file>
Apply a batch of operations to one hive in a single transaction — all-or-nothing. All operations must target one hive (a cross-hive batch fails with exit 4). - reads standard input.
| Option | Effect |
|---|---|
--dir DIR |
Apply every batch file in DIR (sorted), each as its own transaction. A missing or empty directory applies nothing and succeeds. |
--once-delete |
Delete each batch file after it applies successfully (a drain). |
-y, --yes |
Skip confirmation. |
The batch format is JSON (canonical and exact) or a line-oriented text format; apply auto-detects (a leading { or [ means JSON). Text-format input is not yet implemented — supply JSON, or generate one with reg export --json. Text export works for review.
$ reg export --json Machine\App - | reg apply -
applied 4 keys
reg export <key> [file]
Dump a subtree to the batch format. Omit file (or pass -) to write to standard output. Human-readable text by default; --json emits the canonical exact form.
| Option | Effect |
|---|---|
--layer NAME |
Export one layer's view (default: the effective state). |
$ reg export Machine\App app-config.reg
reg backup <key> <file>
Write an opaque, exact, binary kernel snapshot of a key and its subtree to file. Requires SeBackupPrivilege.
$ reg backup Machine\System\KMES kmes.snap
backed up Machine\System\KMES -> kmes.snap
reg restore <key> <file>
Replace a key and its entire subtree from a snapshot, in one transaction. Requires SeRestorePrivilege. Prompts for confirmation on a terminal.
$ reg restore Machine\System\KMES kmes.snap
Replace key Machine\System\KMES and its entire subtree from kmes.snap? [y/N] y
restored Machine\System\KMES from kmes.snap
See Backup and restore for when to reach for each path.
Output formats
Default output is terse, human-readable, and grep-friendly. --json switches every command to structured output — a single self-contained JSON document, except watch, which emits JSON-lines (one object per event). In any value listing, the default (@) value is emitted first, then named values sorted case-insensitively.
Type formatting on read:
| Registry type | Human form | JSON form |
|---|---|---|
REG_SZ / REG_EXPAND_SZ |
the string | {"type":"sz","data":"…"} |
REG_DWORD / REG_QWORD |
decimal | {"type":"dword","data":42} |
REG_MULTI_SZ |
one element per line | {"type":"multi","data":["a","b"]} |
REG_BINARY |
hex | {"type":"binary","data":"deadbeef"} |
REG_LINK |
the target path | {"type":"link","data":"…"} |
Exit status
| Code | Meaning | Typical cause |
|---|---|---|
0 |
Success. | — |
1 |
Usage error. | Bad arguments; a required option missing. |
2 |
Key or value not found. | ENOENT. |
3 |
Access denied. | EACCES, EPERM — the kernel refused the operation. |
4 |
Invalid specification. | Bad path, type, or literal; a cross-hive batch; a name too long (EINVAL, EXDEV, ENAMETOOLONG). |
5 |
Syscall or source failure. | EIO, ETIMEDOUT, ENOSPC, ENOMEM. |
6 |
Compare-and-swap conflict. | EAGAIN — an --expected-seq guard did not match; the value changed under you. |
A denial (3) reports the operation, the target, and, where relevant, the access that was required — in the style of the sd and token tools.
See also
regman— the registry manual: what a key or value means, as opposed to what it is set to. Consult it before youreg set.- Keys, values, and types — the data model
regaddresses. - Layers — what "effective" resolves against, and what
--layer,mask, andhideoperate on. - Access control on keys — the check every
regoperation goes through.