Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use PowerShell to search for string in registry keys and values

Tags:

powershell

I'd like to use PowerShell to find all registry keys and values within a particular hive that contain a string foo, possibly embedded within a longer string. Finding the keys is not hard:

Get-ChildItem -path hkcu:\ -recurse -ErrorAction SilentlyContinue | Where-Object {$_.Name -like "*foo*"}

The problem is that I don't know the best way to find the values, given that I don't know the names of the properties ahead of time. I tried this:

Get-ChildItem -path hkcu:\ -recurse -erroraction silentlycontinue | get-itemproperty | where {$_.'(default)' -like "*foo*"}    

But I got this error:

get-itemproperty : Specified cast is not valid.
At line:1 char:69
+ ... u:\ -recurse -erroraction silentlycontinue | get-itemproperty | where ...
+                                                  ~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Get-ItemProperty], InvalidCastException
    + FullyQualifiedErrorId : System.InvalidCastException,Microsoft.PowerShell.Commands.GetItemPropertyCommand

even when I added -ErrorAction SilentlyContinue to the get-itemproperty.

Furthermore, that only finds the values of the (default) keys.

Also, is it possible to search all hives within a single command?

like image 808
Alan Avatar asked Mar 22 '17 22:03

Alan


People also ask

How do I query a registry key in PowerShell?

One of the easiest ways to find registry keys and values is using the Get-ChildItem cmdlet. This uses PowerShell to get a registry value and more by enumerating items in PowerShell drives. In this case, that PowerShell drive is the HKLM drive found by running Get-PSDrive .

How do I browse the registry in PowerShell?

You can browse the registry tree the same way you navigate your drives. HKLM:\ and HKCU:\ are used to access a specific registry hive. Those, you can access the registry key and their parameters using the same PowerShell cmdlets that you use to manage files and folders.

How do you locate keys and their values in the registry?

Regedit lets you search using the Find feature in the Windows Registry. To access it, you have to click on Edit menu and select Find. The Find box will let you search for items in the Windows Registry, and this includes Keys, Values, and Data. You can also set it to match whole strings only.


2 Answers

Each key has a GetValueNames(), GetValueKind(), and GetValue() method that let you enumerate child values. You can also use the GetSubKeyNames() instead of depending on Get-ChildItem -Recurse to enumerate keys.

To answer your question about searching multiple hives: if you start with Get-ChildItem Registry::\, you can see all hives and start your search there. You'll probably want to stick with HKLM and HKCU (maybe HKU if there are other user hives loaded).

Here's a sample implementation that I created a while back on the TechNet gallery:

function Search-Registry { 
<# 
.SYNOPSIS 
Searches registry key names, value names, and value data (limited). 

.DESCRIPTION 
This function can search registry key names, value names, and value data (in a limited fashion). It outputs custom objects that contain the key and the first match type (KeyName, ValueName, or ValueData). 

.EXAMPLE 
Search-Registry -Path HKLM:\SYSTEM\CurrentControlSet\Services\* -SearchRegex "svchost" -ValueData 

.EXAMPLE 
Search-Registry -Path HKLM:\SOFTWARE\Microsoft -Recurse -ValueNameRegex "ValueName1|ValueName2" -ValueDataRegex "ValueData" -KeyNameRegex "KeyNameToFind1|KeyNameToFind2" 

#> 
    [CmdletBinding()] 
    param( 
        [Parameter(Mandatory, Position=0, ValueFromPipelineByPropertyName)] 
        [Alias("PsPath")] 
        # Registry path to search 
        [string[]] $Path, 
        # Specifies whether or not all subkeys should also be searched 
        [switch] $Recurse, 
        [Parameter(ParameterSetName="SingleSearchString", Mandatory)] 
        # A regular expression that will be checked against key names, value names, and value data (depending on the specified switches) 
        [string] $SearchRegex, 
        [Parameter(ParameterSetName="SingleSearchString")] 
        # When the -SearchRegex parameter is used, this switch means that key names will be tested (if none of the three switches are used, keys will be tested) 
        [switch] $KeyName, 
        [Parameter(ParameterSetName="SingleSearchString")] 
        # When the -SearchRegex parameter is used, this switch means that the value names will be tested (if none of the three switches are used, value names will be tested) 
        [switch] $ValueName, 
        [Parameter(ParameterSetName="SingleSearchString")] 
        # When the -SearchRegex parameter is used, this switch means that the value data will be tested (if none of the three switches are used, value data will be tested) 
        [switch] $ValueData, 
        [Parameter(ParameterSetName="MultipleSearchStrings")] 
        # Specifies a regex that will be checked against key names only 
        [string] $KeyNameRegex, 
        [Parameter(ParameterSetName="MultipleSearchStrings")] 
        # Specifies a regex that will be checked against value names only 
        [string] $ValueNameRegex, 
        [Parameter(ParameterSetName="MultipleSearchStrings")] 
        # Specifies a regex that will be checked against value data only 
        [string] $ValueDataRegex 
    ) 

    begin { 
        switch ($PSCmdlet.ParameterSetName) { 
            SingleSearchString { 
                $NoSwitchesSpecified = -not ($PSBoundParameters.ContainsKey("KeyName") -or $PSBoundParameters.ContainsKey("ValueName") -or $PSBoundParameters.ContainsKey("ValueData")) 
                if ($KeyName -or $NoSwitchesSpecified) { $KeyNameRegex = $SearchRegex } 
                if ($ValueName -or $NoSwitchesSpecified) { $ValueNameRegex = $SearchRegex } 
                if ($ValueData -or $NoSwitchesSpecified) { $ValueDataRegex = $SearchRegex } 
            } 
            MultipleSearchStrings { 
                # No extra work needed 
            } 
        } 
    } 

    process { 
        foreach ($CurrentPath in $Path) { 
            Get-ChildItem $CurrentPath -Recurse:$Recurse |  
                ForEach-Object { 
                    $Key = $_ 

                    if ($KeyNameRegex) {  
                        Write-Verbose ("{0}: Checking KeyNamesRegex" -f $Key.Name)  

                        if ($Key.PSChildName -match $KeyNameRegex) {  
                            Write-Verbose "  -> Match found!" 
                            return [PSCustomObject] @{ 
                                Key = $Key 
                                Reason = "KeyName" 
                            } 
                        }  
                    } 

                    if ($ValueNameRegex) {  
                        Write-Verbose ("{0}: Checking ValueNamesRegex" -f $Key.Name) 

                        if ($Key.GetValueNames() -match $ValueNameRegex) {  
                            Write-Verbose "  -> Match found!" 
                            return [PSCustomObject] @{ 
                                Key = $Key 
                                Reason = "ValueName" 
                            } 
                        }  
                    } 

                    if ($ValueDataRegex) {  
                        Write-Verbose ("{0}: Checking ValueDataRegex" -f $Key.Name) 

                        if (($Key.GetValueNames() | % { $Key.GetValue($_) }) -match $ValueDataRegex) {  
                            Write-Verbose "  -> Match!" 
                            return [PSCustomObject] @{ 
                                Key = $Key 
                                Reason = "ValueData" 
                            } 
                        } 
                    } 
                } 
        } 
    } 
} 

I haven't looked at it in a while, and I can definitely see some parts of it that should be changed to make it better, but it should work as a starting point for you.

like image 170
Rohn Edwards Avatar answered Oct 26 '22 13:10

Rohn Edwards


This is a replacement for get-itemproperty that dumps out the registry in a simple manner. It's easy to use with where-object. You can also pipe it to set-itemproperty.

function get-itemproperty2 {
  # get-childitem skips top level key, use get-item for that
  # set-alias gp2 get-itemproperty2
  param([parameter(ValueFromPipeline)]$key)
  process {
    $key.getvaluenames() | foreach-object {
      $value = $_
      [pscustomobject] @{
        Path = $Key -replace 'HKEY_CURRENT_USER',
          'HKCU:' -replace 'HKEY_LOCAL_MACHINE','HKLM:'
        Name = $Value
        Value = $Key.GetValue($Value)
        Type = $Key.GetValueKind($Value)
      }
    }
  }
}


ls -r hkcu:\key1 | get-itemproperty2 | where name -eq name

Path            Name Value  Type
----            ---- -----  ----
HKCU:\key1\key2 name     1 DWord


ls -r hkcu:\key1 | get-itemproperty2 | where name -eq name | set-itemproperty -value 0
ls -r hkcu:\key1 | get-itemproperty2 | where name -eq name

Path            Name Value  Type
----            ---- -----  ----
HKCU:\key1\key2 name     0 DWord


# pipe 2 commands to one
$(get-item hkcu:\key1; ls -r hkcu:\key1 ) | get-itemproperty2

Path                 Name  Value               Type
----                 ----  -----               ----
HKCU:\key1           multi {hi, there}  MultiString
HKCU:\key1\key2      name  0                  DWord
HKCU:\key1\key2      name2 0                 String
HKCU:\key1\key2\key3 name3 {18, 52, 80}      Binary

EDIT:

This where construction isn't bad for searching both property names and values (and the key name is a value). (Watch out for Netbeans. It creates an invalid registry dword key that causes an exception in get-itemproperty.)

get-childitem -recurse HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | 
  get-itemproperty | where { $_  -match 'Office16.PROPLUS' }
like image 25
js2010 Avatar answered Oct 26 '22 15:10

js2010