Powershell 和注册表:如何按值而不是名称查询(默认| 字符串?

问题描述 投票:0回答:1

所以,我正在编写一个脚本来获取注册表中的项目并删除它们,如下所示:

Get-ChildItem -Path "HKLM:\SOFTWARE\Classes" -Recurse -Include *optane* | Remove-Item -Recurse -Force

现在,我遇到了一个问题,注册表值(例如,optane)位于字符串的值中,但字符串本身被命名为(默认)。我查询字符串本身没有问题,但是当它被列为默认值时,我(当然)没有得到任何结果。如何通过字符串的值而不是字符串的名称来查询结果?

[Sample Registry Entry]

我还没有尝试过任何东西,因为我不确定语法。请注意,在本例中,我尝试这样做是因为我想实际删除包含该项目的 GUID 文件夹,而不必查找 GUID 本身。我有非常具体的选项可以用来防止它变得危险。

编辑:在使用了一些代码之后,我尝试了这个,这样我就可以获得字段名称和属性:

并得到以下回复:

这告诉我,我可以很好地获取其属性中包含“Intel.Optane.Pinning”的任何 ProgId。我想查询包含该值的任何 ProgID,然后删除包含该值的键。

powershell registry
1个回答
0
投票

要按值搜索,您必须首先获取指定路径中的所有键/子键。获得密钥后,您必须仔细检查每个密钥并获取密钥值和数据。如果整个键(和子键)的任何值数据包含指定的搜索词,则整个键(和子键)将被删除。

$searchRegKeyValue = "*test123*"
$myPath = "REGISTRY::HKCR\"
# $mypath = "REGISTRY::HKLM:\Software\"
$childItems = Get-ChildItem -Path $myPath -Recurse -ErrorAction SilentlyContinue

# go through each key in the reg path specified
foreach ($key in $childItems){
    # for each value of the key get it's value and compare against the search term
    foreach ($name in $key.GetValueNames()){
        if ($key.GetValue($name) -like $searchRegKeyValue){       
            # Get-Item -Path $key.pspath
            Remove-Item -Path $key.pspath -Recurse -WhatIf
        }
    }
}

如果没有很多键/子键需要执行,上述解决方案效果很好,但可能会变慢,特别是如果您指定顶级路径 (

"REGISTRY::HKCR\" vs "REGISTRY::HKCR\CLSID"
)。

我发现了一个非常有趣的解决方案来加速 powershell 中的注册表搜索这里。因此,我对解决方案进行了一些修改以适应此用例。对于较大的搜索集,使用此解决方案的速度提升更为明显。我发现在较大的搜索集上加速了 50% 以上,但在较小的搜索集上则更接近。对于我的原始解决方案,搜索 HKCR:\ 需要 293 秒,而使用链接的解决方案则需要 101 秒。

波纹管来自修改后的链接解决方案,以删除具有与

$search
匹配的值的键。我必须在搜索中更改一些内容,以解决空的
$subKey
从根级别搜索的问题,但除此之外基本上是相同的。

# [email protected]
# reference: https://msdn.microsoft.com/de-de/vstudio/ms724875(v=vs.80)

cls
remove-variable * -ea 0
$ErrorActionPreference = "stop"

$signature = @'
[DllImport("advapi32.dll")]
public static extern Int32 RegOpenKeyEx(
    UInt32 hkey,
    StringBuilder lpSubKey,
    int ulOptions,
    int samDesired,
    out IntPtr phkResult
    );

[DllImport("advapi32.dll")]
public static extern Int32 RegQueryInfoKey(
    IntPtr hKey,
    StringBuilder lpClass, Int32 lpCls, Int32 spare, 
    out int subkeys, out int skLen, int mcLen, out int values,
    out int vNLen, out int mvLen, int secDesc,                
    out System.Runtime.InteropServices.ComTypes.FILETIME lpftLastWriteTime
);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern Int32 RegEnumValue(
  IntPtr hKey,
  int dwIndex,
  IntPtr lpValueName,
  ref IntPtr lpcchValueName,
  IntPtr lpReserved,
  out IntPtr lpType,
  IntPtr lpData,
  ref int lpcbData
);

[DllImport("advapi32.dll", CharSet = CharSet.Unicode)]
public static extern Int32 RegEnumKeyEx(
  IntPtr hKey,
  int dwIndex,
  IntPtr lpName,
  ref int lpcName,
  IntPtr lpReserved,
  IntPtr lpClass,
  int lpcClass,
  out System.Runtime.InteropServices.ComTypes.FILETIME lpftLastWriteTime
);

[DllImport("advapi32.dll")]
public static extern Int32 RegCloseKey(IntPtr hkey);
'@ 
$reg = add-type $signature -Name reg -Using System.Text -PassThru
$marshal = [System.Runtime.InteropServices.Marshal]

function search-RegistryTree($path) {
    if(($path -ne "") -and !($path.EndsWith("\"))){
        $path +=  "\"
 
    }


    # open the key:
    [IntPtr]$hkey = 0
    $result = $reg::RegOpenKeyEx($global:hive, $path, 0, 25 ,[ref]$hkey)
    if ($result -eq 0) {

        # get details of the key:
        $subKeyCount  = 0
        $maxSubKeyLen = 0
        $valueCount   = 0
        $maxNameLen   = 0
        $maxValueLen  = 0
        $time = $global:time
        $result = $reg::RegQueryInfoKey($hkey,$null,0,0,[ref]$subKeyCount,[ref]$maxSubKeyLen,0,[ref]$valueCount,[ref]$maxNameLen,[ref]$maxValueLen,0,[ref]$time)
        if ($result -eq 0) {
           $maxSubkeyLen += $maxSubkeyLen+1
           $maxNameLen   += $maxNameLen  +1
           $maxValueLen  += $maxValueLen +1
        }

        # enumerate the values:
        if ($valueCount -gt 0) {
            $type = [IntPtr]0
            $pName  = $marshal::AllocHGlobal($maxNameLen)
            $pValue = $marshal::AllocHGlobal($maxValueLen)
            
            foreach ($index in 0..($valueCount-1)) {
                $nameLen  = $maxNameLen
                $valueLen = $maxValueLen
                $result = $reg::RegEnumValue($hkey, $index, $pName, [ref]$nameLen, 0, [ref]$type, $pValue, [ref]$valueLen)
                if ($result -eq 0) {
                    $name = $marshal::PtrToStringUni($pName)
                    $value = switch ($type) {
                        1 {$marshal::PtrToStringUni($pValue)}
                        2 {$marshal::PtrToStringUni($pValue)}
                        3 {$b = [byte[]]::new($valueLen)
                           $marshal::Copy($pValue,$b,0,$valueLen)
                           if ($b[1] -eq 0 -and $b[-1] -eq 0 -and $b[0] -ne 0) {
                                [System.Text.Encoding]::Unicode.GetString($b)
                           } else {
                                [System.Text.Encoding]::UTF8.GetString($b)}
                           }
                        4 {$marshal::ReadInt32($pValue)}
                        7 {$b = [byte[]]::new($valueLen)
                           $marshal::Copy($pValue,$b,0,$valueLen)
                           $msz = [System.Text.Encoding]::Unicode.GetString($b)
                           $msz.TrimEnd(0).split(0)}
                       11 {$marshal::ReadInt64($pValue)}
                    }
                    # if ($name -match $global:search) {
                    #     write-host "$path\$name : $value"
                    #     $global:hits++
                    # } elseif ($value -match $global:search) {
                    #     write-host "$path\$name : $value"
                    #     $global:hits++
                    # }

                    # only find keys based on matched value data
                    if  ($value -match $global:search) {
                            write-host "$path$name : $value"
                            $item = "$path : $value"
                            $keyList.Add($item)
                            $global:hits++                           
                        }
                }
            }
            $marshal::FreeHGlobal($pName)
            $marshal::FreeHGlobal($pValue)
        }

        # enumerate the subkeys:
        if ($subkeyCount -gt 0) {
            $subKeyList = @()
            $pName = $marshal::AllocHGlobal($maxSubkeyLen)
            $subkeyList = foreach ($index in 0..($subkeyCount-1)) {
                $nameLen = $maxSubkeyLen
                $result = $reg::RegEnumKeyEx($hkey, $index, $pName, [ref]$nameLen,0,0,0, [ref]$time)
                if ($result -eq 0) {
                    $marshal::PtrToStringUni($pName)
                }
            }
            $marshal::FreeHGlobal($pName)
        }

        # close:
        $result = $reg::RegCloseKey($hkey)

        # get Tree-Size from each subkey:
        $subKeyValueCount = 0
        if ($subkeyCount -gt 0) {
            foreach ($subkey in $subkeyList) {
                if (!($subkey.EndsWith("\"))){
                    $subKeyValueCount += search-RegistryTree "$path$subkey\"
                }
                else{
                    $subKeyValueCount += search-RegistryTree "$path$subkey"
                }
            }
        }
        return ($valueCount+$subKeyValueCount)
    }
}
function remove-keys ($keyList){

    Write-Output "The following KEYS will be removed: "
    foreach ($key in $keyList){
        $value = $key.split(":")[1]
        $key = $key.split(":")[0].TrimEnd()
        Get-Item -Path "$root\$key" 
       
    }
    foreach ($key in $keyList){
        $value = $key.split(":")[1]
        $key = $key.split(":")[0].TrimEnd()
        # Get-Item -Path "$root\$key" 
        Remove-Item -Path "$root\$key"  -Recurse -WhatIf
    }

}

$timer = [System.Diagnostics.Stopwatch]::new()
$timer.Start()


# setting global variables:
$search = "test123"

#needs to change depending on the location you are searching
# $hive   = [uint32]"0x80000002" #HKLM
$hive   = [uint32]"0x80000000" #HKCR

# $root = "REGISTRY::HKEY_LOCAL_MACHINE"
$root = "REGISTRY::HKEY_CLASSES_ROOT"

# to search from the root level of the hive you selected
$subkey = ""
# $subkey = "CLSID"
$time   = New-Object System.Runtime.InteropServices.ComTypes.FILETIME
$hits   = 0
$keyList =   [System.Collections.Generic.List[string]]::new()

write-host "We start searching for pattern '$search' in Registry-Path '$subkey' ...`n"
$count = search-RegistryTree $subkey
Write-Output $values
$timer.stop()
$sec = [int](100 * $timer.Elapsed.TotalSeconds)/100
write-host "`nWe checked $count reg-values in $sec seconds. Number of hits = $hits."

remove-keys $keyList

在这两种解决方案中,当使用

-whatIf
实际删除项目时,您都需要删除
remove-item
。为了安全我只是把它留在这里。如果存在匹配,它将删除该密钥以及该密钥的任何子密钥。我建议在删除
-whatIf
之前先测试您的搜索词,以确保它与您要删除的内容匹配。

© www.soinside.com 2019 - 2024. All rights reserved.