Jeroen Wiert Pluimers
Jeroen Wiert Pluimers

Reputation: 24463

How to query registry values skipping the PS* ones

When querying the registry value names like this:

Get-ItemProperty HKCU:\Software\Microsoft\Osk

You get a whole bunch of extra values.

PSPath            : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\Osk
PSParentPath      : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft
PSChildName       : Osk
PSDrive           : HKCU
PSProvider        : Microsoft.PowerShell.Core\Registry
WindowLeft        : 100
WindowTop         : 100
WindowWidth       : 828
WindowHeight      : 236
ClickSound        : 1
Mode              : 1
HoverPeriod       : 1000
ScanInterval      : 1000
UseDevice         : 1
UseMouse          : 0
UseKB             : 1
ScanKey           : 32
UseTextPrediction : 1
InsertSpace       : 1
ShowNumPad        : 0

What I want is only the value names (WindowLeft, ...)

How can I do that?

Edit: string matches don't cut it. I do want legitimate registry value names to be included.

Example (could have done similar things with reg query hklm /v PS* /s or reg query hkcu /v PS* /s

reg add "HKCU\Software\BeSharp.net\Test" /v "Foo" /t REG_SZ /d "Bar" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "Bar" /t REG_SZ /d "Foo" /f

reg add "HKCU\Software\BeSharp.net\Test" /v "PSPath" /t REG_SZ /d "Foo" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "PSParentPath" /t REG_SZ /d "Foo" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "PSChildName" /t REG_SZ /d "Foo" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "PSDrive" /t REG_SZ /d "Foo" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "PSProvider" /t REG_SZ /d "Foo" /f

reg add "HKCU\Software\BeSharp.net\Test" /v "1" /t REG_SZ /d "PSPath" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "2" /t REG_SZ /d "PSParentPath" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "3" /t REG_SZ /d "PSChildName" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "4" /t REG_SZ /d "PSDrive" /f
reg add "HKCU\Software\BeSharp.net\Test" /v "5" /t REG_SZ /d "PSProvider" /f

reg query "HKCU\Software\BeSharp.net\Test"

You can delete the above demo data with this:

reg delete "HKCU\Software\BeSharp.net\Test"

The reg query "HKCU\Software\BeSharp.net\Test" returns this:

HKEY_CURRENT_USER\Software\BeSharp.net\Test
    Foo    REG_SZ    Bar
    Bar    REG_SZ    Foo
    PSPath    REG_SZ    Foo
    PSParentPath    REG_SZ    Foo
    PSChildName    REG_SZ    Foo
    PSDrive    REG_SZ    Foo
    PSProvider    REG_SZ    Foo
    1    REG_SZ    PSPath
    2    REG_SZ    PSParentPath
    3    REG_SZ    PSChildName
    4    REG_SZ    PSDrive
    5    REG_SZ    PSProvider

But the PowerShell Get-ItemProperty "HKCU:\Software\BeSharp.net\Test" returns this, overwriting the PS* values in the registry:

PSPath       : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\BeSharp.net\Test
PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\BeSharp.net
PSChildName  : Test
PSDrive      : HKCU
PSProvider   : Microsoft.PowerShell.Core\Registry
Foo          : Bar
Bar          : Foo
1            : PSPath
2            : PSParentPath
3            : PSChildName
4            : PSDrive
5            : PSProvider

And adding a Select clause skips all PS* values, even if they came from the registry: PowerShell Get-ItemProperty "HKCU:\Software\BeSharp.net\Test" ^| Select * -Exclude PS*:

Foo : Bar
Bar : Foo
1   : PSPath
2   : PSParentPath
3   : PSChildName
4   : PSDrive
5   : PSProvider

So: skip PS* values like PSPath, PSParentPath, PSChildName, PSDrive and PSProvider (are there more?) when they are not in the registry, but include them when they are in the registry.

Bonus: Only list the names (not the values).

Upvotes: 5

Views: 4867

Answers (4)

wasif
wasif

Reputation: 15470

Function Get-KeyProperty to return registry values skipping PS*:

Function Get-KeyProperty {
  [CmdletBinding()]
  Param(
    [Parameter(Mandatory=$True)]
    [ValidateScript({Test-Path $_})]
    [String]$RegPath
  )
  $Values = New-Object PSObject
  Get-ItemProperty "$RegPath" | 
    Get-Member -MemberType NoteProperty |
      Where-Object {$_.Name -notlike "PS*"} | Foreach {
        $_ | Select-Object -ExpandProperty Name | Foreach {
          $Value = Get-ItemProperty "$RegPath" -Name "$_"
          $Values |
            Add-Member -MemberType NoteProperty -Name "$_" -Value "$($Value."$_")"
        }
      }
   Return $Values
}

And Get-HashedProperty to get in Hashtable or JSON (Also excluding PS*):

Function Get-HashedProperty {
  [CmdletBinding()]
  Param(    
    [Parameter(Mandatory=$True)]
    [ValidateScript({Test-Path $_})]
    [String]$RegPath,
    [Parameter(Mandatory=$False)]
    [ValidateSet("Json","HashTable")]
    [String]$As
  )
  $Hash = @{}
  Get-ItemProperty "$RegPath" | 
    Get-Member -MemberType NoteProperty |
      Where-Object {$_.Name -notlike "PS*"} | Foreach {
        $_ | Select-Object -ExpandProperty Name | Foreach {
          $Value = Get-ItemProperty "$RegPath" -Name "$_"
          $Hash.Add("$_","$($Value."$_")")
        }
      }
   If($As -eq "Json"){
     $Hash = $Hash | ConvertTo-Json
   }
   Return $Hash
}

Upvotes: 0

Keith Miller
Keith Miller

Reputation: 802

I know this is truly old, but here's a function I added to my Profile to facilitate registry exploration:

Function Get-KeyProperty  {
Param(
    [Parameter(Mandatory=$true,ValueFromPipeline=$true)]
    [ValidateScript( {(Resolve-Path $_).Provider.Name -Like 'Registry'} )]
    [String[]]
    $Path,
    [String[]]
    $Name=@("*")
)
Process {
    $Name.ForEach({ (Get-Item $Path).Property -like $_}).ForEach({
        Begin {$Hash = @{}}
        Process { $Hash += @{ $_ = (Get-Item $Path).GetValue($_)} }
        End {[PSCustomObject]$Hash}
    })
}}

enter image description here Examples:

PS C:\> set-alias gkp Get-KeyProperty
>>
>> $USF = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders\'
>>
>> $TestPSNames = 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\DummyWithPSNames\'
>>
PS C:\> gkp $TestPSNames
Hello PSPath
----- ------
World Not the real PS Path


PS C:\>>gkp $USF -Name p*,S*

Start Menu : C:\Users\keith\AppData\Roaming\Microsoft\Windows\Start Menu
SendTo     : C:\Users\keith\AppData\Roaming\Microsoft\Windows\SendTo
Startup    : C:\Users\keith\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
PrintHood  : C:\Users\keith\AppData\Roaming\Microsoft\Windows\Printer Shortcuts
Personal   : C:\Users\keith\Documents
Programs   : C:\Users\keith\AppData\Roaming\Microsoft\Windows\Start Menu\Programs


PS C:\>>$USF, $TestPSNames | gkp -Name S*,PS*,H* | fl                                                  

SendTo     : C:\Users\keith\AppData\Roaming\Microsoft\Windows\SendTo
Startup    : C:\Users\keith\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Startup
Start Menu : C:\Users\keith\AppData\Roaming\Microsoft\Windows\Start Menu
History    : C:\Users\keith\AppData\Local\Microsoft\Windows\History

PSPath : Not the real PS Path
Hello  : World

Upvotes: 2

Rohn Edwards
Rohn Edwards

Reputation: 2659

You can use the GetValueNames() method on the registry key objects:

$RegPath = "HKCU:\Software\Microsoft\Osk"

# Get just value names:
(Get-Item $RegPath).GetValueNames() -replace "^$", "(default)"

# Get PSObject excluding PS properties (this won't work when value names collide 
# with reserved PS properties, e.g., PSPath, PSParentPath, PSChildName):
Get-Item $RegPath | ForEach-Object {
    $_ | Get-ItemProperty | select ($_.GetValueNames() -replace "^$", "(default)")
}

# Get PSObject excluding PS properties (this works when the value names collide)
Get-Item $RegPath | ForEach-Object {
    $RegKey = $_
    $PropertyHash = @{}
    $_.GetValueNames() -replace "^$", "(default)" | ForEach-Object {
        $PropertyHash.$_ = $RegKey.GetValue($_)
    }
    New-Object PSObject -Property $PropertyHash
}

Upvotes: 5

TheMadTechnician
TheMadTechnician

Reputation: 36277

That's an easy one, you simple use Select, and tell it to Exclude PS*:

Get-ItemProperty HKCU:\Software\Microsoft\Osk|Select * -Exclude PS*

Edit: I should really read the whole question. Ok, to get just the names you can pipe to Get-Member -MemberType Properties, and then Select -Expand Name, and filter for items that start with PS

Get-ItemProperty HKCU:\Software\Microsoft\Osk|GM -MemberType Properties|Select -Expand Name| ?{!($_ -Match "^PS")}

Edit: Ok, if you want value names, and want to avoid PowerShell generated values, then we'll work around the built in providers and do a WMI query...

$HKEY_CLASSES_ROOT = 2147483648
$HKEY_CURRENT_USER = 2147483649
$HKEY_LOCAL_MACHINE = 2147483650
$HKEY_USERS = 2147483651
$HKEY_CURRENT_CONFIG = 2147483653
$reg = [WMIClass]"ROOT\DEFAULT:StdRegProv"
$reg.EnumValues($HKEY_CURRENT_USER,"Software\Microsoft\Osk")|Select -Expand sNames

On a side note, I'm curious what 2147483652 is since it seems to skip that.

Edit: meaning 2147483652 found by searching for 2147483652 HKEY_CLASSES_ROOT 2147483648 HKEY_CURRENT_USER 2147483649 HKEY_LOCAL_MACHINE 2147483650 HKEY_USERS 2147483651 HKEY_CURRENT_CONFIG 2147483653 HKEY_DYN_DATA 2147483654

Many links answer it, including DLLBinder Example - Registry Access that indicates it is in winreg.h (which - not surprisingly - contains the HEX values).

So, for completeness:

  $HKEY_CLASSES_ROOT       = 2147483648 # 0x80000000   
  $HKEY_CURRENT_USER       = 2147483649 # 0x80000001   
  $HKEY_LOCAL_MACHINE      = 2147483650 # 0x80000002   
  $HKEY_USERS              = 2147483651 # 0x80000003   
  $HKEY_PERFORMANCE_DATA   = 2147483652 # 0x80000004   
  $HKEY_CURRENT_CONFIG     = 2147483653 # 0x80000005   
  $HKEY_DYN_DATA           = 2147483654 # 0x80000006 

Upvotes: 5

Related Questions