reg query, reg add and reg export: the Windows registry from the command line

reg.exe is the registry’s command line front end, and Microsoft’s own registry article for advanced users calls it the Console Registry Tool for Windows. It ships with every installation and needs no module and no profile to load, which is most of the reason it is still the tool reached for on Server Core and in recovery scenarios. Eleven operations cover everything from reading a single value to swapping an entire hive out from under a key.

The trouble is that three of the most ordinary things it does are not what they look like. A value you read back can differ from the value that is stored. A key can exist and not exist on the same machine at the same time. And a key you exported before editing cannot be restored by importing it afterwards.

Each of those three is documented, and much of that documentation sits nowhere near the reg reference pages. This article works through all three with Microsoft’s own wording and Microsoft’s own captured output, and shows what each one costs a script that assumes otherwise. It does not repeat the parameter tables, which Learn already has and which are linked at the end.

Applies to: Windows client and Windows Server, all supported versions


Quick answer

Read one value, create one, remove it again. Everything below is under HKCU, which your own account owns, so no elevated prompt is needed and nothing outside your profile is touched.

rem /v names the value, /e demands an exact name match instead of the default
rem behaviour, which returns every value name that merely contains the string
reg query "HKCU\Environment" /v Path /e

rem /t sets the stored type, /d supplies the data, /f skips the overwrite prompt
reg add "HKCU\Software\ZaurTest" /v AppPath /t REG_SZ /d "C:\Program Files\SRV-PROD-01 Agent" /f

rem No /v, so the subkey and everything under it goes. /f means no confirmation
reg delete "HKCU\Software\ZaurTest" /f
Note: Ten of the eleven operations document exactly two return values, 0 for success and 1 for failure, which is what makes reg query an existence test. The eleventh documents a third value, and that value is not a failure. See the exit codes section below.

What reg does, and its eleven operations

reg is not one command with switches. It is eleven separate operations, each with its own reference page, its own syntax and its own set of switches. They fall into three groups: the ones that only read, the ones that change the registry in place, and the ones that move registry data through a file. Knowing which group an operation sits in tells you most of what you need about its limits.

OperationWhat it doesAccepts a remote computer
reg addAdds a subkey or an entryYes
reg compareCompares two subkeys or entriesYes
reg copyCopies an entry to another locationYes
reg deleteDeletes a subkey or entriesYes
reg exportWrites subkeys and values to a .reg fileNo, local only
reg importMerges a .reg file into the registryNo, local only
reg loadWrites a saved hive into a different subkeyYes
reg queryReturns the next tier of subkeys and entriesYes
reg restoreWrites a saved hive back to the registryNo, local only
reg saveSaves subkeys and values to a hive fileYes
reg unloadRemoves a hive loaded by reg loadYes

Eight of the eleven accept a \\computername\ prefix on the key name. The three that do not are export, import and restore. The export and restore pages each state in as many words that the operation only works with the local computer; the import page never offers a computer name at all and describes its target as the registry of the local computer. That asymmetry is worth remembering, because it means a remote machine can be read and edited over the wire but cannot be exported over it.

Warning: When a remote computer is named, the only valid root keys are HKLM and HKU. Every other root is local only. This is documented on each operation’s page rather than in one place, which is why it is so often discovered at runtime.

Before the first example

Four things need to be true before the examples below behave as written. Each one is a single command, and each answers a question that otherwise gets answered halfway through a script.

1. Know whether your prompt is elevated. Nothing in this article needs elevation, because every write goes under HKCU. Anything under HKLM does need it, and the reliable test is the integrity level in your own token rather than group membership.

rem S-1-16-12288 is the High mandatory level SID. It is present only in an
rem elevated token, which is why it beats looking for the word Administrators
whoami /groups | findstr /c:"S-1-16-12288"

2. Confirm the scratch key does not already exist. The examples create HKCU\Software\ZaurTest and delete it again at the end. If it is already there, the export and compare steps will not show what they are meant to show.

rem The answer is the errorlevel, not the text, so 2>nul keeps stderr off
rem the screen. An errorlevel of 1 here is the good outcome: nothing is there yet
reg query "HKCU\Software\ZaurTest" 2>nul
echo %ERRORLEVEL%

3. Create somewhere for the files to land. The export and save operations write files, and the reg save reference states that it uses the current path when none is given. Give them a folder of their own rather than relying on wherever the prompt happens to be sitting.

rem 2>nul keeps stderr off the screen, so the line is safe to re-run even
rem when the folder is already there. dir confirms it exists
md C:\bat\reg 2>nul
dir C:\bat\reg

4. Read the built-in help for the operation you are about to script. The online reference pages and the help compiled into the binary do not list the same switches, and the section on the 32-bit and 64-bit views below shows exactly where they part company. The binary on the machine in front of you is the authority for what it accepts.

rem Help is per operation. Check each one you intend to put in a script
reg query /?
reg export /?
Result: With those four answered you know what your prompt can write, that the scratch key is clear, where files will go, and which switches your build of reg.exe actually takes.

The value that changes when you read it

Microsoft’s PowerShell sample page for registry entries reads one particular value two different ways, and prints both results. The value is DevicePath under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion. Same machine, same key, same entry, one page.

First through reg.exe. The command and the output below are reproduced from that page exactly as Learn prints them.

reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion /v DevicePath
! REG.EXE VERSION 3.0

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
    DevicePath  REG_EXPAND_SZ   %SystemRoot%\inf

Then the same entry through the PowerShell registry provider, also reproduced from that page.

Get-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion -Name DevicePath
DevicePath   : C:\WINDOWS\inf
PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Windows
PSChildName  : CurrentVersion
PSDrive      : HKLM
PSProvider   : Microsoft.PowerShell.Core\Registry
Common mistake: reg.exe returned %SystemRoot%\inf and the provider returned C:\WINDOWS\inf. Only one of those is what is stored. Read a value with Get-ItemProperty, write it to another machine with reg add, and you have quietly replaced a portable value with one machine’s literal path. On a box where Windows is not on C: it is now wrong, and nothing will say so.

The mechanism is documented, just not on the reg pages. The type is REG_EXPAND_SZ, and Learn’s own description of the matching PowerShell property type says the string holds unexpanded references to environment variables which are expanded when the value is retrieved. Expansion on read is the type’s defining behaviour, not a quirk of one cmdlet. reg query is the odd one out here precisely because it shows you the stored bytes.

It is worth being precise about who does the expanding, because the obvious suspect is innocent. PowerShell itself does nothing at all with percent signs in a string, which is easy to confirm without touching a registry.

# ExpandString is what the shell itself would do to a string. If the shell were
# responsible, this would come back different from what went in
$s = '%SystemRoot%\inf'
$ExecutionContext.InvokeCommand.ExpandString($s) -eq $s
True
Note: Percent signs mean nothing to PowerShell, so the expansion you see in Get-ItemProperty output comes from the registry provider reading a REG_EXPAND_SZ entry. In CMD the percent sign means a great deal, which is the other half of the same problem.

That other half shows up on the writing side. If you type %SystemRoot% into a reg add command, CMD expands it before reg.exe is even started, and the literal path gets stored. Microsoft’s reg add page covers this in one line of its Remarks, and its own example uses the caret to escape each percent sign.

rem The caret stops CMD expanding the percent signs, so reg.exe receives the
rem variable name rather than this machine's answer to it
reg add "HKCU\Software\ZaurTest" /v LogDir /t REG_EXPAND_SZ /d ^%SystemRoot^%\Logs /f

rem Read it straight back. The stored data should still contain the variable
reg query "HKCU\Software\ZaurTest" /v LogDir /e
Warning: Do not assume the caret worked, check it. If the second command prints C:\WINDOWS\Logs instead of %SystemRoot%\Logs, the percent signs were expanded before reg.exe saw them. The type is still REG_EXPAND_SZ either way, so the only thing that gives it away is the data.

There is a third place the same string can change, and this one is not the shell’s doing at all. The Win32 registry redirector page documents that WOW64 intercepts 32-bit writes of REG_SZ and REG_EXPAND_SZ data and rewrites %ProgramFiles% as %ProgramFiles(x86)%, along with the equivalent substitution for the common files variable. The conditions are stated tightly: the string has to begin with the variable, the comparison is case sensitive, there is a length ceiling, and the substitution does not happen when the key was opened for the 64-bit view.

Note: That case sensitivity is the part that catches people. Learn spells out that a string beginning with a differently cased spelling of the common files variable is not substituted, so two installers that differ only in capitalisation end up storing different data.

Practical examples

Five examples, in order, all operating on the same scratch key. The last one removes everything the first four created.

1. Read one value and nothing else

The problem: A deployment check needs to know the value of one named entry, and the script around it treats any output as a match.

The solution: Name the value with /v and add /e, because the documented default is that all matches are returned, not just the exact one.

rem /e demands an exact name match. Without it the documented default is that
rem every matching name is returned, not only the one you asked for
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion" /v DevicePath /e

rem errorlevel is the answer, not the text. 0 found, 1 not found
echo %ERRORLEVEL%
Result: One key path line and one value row, and an errorlevel of 0. If the entry is absent the errorlevel is 1, which is why testing the errorlevel beats matching on the text: the text changes with the locale and the errorlevel does not.

2. Create a value whose data contains spaces

The problem: An agent needs its install path recorded under the current user, and the path has a space in it, which is to say it is a normal path.

The solution: Quote the data. /f suppresses the overwrite prompt so the line is safe to re-run, which matters more than it sounds: without it a second run stops and waits for a keypress that a scheduled task will never provide.

rem The quotes are for CMD, not for reg. Without them the data stops at the
rem first space and /d takes only "C:\Program"
reg add "HKCU\Software\ZaurTest" /v AppPath /t REG_SZ /d "C:\Program Files\SRV-PROD-01 Agent" /f

rem Read it back to confirm the whole path was stored
reg query "HKCU\Software\ZaurTest" /v AppPath /e
Note: The reg add reference states that this version of the command does not ask for confirmation when it adds a subkey. The prompt /f exists to suppress is the one you get when the value already exists.

3. Copy a key and prove the copy matches

The problem: Before changing a block of settings you want a second copy inside the registry itself, and you want to be able to prove later that it is still identical.

The solution: reg copy with /s takes the subkeys too, and reg compare answers in its exit code.

rem /s copies subkeys as well as values, /f skips the confirmation
reg copy "HKCU\Software\ZaurTest" "HKCU\Software\ZaurTestCopy" /s /f

rem /s compares recursively. The default output lists differences only
reg compare "HKCU\Software\ZaurTest" "HKCU\Software\ZaurTestCopy" /s
Warning: reg copy does not ask for confirmation when it copies a subkey, which its own Remarks section states. What it does with entries already present at the destination is not documented anywhere on that page, so do not rely on a stale copy from a previous run being cleared out. Delete the destination key first if you need it to be exact.

4. Export the key, change it, then import the export

The problem: The usual habit, and the one this example exists to break: export a key before editing it, in the belief that importing the file afterwards puts things back.

The solution: Run it and look. The import restores what was changed and leaves what was added.

rem The file must have a .reg extension, which the reference states outright.
rem /y overwrites an existing file without prompting
reg export "HKCU\Software\ZaurTest" C:\bat\reg\ZaurTest.reg /y

rem Now make two kinds of change: alter one value, and add one that the
rem exported file knows nothing about
reg add "HKCU\Software\ZaurTest" /v AppPath /t REG_SZ /d "C:\Program Files\SRV-PROD-02 Agent" /f
reg add "HKCU\Software\ZaurTest" /v AddedLater /t REG_DWORD /d 1 /f

rem Put the export back and read the whole key
reg import C:\bat\reg\ZaurTest.reg
reg query "HKCU\Software\ZaurTest"
Common mistake: AppPath comes back to the exported data and AddedLater stays where it is. That follows directly from what Microsoft’s own article on .reg files says: running one merges its contents into the local registry. A merge cannot remove anything, so an export taken before an edit is a record of what the key used to contain, not an undo.

5. Remove everything the examples created

The problem: Two scratch keys and a file are now sitting in a profile that did not have them twenty minutes ago.

The solution: reg delete without /v takes the subkey and everything beneath it, and a final query confirms the removal by failing.

rem No /v, so this is the whole subkey and all its values. /f, so no prompt
reg delete "HKCU\Software\ZaurTest" /f
reg delete "HKCU\Software\ZaurTestCopy" /f
del C:\bat\reg\ZaurTest.reg

rem The confirmation is an errorlevel of 1: the key is gone
reg query "HKCU\Software\ZaurTest" 2>nul
echo %ERRORLEVEL%
Result: Both keys removed and the final echo prints 1. A cleanup step that verifies itself is worth the two extra lines, because the only documented return values are 0 and 1, and a query that finds nothing is the only positive confirmation the tool offers.

Reading a value into a script variable

Every value row that reg query prints has the same three columns: the value name, the type, and the data. That looks like an invitation to split on whitespace. It is not, because two of the three columns are allowed to contain spaces.

The table below runs three rows through CMD’s for /f splitting rules. The first row is Learn’s captured output from earlier in this article. The second and third are laid out in the same three column shape using value names and data that Learn prints for that same key, so they are assembled from documented pieces rather than captured, which is worth saying plainly rather than presenting them as a transcript.

The rowtokens=1tokens=2tokens=3
DevicePath / REG_EXPAND_SZ / %SystemRoot%\infDevicePathREG_EXPAND_SZ%SystemRoot%\inf
ProgramFilesDir (x86) / REG_SZ / C:\Program Files (x86)ProgramFilesDir(x86)REG_SZ
AppPath / REG_SZ / C:\Program Files\SRV-PROD-01 AgentAppPathREG_SZC:\Program

Only the first row behaves. In the second the value name carries a space, so the type has slid into tokens=3 and tokens=2 returns a fragment of the name. In the third the data carries a space, so tokens=3 returns the first word of a path and throws the rest away. All three results are unchanged if the row is not indented, so leading whitespace is not the problem and stripping it does not help.

Common mistake: There is no tokens= string that reads all three rows correctly. tokens=2,* is right for rows one and three and wrong for row two; tokens=3,* is right for row two and wrong for the other two. Any parser written against the three column layout is guessing about a key it has not seen.

What does work is narrowing the output to one row you chose yourself, for a value name you already know the shape of. Then the star token takes everything after the type column, spaces and all.

rem This line is typed at the prompt, so the loop variable is %A.
rem tokens=2,* puts the type in %A and the whole remaining data in %B.
rem It is safe here only because AppPath is a name with no space in it
for /f "tokens=2,*" %A in ('reg query "HKCU\Software\ZaurTest" /v AppPath /e ^| findstr /c:"REG_"') do @echo %B
Common mistake: The percent sign is the only part of that line that changes between the two places you might put it. At the prompt the loop variables are %A and %B; inside a .bat or .cmd file they must be %%A and %%B. Paste the script spelling into a prompt and CMD stops with %%A was unexpected at this time. Paste the prompt spelling into a script and Microsoft’s for reference says the variable is ignored and an error message is displayed, so the loop runs and simply produces nothing, which is much harder to notice.

The findstr in that pipeline is doing one job: dropping the blank lines and the key path line so that only the value row reaches the loop. It is filtering on the type column rather than on the value name, and that choice is deliberate.

Warning: Filtering on a value name is a substring match. Run it against the value names Learn prints for HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion and findstr /c:"Path" selects three of them, while findstr /c:"Dir" selects six. Let reg query do the selecting with /v and /e, and leave findstr to strip the lines that are not value rows at all.
Common mistake: findstr /c:"REG_SZ" does not match a REG_EXPAND_SZ row. The characters REG_SZ do not occur anywhere inside REG_EXPAND_SZ, so a type filter written that way silently drops every expandable string in the key. /c:"REG_" matches both, which is why the loop above uses it.

Exit codes, and the one that is not a failure

Ten of the eleven operations document exactly two return values. reg compare documents three, and the third one means the command worked.

Operation012
add, copy, delete, export, import, load, query, restore, save, unloadSuccessFailureNot documented
reg compareSuccessful, result identicalThe comparison failedSuccessful, differences found

That third value collides with the oldest idiom in CMD. Microsoft’s if reference defines errorlevel as true when the exit code is equal to or greater than the number given, so if errorlevel 1 is true for 2 as well. The fix is the numeric comparison, which is the form Microsoft’s own if examples use.

rem Capture the code once: every echo below sets its own errorlevel, so a
rem second reading would be describing the echo rather than the comparison
reg compare "HKCU\Software\ZaurTest" "HKCU\Software\ZaurTestCopy" /s
set RC=%ERRORLEVEL%

rem Each code gets its own test. "if errorlevel 1" would catch 2 as well
rem and report a successful comparison as a failed one
if %RC% EQU 0 echo identical
if %RC% EQU 2 echo differences found
if %RC% EQU 1 echo the comparison itself failed
Note: Pair that with /on, which the reference describes as displaying nothing. The comparison then produces no output at all and the entire answer lives in the exit code, which is exactly what a script wants and exactly what a human at a prompt does not.

Two registries on one machine

On 64-bit Windows a subset of the registry exists twice. The Win32 registry redirector page describes it as separate logical views for 32-bit and 64-bit applications, mapped onto different physical locations, with the redirection invisible to the application doing the reading. A 32-bit process and a 64-bit process asking for the same path under HKLM\Software are not necessarily asking about the same data. Learn is careful here: only a subset of the registry is redirected, and some keys under redirected paths are shared rather than duplicated, so the two views return one physical copy for those.

This is where two Microsoft pages give an administrator two different mental models, and it is worth having both rather than picking one.

Note: The registry article for advanced users says the 64-bit Registry Editor displays the 32-bit keys under the WOW6432Node node, which invites you to navigate there and read them. The Win32 redirector page says redirected keys are mapped to physical locations under that node, that the physical location should be considered reserved by the system, and that applications should not access it directly because it may change. Both are Microsoft. The first describes what you see, the second describes what you should write down in a script.

The supported way to choose a view is a switch, not a path. Query the same key name twice and let reg.exe do the mapping.

rem The same key name through each view. On a 64-bit machine these can return
rem different data, or one of them can report that the value does not exist
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion" /v ProgramFilesDir /e /reg:64
reg query "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion" /v ProgramFilesDir /e /reg:32

Which operations take those switches is the least satisfying part of the whole reference. Here is what the eleven pages actually say.

OperationIn the Syntax blockIn the parameter table
reg addYesYes
reg queryYesYes
reg importNoYes
reg compareNoNo
reg copyNoNo
reg deleteNoNo
reg exportNoNo
reg loadNoNo
reg restoreNoNo
reg saveNoNo
reg unloadNoNo
Common mistake: Reading that table as a list of what the binary supports. It is a list of what the reference pages mention. reg import is the tell: the switches are in its parameter table and missing from its own Syntax block on the same page, which is a documentation defect rather than a behaviour. Run reg export /? on the machine you are scripting for and believe the binary.
Warning: reg add documents the view switches and reg delete does not. Whatever the binary turns out to accept, do not write a script that creates a value in a named view and removes it without naming one. Check the help for both halves before you rely on the pair.

Export is not a backup

Example 4 showed the behaviour. This is why it happens, and what the documentation says to use instead.

reg export and reg import deal in .reg files, which are text. Microsoft’s article on those files states that running one merges its contents into the local registry. A merge writes what the file contains and touches nothing else, so anything created after the export survives the import untouched.

reg save and reg restore deal in hive files, which are binary. Both reference pages carry the same sentence in their Remarks, and it is an instruction rather than a description: save the parent subkey before editing any registry entries, and if the edit fails, restore it with reg restore. The Win32 page behind that operation is blunter still, describing the underlying function as replacing the subkeys and values below the specified key with those from the file.

OperationFileScopeEffect on what is already there
reg export.reg, textLocal computer onlyReads only, writes the file
reg import.reg, made by reg exportLocal computer onlyMerges, so additions since the export remain
reg save.hiv, binaryLocal or remoteReads only, writes the file
reg restore.hiv, made by reg saveLocal computer onlyReplaces what is below the key
Common mistake: Treating the two pairs as interchangeable because both produce a file. They are not, and the files are not either: the reference for reg import says its file must be created in advance by reg export, and the reference for reg restore says the same about reg save and a .hiv extension. Mixing the pairs is at least an obvious problem to run into. The quiet one is importing a .reg file and believing the key is back to how it was.

A .reg file can delete, but only if you edit it by hand. Microsoft’s article documents the syntax: a hyphen in front of the bracketed key path removes the key, and a hyphen in place of the data removes a single value. That is an editing step on the file, never something reg export produces on its own, which is the clearest possible confirmation that an untouched export cannot remove anything.

Warning: The reg load page and the Win32 page behind it do not agree on where a hive may be loaded. The command reference lists five valid root keys; the API page says the data is loaded into a subkey under HKEY_USERS or HKEY_LOCAL_MACHINE. The API page makes the narrower claim and describes the layer that does the work, so plan around it and test the rest.

Hidden gems

A search with no /e is wider than it looks. The /e parameter is documented as returning only exact matches, and the default as returning all of them. On a big key that difference is not a nuisance, it is a wrong answer that a script will act on. If your test is whether a specific entry exists, /e is not optional.

/k narrows a recursive search to key names. reg query KEY /s /f pattern /k searches key names only, and the reference spells out that it has to be used together with /f. Compared with dumping a whole subtree and piping it through findstr it is one process instead of two, and the matching is done by the tool that knows which part of the line is a key name.

reg compare with /on is a silent assertion. The output switches are /oa, /od, /os and /on, and /on displays nothing. Combine it with the three-way exit code and you have a drift check that prints nothing at all unless you choose to print something yourself, which is the shape a scheduled job wants.

Two of the eleven reference pages carry copy and paste damage, and it matters when you are reading fast. The Remarks section on the reg copy page introduces its return values as belonging to reg compare. They are not; the values listed there are reg copy‘s own two. The reg delete page has the matching slip in its parameter table, which names the parameter <keyname1> while its own Syntax block calls it <keyname>. Both pages are correct in substance; only the labels travelled from somewhere else.


Cross-shell equivalent

PowerShell reaches the registry through a provider, so keys behave like folders and entries behave like properties of those folders. That mapping is the source of most of the friction: entries cannot be browsed, only read off the key that holds them.

Taskreg.exePowerShell
List the value names in a keyreg query KEYGet-Item -Path KEY | Select-Object -ExpandProperty Property
Read one valuereg query KEY /v NAME /eGet-ItemProperty -Path KEY -Name NAME
Create a valuereg add KEY /v NAME /t TYPE /d DATA /fNew-ItemProperty -Path KEY -Name NAME -PropertyType TYPE -Value DATA
Change a valuereg add KEY /v NAME /d DATA /fSet-ItemProperty -Path KEY -Name NAME -Value DATA
Delete a valuereg delete KEY /v NAME /fRemove-ItemProperty -Path KEY -Name NAME

The first row is the closest thing PowerShell has to a bare reg query. It returns the value names on their own, with none of the PS prefixed properties that the provider adds. Learn’s capture of the output for the CurrentVersion key is five lines.

# Registry keys expose their entries through a property named Property.
# Expanding it gives the same first column reg query prints, and nothing else
Get-Item -Path Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion |
    Select-Object -ExpandProperty Property
DevicePath
MediaPathUnexpanded
ProgramFilesDir
CommonFilesDir
ProductId

To get one entry’s data on its own, without the provider’s own properties wrapped around it, expand the named property in the same way. Remember that what comes back from a REG_EXPAND_SZ entry is the expanded form, as the two captures at the top of this article showed.

# Without the Select-Object this prints PSPath, PSParentPath, PSChildName,
# PSDrive and PSProvider alongside the one value you asked for
Get-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name DevicePath |
    Select-Object -ExpandProperty DevicePath
Note: Get-ItemProperty has Filter, Include and Exclude parameters and Learn states plainly that none of them can filter by property name, because they address keys rather than entries. There is no provider equivalent of reg query‘s /f search across value names, so that filtering is yours to write.

Which leaves a fair summary of when to reach for which. Use the provider when you want typed objects and do not want to parse anything. Use reg.exe when you need the stored bytes rather than the interpreted value, when you are working across a view boundary, or when you are somewhere PowerShell is not, which still includes a good number of recovery and imaging scenarios. The PowerShell commands cheat sheet and the Windows command line cheat sheet are the quick lookups for either shell.


Where this matters

  • Software inventory across a fleet where half the estate reports an install path that does not exist, because the agent read it through the wrong view.
  • Build agents running a 32-bit installer on a 64-bit host, where the key the installer wrote and the key the test looks for have the same name and different contents.
  • Change control before a fix, where the rollback plan says “we exported the key” and the plan only works for values that existed at the time.
  • Migrating a setting between machines, where a path read through PowerShell arrives on the target with the source machine’s drive letter baked into it.
  • Golden image drift, where reg compare against a reference host is the whole check and the wrapper script reads its exit code correctly.
  • Server Core and recovery consoles, where reg.exe is what you have and the shell you would rather be using is not there.

Tips and limitations

  • Eight of the eleven operations accept a \\computername\ prefix. export, import and restore are local only: two of those pages say so outright and the third never offers a computer name.
  • Against a remote computer the only valid roots are HKLM and HKU.
  • The documentation is specific about file extensions: .reg for export and import, .hiv for the file that reg restore and reg load consume.
  • reg add cannot add a subtree, which its Remarks state directly. It adds subkeys and entries only.
  • reg delete with no /v removes the subkey and everything under it. /va is the narrower form: the reference says it deletes all entries within the specified key, and that subkey entries residing within that key are not deleted.
  • The view switches /reg:32 and /reg:64 appear in the Syntax block of two reference pages out of eleven. Treat reg <operation> /? as the authority for switches, and the reference page as the authority for behaviour.
  • For a REG_EXPAND_SZ value, the caret escape in the reg add example is written for the command prompt. Always read the value back and confirm the variable survived rather than assuming it did.
  • Microsoft’s own caution sits at the top of the reg reference and is worth repeating: prefer Control Panel or an MMC snap-in where the setting has one, and back the key up before editing it directly.

Official documentation


Related tools


Related guides

Five cheat sheets, one PDF

Subnet masks, PowerShell, Linux commands, HTTP status codes and the ESXi command line - one page each, free to keep. Leave an address and it arrives in a minute.