Home > Enterprise >  Powershell, registry and wildcards, oh my
Powershell, registry and wildcards, oh my

Time:11-17

Given...

HKLM\Software\   
  KeyName
    Property_1
    Property_2
    Property_[0-1] 
  Key*Name
    Property_1
    Property_2
    Property_[0-1]   
  Key@Name
    Property_1
    Property_2
    Property_[0-1]

I can use

Get-Item -path:"Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name"

which will return KeyName, Key*Name and Key@Name, while

Get-Item -literalPath:"Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name"

will return just Key*Name. So far, so good. I can use -path or -literalPath as needed to either search for a key with wildcards or not. But properties pose a problem.

Get-ItemProperty -path:"Registry::HKEY_LOCAL_MACHINE\SOFTWARE\KeyName" -name:"Prop_[0-9]"

works as expected and returns Prop_1 & Prop_2 from the KeyName key. And

Get-ItemProperty -literalPath:"Registry::HKEY_LOCAL_MACHINE\SOFTWARE\KeyName" -name:"Prop_[0-9]"

works as expected and returns just Prop_[0-9] from the same key. But it all fails apart when you need to use a wildcard to find properties, in a path that includes a wildcard character as a literal in the key path. So...

Get-ItemProperty -path:"Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name" -name:"Prop_[0-9]"

returns Prop_1 & Prop_2 from all three keys. Not the desired behavior at all.

I had hoped to be able to filter on PSPath using -`literalPath' but this

Get-ItemProperty -literalPath:"Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name" -name:"Prop_[0-9]" | where {$_.PSPath -match [RegEx]::Escape("Key*Name")}

does not return the correct properties. It seems that a -literalPath means a literal name also. So I tried filtering on PSPath and Name like so

Get-ItemProperty -literalPath:"Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name" -name:"Prop_[0-9]" | where {(($_.PSPath -match [RegEx]::Escape("Key*Name")) -and ($_.Name -match "Prop_[0-9]"))}

But that doesn't work because once you actually get real properties, they are no longer a .NET type, they have been shat into a PSCustomObject. And that is starting to get so complicated I wonder if there is a better way to proceed. I should note that the ultimate goal here is to get both a literal path and a list of literal property names, so that I can move, copy or delete the properties. So, given a path of Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name and a name of Prop_[0-9] I will eventually want to, for example, delete

HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name\Prop_1 

&

HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name\Prop_2

but not

HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name\Prop_[0-9]

EDIT: Based on the answer from @Tomalak I have simplified a bit, to simply get back a list of property names. That looks like this

$keyPath = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name"
$propExpr = "Prop_[0-9]"
((Get-Item -literalPath:$keyPath | Get-ItemProperty).PSObject.Properties | Where-Object Name -Match $propExpr | ForEach-Object {$_.Name})

CodePudding user response:

This will get a registry key by literal path and filter its properties by regex match

$keyPath = "Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Key*Name"
$propExpr = "Prop_[0-9]"

Get-Item -literalPath $keyPath -PipelineVariable key | Get-ItemProperty | ForEach-Object {
    $_.PSObject.Properties | Where-Object Name -Match $propExpr | ForEach-Object {
        [pscustomobject]@{
            key = $key.Name
            prop = $_.Name
            value = $_.Value
        }
    }
}

Instead of the $key.Name you can of course return the actual $key if that's more convenient for your task.

  • Related