How to filter name / value pairs in a registry key by name and value in PowerShell?

I'm trying to figure out which idioms to use in PowerShell.

Given this script:

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

I get a conclusion at the bottom of this question.

I would like to get the output of the properties (name / value pairs under $key ), where I can filter by name and value.

For example, a filter to display all extensions that have:

  • name like xls*
  • or a value similar to *\MSACCESS.EXE

Or an exception filter: exclude all names, for example doc*

The first filter, I would like to get this result:

 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 

This is the original script output:

 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 

Edit

I solved a part of the problem: get a list of Name / Value pairs. It uses PSCustomObject :

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

(How do I wrap this code?)

Any help with filtering would be much appreciated

+4
source share
3 answers

There is a much smarter way to list registry values ​​(found it here ). And this is a more powerful way to IMO.

I turned this into a single line:

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

Update: as noted in the comments of @ mklement0, you should be careful with the properties PSPath , PSParentPath , PSChildName , PSDrive and PSProvider within psobject.properties .

+4
source

The answer is in two parts.

Let's start with $key from the registry:

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

Since $key is Microsoft.Win32.RegistryKey , you cannot directly get name value pairs.

The first step is to create a PSCustomObjects list with Name / Value pairs. Name comes from GetValueNames laid through a ForEach object . For each of these names, we get Value through GetValue :

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

An alternative for the first step is to use Select-Object with -ExpandProperty , as explained by Scott Saad :

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

The second step is to filter $namevalues either by Name or by Value .

Where-Object has a pretty cool Comparison that accept regular expressions like match , notMatch , etc.

To make the code more readable, you can wrap the lines (thanks Joey !) Or use backtick (`) or use places in PowerShell syntax where it takes line breaks, for example, after a pipe (|) or opening a bracket ({):

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

Result at will:

 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 
+5
source

More reliable PSv4 + alternative to montonero's useful answer : [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 stores an instance of [Microsoft.Win32.RegistryKey] returned by Get-Item in the $key variable for later use in the pipeline.

  • ForEach-Object Property lists the names of the values ​​of the target keys (via .Property notes .Property which PowerShell adds to the output instance [Microsoft.Win32.RegistryKey] ).

  • Inside the script block, Where-Object $_ then references $key.GetValue(<valueName>) name of the value, and $key.GetValue(<valueName>) used to retrieve the associated data.

    • Important .Property : In the .Property array .Property PowerShell translates the name of the default value , which is an empty string ( '' ) at the API level, into the name '(default)' ; thus, if $_ is equal to '(default)' , you must translate it to '' before calling $_.GetValue(<valueName>) , which
      ($_, '')[$_ -eq '(default)'] does.
  • [pscustomobject] @{... } then creates and displays an instance of [pscustomobject] with .Name and .Value properties reflecting the name and data of the matching value.


[1] Montonero's answer is concise and works well in this case, but with the caveats:

The PowerShell registry provider automatically adds the following additional note properties (members of type NoteProperty , as reflected in the Get-Member output) containing metadata about the target registry keys to the [pscustomobject] instance that Get-ItemProperty displays :

  • PSPath , PSParentPath , PSChildName , PSDrive , PSProvider

They can interfere with filtering based on .psobject.properties two ways:

  • Using wildcard matching $_.Name may accidentally include these properties.

    • For example, $_.Name -like '*drive*' will match the PSDrive property, even if it is not part of a registry key.
  • Perhaps more hypothetically, if the registry key has values ​​with the same name as these provider properties, the provider properties obscure (override) these values.

    • For example, if the key is PSPath , $_.Value instead report the value of the provider property.
0
source

Source: https://habr.com/ru/post/1445606/


All Articles