如何使用 PowerShell 删除 REG_DWORD 注册表值,其中注册表值如“*String*”?

How to delete REG_DWORD registry value where registry value like '*String*' using PowerShell?

PowerShell 在其父注册表项的 $\_.Property 中将注册表值(及其注册表数据)显示为数组。如何 select 并仅删除值类似于 \*String\* 的注册表值?

我曾尝试在 Whosebug 和 Google 上搜索高价和低价,尝试了很多涉及 Get-ItemGet-ItemPropertyGet-ChildItemSelect-Object 的组合(包括 -ExpandProperty 参数)和 Where-Object 到 select 我想要的注册表值(在继续合并删除之前)。我现在处于完全无能为力的地步,无法弄清楚如何简单地找到特定注册表项中存在的 \*Text\* 之类的注册表值并将其删除。如此简单的事情似乎如此困难!我不知道如何处理数组中的数据!

Get-Item -Path HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs

注册表项 HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs 的每个注册表值都列为 $\_.Property 下数组的一部分。我期待的结果是我可以做一些大致类似于 $\_.RegistryValue -Like '\*Text\*' | Remove-Item 的事情来删除匹配 \*Text\*.

的注册表值

为了确保某些词汇的技术用法正确,"registry key" 在 regedit.exe 中显示为一个文件夹。

A "registry value" 是任何类型的条目,例如 REG\_SZREG\_DWORDREG\_MZ 等。注册表值包含 "registry data",根据注册表类型,它可能是一个字符串,一个 32 位值(有时表示为 1、0 或 0x000000、0x000001)。

我们经常将 "registry values" 称为 'registry keys'(这是不正确的技术用法),将 "registry data" 称为 'registry values'(也是不正确的技术用法),并且 "registry keys" 作为 folders/location/"this place in the registry".

仅按值名称过滤器删除注册表值:

更新,根据自己的简化:

# The target registry key's full path.
$keyPath = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs'

# Pass the value name pattern to Remove-ItemProperty's -Name parameter.
# Remove `-WhatIf` if the preview suggests that the operation works as intended.
Remove-ItemProperty -Path $keyPath -Name *Text* -WhatIf

陷阱:如果你想使用通配符表达式比如*Text*-Name,你必须将其与 -Path 而不是 -LiteralPath 组合,即使键路径本身不是通配符;
-LiteralPath-Name 也按字面意思(逐字)。

如果确实需要使用 -LiteralPath(例如,如果文字路径包含 * 字符,例如 HKEY_CLASSES_ROOT\*):

# The target registry key's full path.
$keyPath = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs'

# Get an array of all value names that match the name wildcard pattern.
$valueNames = (Get-Item -LiteralPath $keyPath).Property -like '*Text*'

# Pass the array of value names to Remove-ItemProperty's -Name parameter.
# Remove `-WhatIf` if the preview suggests that the operation works as intended.
if ($valueNames) {
  Remove-ItemProperty -LiteralPath $keyPath -Name $valueNames -WhatIf
}

注意使用 Get-Item 而不是 Get-ItemProperty[1]

Get-Item returns 代表整个键的对象,类型为 [Microsoft.Win32.RegistryKey],PowerShell 用 .Property 注释 属性 装饰,其中包含所有键值名称的数组。

重要:在.Property数组中,PowerShell翻译默认值名称,即empty string ('') 在 API 级别,进入名称 '(default)'.

将运算符 -like 应用于 array LHS 使其充当 filter 只有 returns a匹配项的子数组。

Remove-ItemProperty-Name 参数直接接受 数组 的 属性(注册表值)名称以从目标键中删除。


正在按值名称删除值 and/or 数据过滤器:

注意:由于使用了-PipelineVariable公共参数,此解决方案需要PSv4+。

# The target registry key's full path.
$keyPath = 'HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\SharedDLLs'

$pattern = '*Text*'

# Look for $pattern in both the name and the data.
# Remove `-WhatIf` if the preview suggests that the operation works as intended.
Get-Item -LiteralPath $keyPath -PipelineVariable key |
  ForEach-Object Property | 
    Where-Object { 
      $valueName = ($_, '')[$_ -eq '(default)'] # translate '(default)' to '' for API
      $valueName -like $pattern -or $key.GetValue($valueName) -like $pattern 
    } |
      Remove-ItemProperty -LiteralPath $keyPath -WhatIf
  • -PipelineVariable keyGet-Item 返回的 [Microsoft.Win32.RegistryKey] 实例存储在变量 $key 中供以后在管道中使用。

  • ForEach-Object Property 枚举目标键的值名称(通过 .Property 注释 属性 PowerShell 添加到输出 [Microsoft.Win32.RegistryKey] 实例,如讨论的那样) .

  • Where-Object脚本块中,$_然后引用手头的值名称,$key.GetValue(<valueName>)用于检索关联数据。

    • 重要:在.Property数组中,PowerShell翻译默认值名称,即empty string ('') 在 API 级别,进入名称 '(default)';因此,如果 $_'(default)',您必须在调用 $_.GetValue(<valueName>) 之前将其转换为 '',这就是
      ($_, '')[$_ -eq '(default)'] 所做的。
  • 然后将任何符合条件的值名称通过管道传输到 Remove-ItemProperty,这会将这些名称隐式绑定到其 -Name 参数。

如果您只想列出匹配值及其数据,请参阅this answer


[1] Get-ItemProperty -Path $keyPath -Name *Text* 在技术上也有效,但输出是 类型 [pscustomobject] 的单个对象 ,其 你必须通过反射枚举的属性,因为属性名称反映了匹配的值名称;虽然通过 this answer 中所示的 .psobject.properties 可以工作并允许您也通过 data 进行过滤,但陷阱是 PowerShell 的注册表提供程序会自动将其自己的属性添加到属性集合,即 PSPathPsParentPathPSChildNamePSDrivePSProvider,这意味着按名称过滤的通配符表达式可能会意外包含它们或者,更糟糕的是,如果键上恰好存在同名的值(即使不太可能),提供者属性会覆盖它们。

注册表提供商太糟糕了。我只希望 get-itemproperty 像这样工作:

# get-itemproperty2.ps1

# get-childitem skips top level key, use get-item
# can't remove default name
param([parameter(ValueFromPipeline)]$key)

process { 
  $valuenames = $key.getvaluenames() 

  if ($valuenames) { 
    $valuenames | foreach {
      $value = $_
      [pscustomobject] @{
        Path = $key -replace 'HKEY_CURRENT_USER',
          'HKCU:' -replace 'HKEY_LOCAL_MACHINE','HKLM:'
        Name = $Value
        Value = $Key.GetValue($Value)
        Type = $Key.GetValueKind($Value)
      }
    }
  } else {
    [pscustomobject] @{
      Path = $key -replace 'HKEY_CURRENT_USER',
        'HKCU:' -replace 'HKEY_LOCAL_MACHINE','HKLM:'
        Name = ''
        Value = ''
        Type = ''
    }
  }
}

然后你可以这样做:

PS C:\users\me> get-item hkcu:\key1 | get-itemproperty2

Path       Name  Value    Type
----       ----  -----    ----
HKCU:\key1 name1 value1 String
HKCU:\key1 name2 value2 String


PS C:\users\me> get-item hkcu:\key1 | get-itemproperty2 | where name -eq name1

Path       Name  Value    Type
----       ----  -----    ----
HKCU:\key1 name1 value1 String


PS C:\users\me> get-item hkcu:\key1 | get-itemproperty2 | where name -eq name1 | Remove-ItemProperty -whatif
What if: Performing the operation "Remove Property" on target "Item: HKEY_CURRENT_USER\key1 Property: name1".


PS C:\users\me> get-childitem -recurse hkcu:\key1 | get-itemproperty2

Path                      Name  Value     Type
----                      ----  -----     ----
HKCU:\key1\key2           name2 value2  String
HKCU:\key1\key2                 default String
HKCU:\key1\key2\key3      name3 value3  String
HKCU:\key1\key2\key3\key4