使用PowerShell在注册表项和值中搜索字符串

时间:2017-03-22 22:15:07

标签: powershell

我想使用PowerShell查找包含字符串foo的特定配置单元中的所有注册表项和值,可能嵌入在更长的字符串中。找到钥匙并不难:

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

问题是我不知道找到值的最佳方法,因为我不知道提前属性的名称。我试过这个:

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

但得到了这个错误:

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

即使我将-ErrorAction SilentlyContinue添加到get-itemproperty

此外,它只能找到(default)键的值。

此外,是否可以在单个命令中搜索所有配置单元?

3 个答案:

答案 0 :(得分:3)

每个密钥都有GetValueNames()GetValueKind()GetValue()方法,可以枚举子值。您也可以使用GetSubKeyNames()而非依赖Get-ChildItem -Recurse来枚举密钥。

要回答有关搜索多个配置单元的问题:如果您从Get-ChildItem Registry::\开始,则可以查看所有配置单元并在那里开始搜索。您可能希望坚持使用HKLM和HKCU(如果装有其他用户配置单元,则可能是HKU)。

这是我在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" 
                            } 
                        } 
                    } 
                } 
        } 
    } 
} 

我暂时没有看过它,我肯定可以看到它的某些部分应该改变以使其更好,但它应该作为你的起点。

答案 1 :(得分:1)

这是get-itemproperty的替代,它以一种简单的方式转储了注册表。与where-object一起使用很容易。您也可以通过管道将其传递给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

答案 2 :(得分:0)

这里是通过Powershell超快速执行注册表搜索的情况,以防您需要扫描注册表的大部分内容: https://stackoverflow.com/a/55853204