Search code examples
powershellreplacepathregistry

Powershell - transform fully qualified paths into PS drive-based paths using string replacement


I have this code which finds a registry key with the name "c02ebc5353d9cd11975200aa004ae40e". This works perfectly. However the variable also has Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\Office..path to found key in when it completes. How do I remove the Microsoft.powershell.core\Registry:: part?

$path = ls 'HKCU:\' -Recurse | where { $_.Name -like 
 '*c02ebc5353d9cd11975200aa004ae40e*' } | Select PSParentPath | ft -AutoSize -Wrap

I looked at using the .replace function on a variable like below:

$path.replace ("Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER", "HKU:")

I get this error: [Microsoft.PowerShell.Commands.Internal.Format.FormatStartData] does not contain a method named 'replace'.. But If I do this on a normal variable, the .replace part works fine

Any help appreciated.


Solution

    • Formatting cmdlets such as ft (Format-Table) are only ever meant for displaying data - do not use their output as data for subsequent processing.

      • Remove | ft -AutoSize -Wrap from your first command.
      • Because ft produces output objects of types such as [Microsoft.PowerShell.Commands.Internal.Format.FormatStartData], which have no .Replace() method, your call failed.
    • You were looking for the [string]-type .Replace() method, but even without the ft call, Select PSParentPath doesn't output strings, but wrapper objects that have a .PSParentPath property with the desired values. To output the values only, use -ExpandProperty:

      • Use Select -ExpandProperty PSParentPath to skip the wrapper object and output the .PSParentPath values directly, as strings.

    To put it all together (using Get-ChildItem instead of alias ls, and Where-Object instead of alias where):

    $path = Get-ChildItem HKCU:\ -Recurse | Where-Object {
      $_.Name -like '*c02ebc5353d9cd11975200aa004ae40e*' 
    } | Select -ExpandProperty PSParentPath
    
    $path.Replace("Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER", "HKCU:")
    

    Here's a streamlined alternative solution that:

    • assumes that it is sufficient to apply the wildcard pattern to the registry key names only (the .Name property actually reports the full key path), in which case Get-ChildItem's -Include parameter can be used.

    • uses PowerShell's -replace operator, which - unlike the .Replace() string method, operates on regular expressions, which enables many more features; in the case a hand, it allows anchoring the match at the start of the string ^ (but conversely requires escaping regex metachars. such as . and \ with \).

    (Get-ChildItem HKCU:\ -Recurse -Include *c02ebc5353d9cd11975200aa004ae40e*)
     .PSParentPath -replace '^Microsoft\.PowerShell\.Core\\Registry::HKEY_CURRENT_USER', 'HKCU:'