Query multiple entries from registry at once (using reg query) - powershell

I run subsequent reg queries and this takes quite a time:
reg query HKLM\SOFTWARE\Classes /s /f "foo"
reg query HKLM\SOFTWARE\Classes /s /f "bar"
Is there any way to search by multiple values at once with reg query?

No, unfortunately reg query /s /f accepts only a single filter expression.
The filter expression:Tip of the hat to aschipfl for his help.
is matched against all registry entities by default: key names, value names and data.
(OR-ed combinations of) options /k (keys), /v (values) and /d (data) can be used to narrow the scope.
/v can also be used without /f, in which case it requires a value-name search term (e.g., /v foo) that is matched in full (see below); /ve returns only default values (the values whose name is the empty string) if they contain data.
When combining /f with /v <valueNameSearchTerm> or /ve, only combining key search (/k) via /f is supported to narrow down the matches; that is, the only combinations that make sense are:
/f <keySearchTerm> /k /v <valueNameSearchTerm>
/f <keySearchTerm> /k /ve
That way, the /v <valueNameSearchTerm> / /ve matching is limited to those keys that match /f <keySearchTerm>, amounting to AND logic.
Any other combination - omitting /k, adding /d, using just /d - effectively causes the /f search term to be ignored.
/t REG_* can be used to narrow matching to specified value types, such as REG_SZ
performs case-insensitive substring matching by default.
supports wildcard characters * (any number of chars., including none) and ? (exactly 1 char.) - though note that something like foo* still only performs substring matching; there is seemingly no way to anchor substrings.
As stated, when you use /v directly with a value-name search term (e.g., /v foo, it must match in full; e.g., to find a value name that contains substring foo, you then must use *foo*.
/e performs whole-string matching, without wildcard support.
/c uses case-sensitive matching.
numeric data such as REG_DWORD is matched in its decimal string representation
binary data (REG_BINARY) is matched as a "byte string": a list of 2-hex-digit byte values without separators.
Run reg query /? to see all options or consult the documentation.
You can use the following PowerShell command to provide multiple filters:
Note:
The command is limited to the following search logic - though it could be adapted to support all reg query options, at which point creating a function wrapper would definitely be called for:
A regular expression (with -match) rather than wildcard matching (with -like) is used, which both simplifies the command and makes it more flexible (it wouldn't be hard to adapt the solution to use wildcard matching instead).
Only registry data is searched, not also key names and value names.
For instance, to search key names only, the command would be as simple as:
Get-ChildItem HKLM:\SOFTWARE\Classes -Recurse |
Where-Object { $_.PSChildName -match 'foo|bar' }
Unlike with reg.exe, binary data is matched byte by byte, based on their decimal string representation.
Only the sub-keys of the target key are examined, not the target key itself.
With a single filter, the command is slower than reg.exe, but with multiple filters it is eventually likely faster than multiple reg.exe calls; for the OP it took 4-5 - YMMV.
Replacing the Get-ChildItem call with direct use of the .NET framework for recursive key enumeration will likely bring speed improvements, though I have no sense of how much. A purpose-built native binary such as reg.exe will always be faster than custom PowerShell code.
Generally, the main advantages of a PowerShell solution are:
Objects are being returned, which greatly facilitates subsequent processing (no need for parsing text output).
The use of regular expressions allows for more sophisticated matching.
# The two filters to use, combined into a single regex.
$regex = 'foo|bar'
Get-ChildItem HKLM:\SOFTWARE\Classes -Recurse | ForEach-Object {
foreach ($value in $_.GetValueNames()) {
if (($data = $_.GetValue($value)) -match $regex) {
[PSCustomObject]#{
Key = $_.Name
Value = if ($value) { $value } else { '(default)' }
Data = $data
}
}
}
}
The output is something like the following, with the Data column containing the matches (scroll to the right; alternatively, pipe the above to Format-List for a one-property-per-line view):
Key Value Data
--- ----- ----
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AllSyncRootObjects StatusBar prop:~System.StatusBarViewItemCount;~System.StatusBarSelectedItemCount...
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{0002E132-0000-0000-C000-000000000046}\InprocServer32 Class Microsoft.Vbe.Interop.CommandBarEventsClass
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{0002E132-0000-0000-C000-000000000046}\InprocServe... Class Microsoft.Vbe.Interop.CommandBarEventsClass
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{0006F054-0000-0000-C000-000000000046} (default) Microsoft Outlook InfoBar Control
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{0006F054-0000-0000-C000-000000000046}\InprocServer32 Class Microsoft.Office.Interop.Outlook.OlkInfoBarClass
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{0006F054-0000-0000-C000-000000000046}\InprocServe... Class Microsoft.Office.Interop.Outlook.OlkInfoBarClass
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{0006F054-0000-0000-C000-000000000046}\ProgID (default) Outlook.OlkInfoBar.1
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{0006F054-0000-0000-C000-000000000046}\VersionInde... (default) Outlook.OlkInfoBar
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{056440FD-8568-48e7-A632-72157243B55B} (default) Explorer Navigation Bar
HKEY_LOCAL_MACHINE\SOFTWARE\Classes\CLSID\{05d7b0f4-2121-4eff-bf6b-ed3f69b894d7} (default) Taskbar Control Panel
...

Related

How to list contents of a specific directory in powershell?

I'm rather baffled by Powershell in general. Very weird. Anyway, I've read:
Powershell's equivalent to Linux's: ls -al
so I now know how to list the contents of the current directory. But how can I list the contents of an arbitrary directory?
Specifically,
How do I type in the path I want to check?
in Windows, \ is the directory separator; but it's also an escape char in most languages. What do I do with it?
Do I need single-quotes? Double-quotes? No-quotes?
Where do I place the argument relative to the switches? After, like I'm used to, or rather before?
If I want to use an environment variable, or a powershell variable, as part of the path to list - how do I do that?
General PowerShell information and examples:
PowerShell-native commands, including user-authored ones that opt in, have standardized parameter syntax and binding rules, so the following, focused on Get-ChildItem, applies generally:
See the help topic for Get-ChildItem, which describes the command's purpose, syntax, and individual parameters, along with showing examples.
If you have offline help installed (true by default in Windows PowerShell; installable on demand via Update-Help in PowerShell (Core) 7+), you can also print the examples with Get-Help -Example Get-ChildItem | more
As for how to generally read the notation describing the supported parameters listed under the SYNTAX heading of cmdlet help topics, which PowerShell calls syntax diagrams, see the conceptual about_Command_Syntax help topic.
Offline, you can print the syntax diagrams for PowerShell-native commands with standard switch -? or by passing the command name to Get-Command -Syntax (Get-ChildItem -? or Get-Command -Syntax Get-ChildItem). To also access the help text offline, you may have to install local help first, as described above.
Examples:
# The following commands all pass "\" (the [current drive's] root dir)
# to the -Path parameter.
# Note:
# * "\" is NOT special in PowerShell, so it needs no escaping.
# PowerShell allows use of "/" instead even on Windows.
# * -Path arguments are interpreted as wildcard patterns, whether
# quoted or not. You may pass *multiple* paths / patterns.
# * Switch -Force - which, as all switches - can be placed anywhere
# among the arguments, requests that *hidden* items be listed too.
Get-ChildItem -Path \ -Force
Get-ChildItem \ -Force # ditto, with *positional* param. binding
'\' | Get-ChildItem # ditto, via the pipeline.
Get-ChildItem / -Force # ditto, with "/" as alternative to "\"
# To force interpretation as a *literal* path - which matters for
# paths that contain "[" chars. - use -LiteralPath.
# Here too you may pass *multiple* paths.
Get-ChildItem -LiteralPath \ -Force
# Quoting is needed for paths with spaces, for instance.
# Single-quoting treats the string *verbatim*:
Get-ChildItem 'C:\path\to\dir with spaces'
# Double-quoting *expands* (interpolates) variable references
# and subexpressions.
Get-ChildItem "$HOME\dir with spaces"
# A variable alone can be used as-is, without double-quoting, even
# if its value contains spaces.
Get-ChildItem $HOME
To answer your specific questions, for readers who come from POSIX-compatible shells such as Bash:
How do I type in the path I want to check?
Get-ChildItem offers two ways to specify one or more input paths, as most file-processing cmdlets in PowerShell do:
-Path accepts one or more names or paths that are interpreted as a wildcard pattern.
Note that - unlike in POSIX-compatible shells such as Bash - it does not matter whether the path is unquoted or not; e.g., Get-ChildItem -Path *.txt, Get-ChildItem "*.txt", and Get-ChildItem '*.txt' are all equivalent; more on that below (note the incidental omission of -Path in the latter two calls, which makes "*.txt" and '*.txt' bind positionally to the first positional parameter, -Path).
-LiteralPath accepts one or more names or paths that are assumed to refer to existing file-system items literally (verbatim).
Given that literal paths on Unix-like platforms usually do not contain * and ? characters and on Windows cannot, use of -LiteralPath for disambiguation is usually only necessary for paths that contain [ (and possibly also ]), given that PowerShell's wildcard pattern language also supports character sets and ranges (e.g. [ab] and [0-9]).
Binding to -LiteralPath via an argument requires explicit use of -LiteralPath, i.e. use of a named argument; e.g., Get-ChildItem -LiteralPath foo
However, supplying System.IO.FileInfo and/or System.IO.DirectoryInfo instances (such as output by (another) Get-ChildItem or Get-Item call) via the pipeline DOES bind to -LiteralPath, as explained in this answer.
in Windows, \ is the directory separator; but it's also an escape char in most languages. What do I do with it?
In PowerShell \ is not an escape character, so \ instances are treated as literals and do not require escaping; it is `, the so-called backtick that serves as the escape character in PowerShell - see the conceptual about_Special_Characters help topic.
Note, however, that PowerShell generally allows you to use \ and / in paths interchangeably, so that, e.g., Get-ChildItem C:/Windows works just fine.
Where do I place the argument relative to the switches? After, like I'm used to, or rather before?
Note:
All parameters have names in PowerShell - that is, there is no POSIX-like distinction between options (e.g. -l and operands (value-only arguments, such as the / in ls -l /).
A command may declare parameters that may also be passed by value only, positionally, meaning that prefixing the value with the parameter name is then optional (e.g., Get-Path / as shorthand for Get-Path -Path /).
Only parameters that require a value (argument) can potentially be passed as values only - depending on the parameter declaration of the target command - in which case their order matters:
Value-only arguments are called positional arguments, and they bind in order to those parameters of the target command that are declared as positional, if any - see this answer for how to discover which of a given command's parameters are positional ones.
Prefixing a value by its target parameter (e.g., -LiteralPath /some/path) makes it a named argument.
A switch (flag) in PowerShell, such as -Force, is a special parameter type - Boolean in nature - that by definition requires passing it as a named argument, typically without a value (though you can attach a value, e.g. -Force:$true or -Force:$false - note that : is then required to separate the parameter name from its value; see this answer for details).
As an aside: Unlike POSIX-compliant utilities, PowerShell does not support parameters with optional values of any other type - see this answer.
Since PowerShell allows named arguments to be specified in any order, the implication is that you're free to place by-definition-named switch arguments such as -Force anywhere on the command line.
In short: Order only matters among positional (unnamed) arguments in PowerShell.
See the conceptual about_Parameters help topic for more information.
Do I need single-quotes? Double-quotes? No-quotes?
A path (parameter value in general) needs quoting:
if it contains PowerShell metacharacters, notably spaces; e.g. C:\path\to\foo needs no quoting, whereas C:\path with spaces\to\foo does.
if it starts with a subexpression ($(...)), in which case you need double-quoting, i.e. "..." (see below) - though you may choose to always use "..."-quoting for paths involving subexpressions or variable references.
Note that PowerShell has no concept that is the equivalent of the so-called shell expansions in POSIX-compatible shells such as Bash; therefore, whether a given argument is quoted or not makes no semantic difference (assuming it doesn't require quoting); as noted above, *.txt, '*.txt' and "*.txt" are all equivalent, and it is the target command, not PowerShell itself, that interprets the pattern - see this answer for more information.
If quoting is needed:
Verbatim (single-quoted) strings ('...') treat their content verbatim
Expandable (double-quoted) strings ("...") perform string interpolation ("expand" embedded variables and subexpressions, i.e replace them with their values).
If I want to use an environment variable, or a powershell variable, as part of the path to list - how do I do that?
To use such variables as-is, no quoting is needed (even if the values contain spaces):
# PowerShell variable:
Get-ChildItem -LiteralPath $HOME
# Environment variable, e.g. on Windows:
Get-ChildItem -LiteralPath $env:USERPROFILE
To make a variable (or expression) part of a larger string, embed it in an expandable (double-quoted) string ("..."); e.g.:
Get-ChildItem -LiteralPath "$HOME/Desktop"
Note:
Embedding the output from expressions or commands requires use of $(...), the subexpression operator; e.g. Get-ChildItem "$(Get-Variable -ValueOnly Home)/Desktop"; for a complete overview of PowerShell's expandable strings (string interpolation), see this answer.
Situationally, such as in the example above, omitting the "..." quoting would work too - see this answer for more information.
Additionally and alternatively, PowerShell allows you to use (...), the grouping operator to pass the result of arbitrary expressions and commands as arguments; the following is the equivalent of the command above:
Get-ChildItem -LiteralPath ($HOME + '/Desktop')
Alternatively, using the Join-Path cmdlet:
Get-ChildItem -LiteralPath (Join-Path $HOME Desktop)

Why is PS Get-ChildItem so difficult

I did a ton of reading and searching about a way to have Get-ChildItem return a dir listing in wide format, in alphabetical order, with the number of files and directories in the current directory. Here is a image of what I ended up with, but not using GCI.
I ended up writing a small PS file.
$bArgs = "--%/c"
$cArgs = "Dir /n/w"
& cmd.exe -ArgumentList $bArgs $cArgs
As you can see I ended up using the old cmd.exe and passing the variables I wanted. I made an alias in my PS $Profile to call this script.
Can this not be accomplished in PS v5.1? Thanks for any help or advice for an old noob.
PowerShell's for-display formatting differs from cmd.exe's, so if you want the formatting of the latter's internal dir command, you'll indeed have to call it via cmd /c, via a function you can place in your $PROFILE file (note that aliases in PowerShell are merely alternative names and can therefore not include baked-in arguments):
function lss { cmd /c dir /n /w /c $args }
Note that you lose a key benefit of PowerShell: the ability to process rich objects:
PowerShell-native commands output rich objects that enable robust programmatic processing; e.g., Get-ChildItem outputs System.IO.FileInfo and System.IO.DirectoryInfo instances; the aspect of for-display formatting is decoupled from the data output, and for-display formatting only kicks in when printing to the display (host), or when explicitly requested.
For instance, (Get-ChildItem -File).Name returns an array of all file names in the current directory.
By contrast, PowerShell can only use text to communicate with external programs, which makes processing cumbersome and brittle, if information must be extracted via text parsing.
As Pierre-Alain Vigeant notes, the following PowerShell command gives you at least similar output formatting as your dir command, though it lacks the combined-size and bytes-free summary at the bottom:
Get-ChildItem | Format-Wide -AutoSize
To wrap that up in a function, use:
function lss { Get-ChildItem #args | Format-Wide -Autosize }
Note, however, that - due to use of a Format-* cmdlet, all of which output objects that are formatting instructions rather than data - this function's output is also not suited to further programmatic processing.
A proper solution would require you to author custom formatting data and associate them with the System.IO.FileInfo and System.IO.DirectoryInfo types, which is nontrivial however.
See the conceptual about_Format.ps1xml help topic, Export-FormatData, Update-FormatData, and this answer for a simple example.

Using Powershell environmental variables as strings when outputting files

I am using Get-WindowsAutopilotInfo to generate a computer's serial number and a hash code and export that info as a CSV.
Here is the code I usually use:
new-item "c:\Autopilot_Export" -type directory -force
Set-Location "C:\Autopilot_Export"
Get-WindowsAutopilotInfo.ps1 -OutputFile Autopilot_CSV.csv
Robocopy C:\Autopilot_Export \\Zapp\pc\Hash_Exports /copyall
This outputs a CSV file named "Autopilot_CSV.csv" to the C:\Autopilot_Export directory and then Robocopy copies it to the Network Share drive inside of the Hash_Exports folder listed above. In the above code, if I manually type in "test", "123", "ABC", etc. and replace "Autopilot_CSV" it will output a CSV under all of those names as well. So it looks like Get-WindowsAutopilotInfo will create a CSV file and save the file name with whatever string you pass into it. Great.
However, I am running this script on multiple different computers and I would like the exported CSV to be named something unique to the machine it is running on so I can easily identify it once it's copied. I am trying to pass the value of the environmental variable $env:computername as a string input for the CSV and it isn't working.
Here's the code I'm trying to use:
new-item "c:\Autopilot_Export" -type directory -force
Set-Location "C:\Autopilot_Export"
Get-WindowsAutopilotInfo.ps1 -OutputFile $env:computername.csv
Robocopy C:\Autopilot_Export C:\Users\danieln\Desktop /copyall
This code does not generate the CSV file at all. Why not?
Do I just have a basic misunderstanding of how environmental variables are used in Powershell? $env:computername appears to return a string of the computer's name, but I cannot pass it into Get-WindowsAutopilotInfo and have it save, but it will work if I manually type a string in as the input.
I have also tried setting it to a variable $computername = [string]$env:computername and just passing $computername in before the .CSV and that doesn't appear to work either. And per the docmentation, environmental variables are apparently already strings.
Am I missing something?
Thanks!
js2010's answer shows the effective solution: use "..."-quoting, i.e. an expandable string explicitly.
It is a good habit to form to use "..." explicitly around command arguments that are strings containing variable references (e.g. "$HOME/projects") or subexpressions (e.g., "./folder/$(Get-Date -Format yyyy-MM)")
While such compound string arguments generally do not require double-quoting[1] - because they are implicitly treated as if they were "..."-enclosed - in certain cases they do, and when they do is not obvious and therefore hard to remember:
This answer details the surprisingly complex rules, but here are two notable pitfalls if you do not use "...":
If a compound argument starts with a subexpression ($(...)), its output is passed as a separate argument; e.g. Write-Output $(Get-Location)/folder passes two arguments to Write-Output: the result of $(Get-Location) and literal /folder
If a compound argument starts with a variable reference and is followed by what syntactically looks like either (a) a property access (e.g., $PSVersionTable.PsVersion) or (b) a method call (e.g., $PSHome.Tolower()) it is executed as just that, i.e. as an expression (rather than being considered a variable reference followed by a literal part).
Aside #1: Such an argument then isn't necessarily a string, but whatever data type the property value or method-call return value happens to be.
Aside #2: A compound string that starts with a quoted string (whether single- or double-quoted) does not work, because the quoted string at the start is also considered an expression, like property access and method calls, so that what comes after is again passed as separate argument(s). Therefore, you can only have a compound strings consisting of a mix of quoted and unquoted substrings if the compound string starts with an unquoted substring or a non-expression variable reference.[2]
The latter is what happened in this case:
Unquoted $env:computername.csv was interpreted as an attempt to access a property named csv on the object stored in (environment) variable $env:computername, and since the [string] instance stored there has no csv property, the expression evaluated to $null.
By forcing PowerShell to interpret this value as an expandable string via "...", the usual interpolation rules apply, which means that the .csv is indeed treated as a literal (because property access requires use of $(...) in expandable strings).
[1] Quoting is required for strings that contain metacharacters such as spaces.
For values to be treated verbatim, '...' quoting is the better choice (see the bottom section of this answer for an overview of PowerShell string literals).
Also, using neither double- nor single-quoting and individually `-escaping metacharacters is another option (e.g. Write-Output C:\Program` Files.
[2] For instance, Write-Output a"b`t"'`c' and Write-Output $HOME"b`t"'`c' work as intended, whereas Write-Output "b`t"'`c' and Write-Output $HOME.Length"b`t"'`c' do not (the latter two each pass 3 arguments). The workaround is to either use a single "..." string with internal `-escaping as necessary (e.g. Write-Output "${HOME}b`t``c") or to use string-concatenation expression with + enclosed in (...) (e.g. Write-Output ($HOME + "b`t" + '`c'))
Doublequoting seems to work. The colon is special in powershell parameters.
echo hi | set-content "$env:computername.csv"
dir
Directory: C:\users\me\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2/11/2021 1:02 PM 4 COMP001.csv
The colon is special. For example in switch parameters:
get-childitem -force:$true
Actually, it's trying to find a property named csv:
echo hi | Set-Content $env:COMPUTERNAME.length
dir
Directory: C:\Users\me\foo
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2/11/2021 3:04 PM 4 8
Basically pass it a string rather than the variable:
write-host $env:computername.csv
# output: (no output - looking for a variable called "computername.csv" instead of "computername")
Try the following syntax:
$filename = "$($env:computername).csv"
write-host $filename
# output: MYPCNAME.csv

REG EXPORT single value to .reg file

I want to export a single registry value to a file using PowerShell (eventually scripting to backup a bunch of registry values).
I can view the file with QUERY:
REG QUERY "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa" /v LimitBlankPasswordUse
>>
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa
LimitBlankPasswordUse REG_DWORD 0x1
However, I can't export the single value.
REQ EXPORT has no /v flag, so:
REG EXPORT "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa" \v "LimitBlankPasswordUse" LBPU.reg
ERROR: Invalid syntax.
Doesn't work.
If I try to export the value I get:
REG EXPORT "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\LimitBlankPasswordUse" LBPU.reg
ERROR: The system was unable to find the specified registry key or value.
And if I simply do the folder:
REG EXPORT "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa\" Lsa.reg
The operation completed successfully.
I get a .reg file which includes the correct value:key pair "LimitBlankPasswordUse"=dword:00000001 - but also all the others. Which is no use. I want one pair, not hundreds.
How do I export a single value to a .reg file?
There is no direct way of achieving what you want, and given that you want a .reg file as output, using PowerShell's cmdlets (such as Get-Item, Get-ItemProperty, and Get-ItemPropertyValue) is not an option - unless you're prepared to emulate the .reg file format in all aspects, which is nontrivial both in terms of effort and complexity.[1]
The best approach in your case is to first export the whole key, with reg.exe export, to a temporary file, and then extract and export only the header lines and the data-value pair of interest.
Given that a single data-value pair can span multiple lines, this isn't straightforward, but the following should work robustly (you could wrap it in a function for convenience and reuse):
# Determine the key path and the name of the value to export...
$keyPath = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa'
$valueName = 'LimitBlankPasswordUse'
# ... and the output file path.
$outFile = 'LBPU.reg'
# Create a temporary file and export the whole key to it.
$tempFile = New-TemporaryFile
$null = reg.exe export $keyPath $tempFile /y
# Extract the header lines and the key's *immediate* value children.
# Note: reg.exe export invariably exports *recursively*, so that any
# descendant keys are exported as well, which we want to exclude.
$null = (Get-Content -Raw $tempFile) -match '(?s)^(.+?\])\r\n(.+?)\r\n(?:\r\n|\z)'
Remove-Item $tempFile
# Extract the header lines (format identifier and key path)...
$headerLinesBlock = $Matches[1]
# ... and the key's immediate children as value-data pairs
$valueLinesBlock = $Matches[2]
# Extract the specific value-data pair of interest.
# Note: Such a pair can span *multiple* lines, if "\" is used as the
# line-continuation character at the end of a line, as is common
# with hex. data.
# Continuation lines always start with a *space*, so a data-value pair
# ends either with a new line whose first char. is a non-whitespace char.
# or with the end of the input string.
if ($valueLinesBlock -notmatch "(?sm)^`"$valueName`"=.+?(?=(\r\n\S|\z))") {
throw "Value name not found: $valueName"
}
$valueDataPair = $Matches[0]
# Save the header lines and the data-value pair line(s) to the result file.
# Note that .reg files are "Unicode" (UTF-16LE) files.
$headerLinesBlock, $valueDataPair | Set-Content -Encoding Unicode $outFile
$outFile receives the following content:
Windows Registry Editor Version 5.00
[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa]
"LimitBlankPasswordUse"=dword:00000001
[1] To name a few challenges: REG_DWORD and REG_QWORD values must be represented as hex values, REG_EXPAND_SZ values, when queried with Get-ItemProperty are invariably expanded, so you wouldn't preserve the actual value as stored in the registry; furthermore, REG_EXPAND_SZ and REG_MULTI_SZ values must be represented as types hex(2) and hex(7) in the form of hex byte arrays, respectively.
You haven't used PowerShell at all here. As zett42 said, this is a Get-ItemProperty problem. If you must have a .reg file as the output then you could easily create one providing you have simple case such as this where the output is a single dword. The approach will struggle if you have numerous items and more complex datatypes.
$lsa = Get-ItemProperty "HKLM:\SYSTEM\CurrentControlSet\Control\Lsa" -Name LimitBlankPasswordUse
$path = $lsa.PSPath.Split('::')
Set-Content foo.reg "Windows Registry Editor Version 5.00`r`n`r`n[$($path[2])]`r`n`"LimitBlankPasswordUse`"=dword:$($lsa.LimitBlankPasswordUse)"
You can hard code or script as much as you need depending upon your overall objective. Probably export to CSV and then apply then at the target with Set-ItemProperty.

Display Multiple Characters in MS-DOS output

How do I display multiple characters in a MS-Dos command
So for example, if I want to display everything in a current directory that begins with A, I might type the following command into CMD.
dir/b A*
But what if I want to display everything A-M? How would I go about telling the computer to display multiple characters?
(this is for PowerShell) ls command for listing the current directory and after you add A*.
so the command is ls A*(it will list name starting with a as well).
If you want to filter using regular expression
Get-ChildItem | Where-Object { $_.Name -Match 'RegularExpression' }
A regular expression for starts with a letter is ^[A-M]+.
Change -Match to CMatch for capital sensitive.
Using cmd leaves you two possibilities: list files for each desired letter:
dir /b a* b* c* d* ... m*
which is awkward and inflexible because of hardcoding the list. Even using a for loop isn't better:
for %a in (a b c d e ... m) do #dir /b %a*
This might work fine if you want just two or three letters.
The second (much more flexible and probably faster too) method: get the whole list and just filter it:
dir /b | findstr /rib "[a-m]"
For not-consecutive letters (a*, b*, m*, n*, x*, y*):
dir /b | findstr /rib "[abmnxy]"