I'm trying to get a feel for the idioms to use in PowerShell.
Given this script:
$path = 'hkcu:\Software\Microsoft\Windows\CurrentVersion\Extensions'
$key = Get-Item $path
$key
I get the output at the bottom of this question.
I'd like to get output of the properties (the name/value pairs under the $key
) where I can filter on both name and value.
For instance, filter to list all the Extensions that have:
xls*
*\MSACCESS.EXE
Or an exclude filter: exclude all names like doc*
Fir the first filter, I'd want a result like this:
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 output of the script:
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 part of the problem: getting a list of Name/Value pairs. It uses PSCustomObject:
$namevalues = $key.GetValueNames() | ForEach-Object { [pscustomobject]@{ Name=$_; Value=$key.GetValue($_) } }
$namevalues
(How should I wrap that code?)
Any help with the filtering would be much appreciated
A two part answer.
We start with the $key
from the registry:
$path = 'hkcu:\Software\Microsoft\Windows\CurrentVersion\Extensions'
$key = Get-Item $path
$key
$key | Get-Member
Since $key
is a Microsoft.Win32.RegistryKey, you cannot get the name value pairs out directly.
The first step is to create a list of PSCustomObjects with Name
/Value
pairs. The Name
comes from the GetValueNames piped through a ForEach-Object. For each of those Names, we get the 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 the Select-Object using -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 the $namevalues
either by Name
or by Value
.
The Where-Object has some pretty cool Comparison operators that accept regular expressions like match
, notMatch
, etc.
To make the code more readable, you can wrap lines (thanks Joey!) either use the backtick (`) or take advantage of the places in the PowerShell syntax where it does accept line breaks, like after a pipe (|) or opening brace ({):
$matches = $namevalues |
Where-Object {
$_.Name -match '^xls' `
-or $_.Value -match 'msaccess.exe$'
}
$matches | Format-Table
The result is as wanted:
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
There's a much more clever way to enumerate registry values (found it here). And it's more powershell-way IMO.
I've turned it into a one-liner:
(Get-ItemProperty $path).psobject.properties |
where {$_.name -like "xls*" -or $_.value -like "*\MSACCESS.EXE"} |
select name,value
Update: As noted in comments by @mklement0, you should be careful about properties PSPath
, PSParentPath
, PSChildName
, PSDrive
, and PSProvider
within the psobject.properties
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With