ntdll/NtEnumerateValueKey.ps1

function NtEnumerateValueKey
{
    <#
    .SYNOPSIS
 
    Provides information about the value entries of an open key.
 
    .PARAMETER KeyHandle
 
    Handle to the registry key that you want to enumerate value entries for.
 
    .PARAMETER Index
 
    The index of the subkey that you want value information for.
 
    .PARAMETER KeyInformationClass
 
    Specifies a KEY_VALUE_INFORMATION_CLASS value that determines the type of information returned in the KeyValueInformation buffer.
 
    .NOTES
 
    Author: Jared Atkinson (@jaredcatkinson), Brian Reitz (@brian_psu)
    License: BSD 3-Clause
    Required Dependencies: PSReflect, KEY_INFORMATION_CLASS (Enumeration), KEY_BASIC_INFORMATION, KEY_FULL_INFORMATION, KEY_NODE_INFORMATION, KEY_NAME_INFORMATION (Structures)
    Optional Dependencies: None
 
    (func ntdll NtEnumerateValueKey ([UInt32]) @(
        [IntPtr], #_In_ HANDLE KeyHandle,
        [UInt32], #_In_ ULONG Index,
        $KEY_VALUE_INFORMATION_CLASS, #_In_ KEY_INFORMATION_CLASS KeyValueInformationClass,
        [IntPtr], #_Out_opt_ PVOID KeyValueInformation,
        [UInt32], #_In_ ULONG Length,
        [UInt32].MakeByRefType() #_Out_ PULONG ResultLength
    ) -EntryPoint NtEnumerateValueKey),
 
    .LINK
 
    https://msdn.microsoft.com/en-us/library/windows/hardware/ff566453(v=vs.85).aspx
 
    .EXAMPLE
     
    $MyKeyHandle = NtOpenKey -KeyName "\Registry\Machine\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
    $KeyInfo = NtEnumerateValueKey -KeyHandle $MyKeyHandle -Index 0 -KeyValueInformationClass KeyValueFullInformation
    NtClose -KeyHandle $MyKeyHandle
 
    #>


    param
    (
        [Parameter(Mandatory = $true)]
        [IntPtr]
        $KeyHandle,

        # Index of the value key we wish to enumerate
        [Parameter()]
        [int]
        $Index = 0,

        [Parameter()]
        [ValidateSet('KeyValueBasicInformation','KeyValueFullInformation','KeyValuePartialInformation')]
        [string]
        $KeyValueInformationClass = 'KeyValueBasicInformation'
    )
#>

    $SubKeyValuePtrSize = 0
    $status = $ntdll::NtEnumerateValueKey($KeyHandle, $Index, $KEY_VALUE_INFORMATION_CLASS::$KeyValueInformationClass, 0, $SubKeyValuePtrSize, [ref]$SubKeyValuePtrSize)

    # if it returns STATUS_NO_MORE_ENTRIES, that means the Index is not valid (i.e. there isn't a subkey at that index)
    if($status -eq 0x8000001A) {
        throw [System.IndexOutOfRangeException] "Index out-of-bounds, or the given registry key has no value entries."
    } 
    # allocate the correct size and assign the value to our buffer
    [IntPtr]$SubKeyValuePtr = [System.Runtime.InteropServices.Marshal]::AllocHGlobal($SubKeyValuePtrSize)
    $status = $ntdll::NtEnumerateValueKey($KeyHandle, $Index, $KEY_VALUE_INFORMATION_CLASS::$KeyValueInformationClass, $SubKeyValuePtr, $SubKeyValuePtrSize, [ref]$SubKeyValuePtrSize)

    # if there are no errors, cast to specific type
    if(!$status){
        switch($KeyValueInformationClass)
        {
            KeyValueBasicInformation
            {
                $KeyValueBasicInformation = $SubKeyValuePtr -as $KEY_VALUE_BASIC_INFORMATION
                Write-Output $KeyValueBasicInformation
            }
            KeyValuePartialInformation
            {
                $KeyValuePartialInformation = $SubKeyValuePtr -as $KEY_VALUE_PARTIAL_INFORMATION
                Write-Output $KeyValuePartialInformation
            }
            KeyValueFullInformation
            {
                $KeyValueFullInformation = $SubKeyValuePtr -as $KEY_VALUE_FULL_INFORMATION
                if($KeyValueFullInformation.DataLength -gt 0) {
                    $DataPtr = [IntPtr]::Add($SubKeyValuePtr, $KeyValueFullInformation.DataOffset)
                    $SubKeyValueData = New-Object byte[] $KeyValueFullInformation.DataLength
                    [System.Runtime.InteropServices.Marshal]::Copy($DataPtr, $SubKeyValueData, 0, $KeyValueFullInformation.DataLength)
                    # Need to check Registry Value Type to see what kind of data this is before printing
                    Write-Output $KeyValueFullInformation
                    [System.Text.Encoding]::Unicode.GetString($SubKeyValueData)
                }
            }
        }
    }
    [System.Runtime.InteropServices.Marshal]::FreeHGlobal($SubKeyValuePtr)
}