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