如何在PowerShell中按名称和值过滤注册表项下的名称/值对?

时间:2013-07-24 15:03:43

标签: powershell registry powershell-v3.0

我试图了解在PowerShell中使用的习语。

鉴于此脚本:

$path = 'hkcu:\Software\Microsoft\Windows\CurrentVersion\Extensions'
$key = Get-Item $path
$key

我在这个问题的底部得到了输出。

我想获取属性的输出($key下的名称/值对),我可以在其中过滤名称和值。

例如,过滤以列出所有具有以下内容的扩展程序:

  • 名称如xls*
  • 或类似*\MSACCESS.EXE
  • 的值

或排除过滤器:排除doc*

等所有名称

对第一个过滤器,我想要一个像这样的结果:

Name                           Value                                                                                                                                                       
----                           --------                                                                                                                                                       
xlsx                           C:\PROGRA~2\MICROS~1\Office15\EXCEL.EXE                                                                                                                 
xls                            C:\PROGRA~2\MICROS~1\Office15\EXCEL.EXE                                                                                                                 
mdb                            C:\PROGRA~2\MICROS~1\Office15\MSACCESS.EXE                                                                                                              
mda                            C:\PROGRA~2\MICROS~1\Office15\MSACCESS.EXE                                                                                                              

这是脚本的原始输出:

Hive: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion
Name                           Property                                                                                                                                                       
----                           --------                                                                                                                                                       
Extensions                     rtf  : C:\PROGRA~2\MICROS~1\Office15\WINWORD.EXE ^.rtf                                                                                                         
                               dot  : C:\PROGRA~2\MICROS~1\Office15\WINWORD.EXE ^.dot                                                                                                         
                               dotm : C:\PROGRA~2\MICROS~1\Office15\WINWORD.EXE ^.dotm                                                                                                        
                               dotx : C:\PROGRA~2\MICROS~1\Office15\WINWORD.EXE ^.dotx                                                                                                        
                               docm : C:\PROGRA~2\MICROS~1\Office15\WINWORD.EXE ^.docm                                                                                                        
                               docx : C:\PROGRA~2\MICROS~1\Office15\WINWORD.EXE ^.docx                                                                                                        
                               doc  : C:\PROGRA~2\MICROS~1\Office15\WINWORD.EXE ^.doc                                                                                                         
                               xlsx : C:\PROGRA~2\MICROS~1\Office15\EXCEL.EXE                                                                                                                 
                               xls  : C:\PROGRA~2\MICROS~1\Office15\EXCEL.EXE                                                                                                                 
                               mdb  : C:\PROGRA~2\MICROS~1\Office15\MSACCESS.EXE                                                                                                              
                               mda  : C:\PROGRA~2\MICROS~1\Office15\MSACCESS.EXE                                                                                                              

修改

我解决了部分问题:获取名称/值对列表。它使用PSCustomObject

$namevalues = $key.GetValueNames() | ForEach-Object { [pscustomobject]@{ Name=$_; Value=$key.GetValue($_) } }
$namevalues

(我应该如何包装该代码?)

非常感谢任何有关过滤的帮助

3 个答案:

答案 0 :(得分:5)

两部分答案。

我们从注册表中的$key开始:

$path = 'hkcu:\Software\Microsoft\Windows\CurrentVersion\Extensions'
$key = Get-Item $path
$key
$key | Get-Member

由于$keyMicrosoft.Win32.RegistryKey,您无法直接获取名称值对。

第一步是创建PSCustomObjectsName / Value对的列表。 Name来自GetValueNames管道ForEach-Object。对于每个名称,我们都会获得ValueGetValue

$namevalues = $key.GetValueNames() | 
  ForEach-Object { 
    [PSCustomObject] @{ 
      Name = $_; 
      Value = $key.GetValue($_) 
    } 
  }
$namevalues | Format-Table

第一步的替代方法是使用Select-Object使用-ExpandPropertyScott Saad解释:

$namevalues = $key | Select-Object -ExpandProperty Property | 
  ForEach-Object { 
    [PSCustomObject] @{ 
      Name = $_; 
      Value = $key.GetValue($_) 
    } 
  }
$namevalues | Format-Table

第二步是按$namevaluesName过滤Value

Where-Object有一些非常酷的Comparison运营商,accept regular expressions喜欢matchnotMatch等。

为了使代码更具可读性,您可以wrap lines(感谢Joey!)使用反引号(`)或利用PowerShell语法中的地方接受换行符,比如在管道(|)或左大括号({)之后:

$matches = $namevalues | 
  Where-Object { 
    $_.Name -match '^xls' `
    -or $_.Value -match 'msaccess.exe$' 
  }
$matches | Format-Table

结果如预期所示:

Name    Value                                                                                         
----    -----                                                                                         
xlsx    C:\PROGRA~2\MICROS~1\Office15\EXCEL.EXE                                                       
xls     C:\PROGRA~2\MICROS~1\Office15\EXCEL.EXE                                                       
mdb     C:\PROGRA~2\MICROS~1\Office15\MSACCESS.EXE                                                    
mda     C:\PROGRA~2\MICROS~1\Office15\MSACCESS.EXE

答案 1 :(得分:4)

有一种更聪明的方法可以枚举注册表值(找到它here)。而且它更像是PowerShell-way IMO。

我把它变成了一个单行:

(Get-ItemProperty $path).psobject.properties | 
   where {$_.name -like "xls*" -or $_.value -like "*\MSACCESS.EXE"} | 
      select name,value

更新:正如@ mklement0的评论中所述,您应该注意属性PSPathPSParentPathPSChildNamePSDrive,和PSProvider中的psobject.properties

答案 2 :(得分:0)

montonero's helpful answer更强大的PSv4 +替代方案 [1]

Get-Item $path -PipelineVariable key | ForEach-Object Property |
  ForEach-Object {
    $name = ($_, '')[$_ -eq '(default)'] # translate '(default)' to '' for API calls
    if (
         $name -like 'xls*' -or 
         ($value = $key.GetValue($name)) -like "*\MSACCESS.EXE"
       ) { [pscustomobject] @{ Name = $name; Value = $value } }
 }
  • -PipelineVariable key[Microsoft.Win32.RegistryKey]返回的Get-Item实例存储在变量$key中,以供以后在管道中使用。

  • ForEach-Object Property枚举目标键的值名称(通过PowerShell添加到输出.Property实例的[Microsoft.Win32.RegistryKey] note属性)。

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

    • 重要:在.Property数组中,PowerShell转换默认值名称,它是空字符串({{ 1}})在API级别上,命名为'';因此,如果'(default)'$_,则必须在调用'(default)'之前将其转换为'',这是
      $_.GetValue(<valueName>)的作用。
  • ($_, '')[$_ -eq '(default)']然后构造并输出一个[pscustomobject] @{ ... }实例,该实例具有[pscustomobject].Name属性,它们反映匹配值的名称和数据。


[1] montonero's answer简洁明了,适用于当前情况,但有一些警告:

PowerShell的注册表提供程序自动添加以下包含元数据(类型为.Value的成员,反映在NoteProperty的输出中) >关于Get-Member输出的[pscustomobject]实例的目标注册表项

  • Get-ItemPropertyPSPathPSParentPathPSChildNamePSDrive

这些可以通过两种方式干扰基于PSProvider 的过滤:

  • 再次使用通配符匹配.psobject.properties可能会意外地包含这些属性。

    • 例如,$_.Name会与$_.Name -like '*drive*'属性匹配,即使它实际上不是注册表项的一部分。
  • 也许更假设,如果注册表项恰好具有与这些提供程序属性相同的名称,则提供程序属性 shadow (覆盖)这些值。

    • 例如,如果键的值为PSDrive,则PSPath将报告 provider 属性值。