Search code examples
powershellcmdregistryregedit

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


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?


Solution

  • 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
    ...