Get-RegistryKey.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
<#PSScriptInfo
.VERSION 1.0.2
 
.GUID 3db94b5b-3f5c-46b5-b382-0e1ed1eb18e1
 
.AUTHOR /u/Pyprohly
 
.TAGS Registry
 
.RELEASENOTES
 1.0.2 | 2018-11-12
  Add more registry hives
 
 1.0 | 2018-11-12
  Initial release
 
.DESCRIPTION
 Returns a read and writable Microsoft.Win32.RegistryKey object.
 
 The RegistryKey object that is returned by Get-Item isn’t open for writing.
 This cmdlet returns a RegistryKey object that is writable.
 
 No object is returned if the specified key could not be found or opened.
#>


param(
    [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)]
    [Alias('PSPath', 'KeyName')]
    [string]
    $Path,

    [Microsoft.Win32.RegistryKeyPermissionCheck]
    $PermissionCheck = [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,

    [System.Security.AccessControl.RegistryRights]
    [Alias('Rights')]
    $RegistryRights = [System.Security.AccessControl.RegistryRights]'ReadKey,WriteKey'
)

function Get-RegistryKey {
    [CmdletBinding()]
    [OutputType('Microsoft.Win32.RegistryKey')]
    param(
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        [Alias('PSPath', 'KeyName')]
        [string]
        $Path,

        [Microsoft.Win32.RegistryKeyPermissionCheck]
        $PermissionCheck = [Microsoft.Win32.RegistryKeyPermissionCheck]::ReadWriteSubTree,

        [System.Security.AccessControl.RegistryRights]
        [Alias('Rights')]
        $RegistryRights = [System.Security.AccessControl.RegistryRights]'ReadKey,WriteKey'
    )

    begin {
        $hives = @{
            hkcr = [Microsoft.Win32.Registry]::ClassesRoot
            hkcu = [Microsoft.Win32.Registry]::CurrentUser
            hklm = [Microsoft.Win32.Registry]::LocalMachine
            hku  = [Microsoft.Win32.Registry]::Users
            hkcc = [Microsoft.Win32.Registry]::CurrentConfig
            hkdd = [Microsoft.Win32.Registry]::DynData
        }

        $provider = Get-PSProvider -PSProvider Registry
        $providerString = $provider.ToString()

        foreach ($hive in $hives.GetEnumerator()) {
            $null = New-PSDrive -Name $hive.Name.ToUpper() -PSProvider Registry -Root $hive.Value.Name -ErrorAction SilentlyContinue
        }
    }

    process {
        foreach ($key in $Path) {
            if ($key.StartsWith($providerString)) {
                $key = $key.Substring($providerString.Length).TrimStart(':')
            } elseif ($key.StartsWith($provider.Name)) {
                $key = $key.Substring($provider.Name.Length).TrimStart(':')
            }

            $rh = $rk = $null
            :outer foreach ($rootKey in $hives.GetEnumerator()) {
                $rh = $rootKey.Value
                foreach ($prefix in ($rootKey.Name, $rootKey.Value.Name)) {
                    if ($key.StartsWith($prefix, [System.StringComparison]::OrdinalIgnoreCase)) {
                        $rk = $key.Substring($prefix.Length).TrimStart(':\')
                        break outer
                    }
                }
            }
            if (!$rk) { return }

            $o = $rh.OpenSubKey($rk, $PermissionCheck, $RegistryRights)
            if (!$o) { return }

            [string[]]$keyValueNames = try {
                $o.GetValueNames()
            } catch [System.UnauthorizedAccessException] {
                New-Object string[] 0
            }

            $rootName, $keyName = $o.Name.Split('\')[0,-1]
            $keyPath = $o.Name.Substring(0, $o.Name.LastIndexOf('\'))
            $o | Add-Member -PassThru -MemberType NoteProperty -Name Property -Value $keyValueNames |
                    Add-Member -PassThru -MemberType NoteProperty -Name PSChildName -Value $keyName |
                    Add-Member -PassThru -MemberType NoteProperty -Name PSDrive -Value (
                        Get-PSDrive -PSProvider Registry | Where-Object Root -eq $rootName) |
                    Add-Member -PassThru -MemberType NoteProperty -Name PSIsContainer -Value $true |
                    Add-Member -PassThru -MemberType NoteProperty -Name PSParentPath -Value (
                        $providerString + '::' + $keyPath) |
                    Add-Member -PassThru -MemberType NoteProperty -Name PSPath -Value (
                        $providerString + '::' + $o.Name) |
                    Add-Member -PassThru -MemberType NoteProperty -Name PSProvider -Value $provider
        }
    }
}

if ($MyInvocation.InvocationName -ne '.') {
    if ($MyInvocation.ExpectingInput) {
        $null = $PSBoundParameters.Remove('Path')
        $input | Get-RegistryKey @PSBoundParameters
    } else {
        Get-RegistryKey @PSBoundParameters
    }
}