Created
December 18, 2025 18:50
-
-
Save Bill-Stewart/1014e295faedf840b56f060ddee49806 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Get-RegistryValue.ps1 | |
| # Written by Bill Stewart (bstewart AT iname.com) | |
| # Version History | |
| # | |
| # 2025-12-18 | |
| # * Initial version. | |
| #requires -version 5.1 | |
| <# | |
| .SYNOPSIS | |
| Gets a registry value from one or more computers. | |
| .DESCRIPTION | |
| Gets a registry value from one or more computers. | |
| .PARAMETER SubKeyName | |
| Specifies the registry subkey where the value is located, using the format <RootKey>\SubKeyName, where <RootKey> is HKEY_CURRENT_USER (or HKCU) or HKEY_LOCAL_MACHINE (or HKLM). The root key name can optionally be followed by a ':' character. HKEY_CURRENT_USER (HKCU) does not work for remote computers. | |
| .PARAMETER ValueName | |
| Specifies the name of the registry value. | |
| .PARAMETER ComputerName | |
| Specifies one or more computer names from which to read the registry value. Omitting this parameter specifies the current computer. Reading from HKEY_CURRENT_USER (HKCU) is only supported on the current computer. | |
| .INPUTS | |
| String: You can pipe strings to specify computer names. | |
| .OUTPUTS | |
| PSObjects with the following properties: | |
| * ComputerName - Computer name (String) | |
| * SubKeyName - Registry subkey name (String) | |
| * ValueName - Registry value name (String) | |
| * ValueData - Registry value data (Varies based on type) | |
| * ValueType - Registry value type (String - REG_SZ, REG_DWORD, etc.) | |
| * ErrorCode - Error code (Integer - 0 for success) | |
| * Status - Status message | |
| Common error codes: | |
| * 2 - Registry value not found ("file not found") | |
| * 3 - Registry subkey not found ("path not found") | |
| * 5 - Access denied | |
| * 53 - Remote computer not reachable | |
| .EXAMPLE | |
| PS > Get-RegistryValue HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters SupportedEncryptionTypes | |
| Example output: | |
| ComputerName : COMPUTER1 | |
| SubKeyName : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System\Kerberos\Parameters | |
| ValueName : SupportedEncryptionTypes | |
| ValueData : 2147483640 | |
| ValueType : REG_DWORD | |
| ErrorCode : 0 | |
| Status : The operation completed successfully. | |
| This command outputs the registry value that corresponds to the "Network security: Configure encryption types allowed for Kerberos" policy setting. | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Position = 0,Mandatory)] | |
| [String] | |
| $SubKeyName, | |
| [Parameter(Position = 1)] | |
| [AllowEmptyString()] | |
| [String] | |
| $ValueName, | |
| [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName)] | |
| [String[]] | |
| $ComputerName | |
| ) | |
| begin { | |
| $ERROR_SUCCESS = 0 | |
| $ERROR_PATH_NOT_FOUND = 3 | |
| if ( -not $ComputerName ) { $ComputerName = [Environment]::MachineName } | |
| # Maps .NET's registry value types to the more common names | |
| $RegistryValueTypeNames = @{ | |
| [Microsoft.Win32.RegistryValueKind]::Unknown = "Unknown" | |
| [Microsoft.Win32.RegistryValueKind]::String = "REG_SZ" | |
| [Microsoft.Win32.RegistryValueKind]::ExpandString = "REG_EXPAND_SZ" | |
| [Microsoft.Win32.RegistryValueKind]::Binary = "REG_BINARY" | |
| [Microsoft.Win32.RegistryValueKind]::DWord = "REG_DWORD" | |
| [Microsoft.Win32.RegistryValueKind]::MultiString = "REG_MULTI_SZ" | |
| [Microsoft.Win32.RegistryValueKind]::QWord = "REG_QWORD" | |
| [Microsoft.Win32.RegistryValueKind]::None = "REG_NONE" | |
| } | |
| # Gets registry base key; outputs 0 for success, non-zero for failure | |
| function Get-RegistryBaseKey { | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Position = 0,Mandatory)] | |
| [String] | |
| $computerName, | |
| [Parameter(Position = 1,Mandatory)] | |
| [Ref] | |
| $baseKey, | |
| [Switch] | |
| $currentUser | |
| ) | |
| # LocalMachine if not -currentUser, or CurrentUser otherwise | |
| $registryHive = ([Microsoft.Win32.RegistryHive]::LocalMachine, | |
| [Microsoft.Win32.RegistryHive]::CurrentUser)[$currentUser.IsPresent] | |
| try { | |
| # It's a [Ref] parameter; set it using the Value property | |
| $baseKey.Value = [Microsoft.Win32.RegistryKey]::OpenRemoteBaseKey($registryHive,$computerName) | |
| return $ERROR_SUCCESS | |
| } | |
| catch [Management.Automation.MethodInvocationException] { | |
| return $_.Exception.InnerException.HResult | |
| } | |
| } | |
| # Gets a registry subkey; outputs 0 for success or non-zero for failure | |
| function Get-RegistrySubKey { | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Position = 0,Mandatory)] | |
| [Microsoft.Win32.RegistryKey] | |
| $baseKey, | |
| [Parameter(Position = 1,Mandatory)] | |
| [AllowEmptyString()] | |
| [String] | |
| $subKeyName, | |
| [Parameter(Position = 2,Mandatory)] | |
| [Ref] | |
| $subKey | |
| ) | |
| try { | |
| # OpenSubKey returns $null rather than throwing an exception if the | |
| # named subkey isn't found; in this case, we return ERROR_PATH_NOT_FOUND | |
| $subKey.Value = $baseKey.OpenSubKey($subKeyName,$false) | |
| return ($ERROR_SUCCESS,$ERROR_PATH_NOT_FOUND)[$null -eq $subKey.Value] | |
| } | |
| catch [Management.Automation.MethodInvocationException] { | |
| return $_.Exception.InnerException.HResult | |
| } | |
| } | |
| # Gets a registry value's kind (i.e., data type); outputs 0 for success, or | |
| # non-zero for failure | |
| function Get-RegistryValueKind { | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Position = 0,Mandatory)] | |
| [Microsoft.Win32.RegistryKey] | |
| $subKey, | |
| [Parameter(Position = 1,Mandatory)] | |
| [AllowEmptyString()] | |
| $valueName, | |
| [Parameter(Position = 2,Mandatory)] | |
| [Ref] | |
| $valueKind | |
| ) | |
| try { | |
| $valueKind.Value = $subKey.GetValueKind($valueName) | |
| return $ERROR_SUCCESS | |
| } | |
| catch [Management.Automation.MethodInvocationException] { | |
| return $_.Exception.InnerException.HResult | |
| } | |
| } | |
| # Gets a registry value's data and kind (i.e., data type); outputs 0 for | |
| # success, or non-zero for failure | |
| function Get-RegistryValueDataAndKind { | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Position = 0,Mandatory)] | |
| [Microsoft.Win32.RegistryKey] | |
| $baseKey, | |
| [Parameter(Position = 1,Mandatory)] | |
| [AllowEmptyString()] | |
| [String] | |
| $subKeyName, | |
| [Parameter(Position = 2,Mandatory)] | |
| [AllowEmptyString()] | |
| [String] | |
| $valueName, | |
| [Parameter(Position = 3,Mandatory)] | |
| [Ref] | |
| $valueDataAndKind | |
| ) | |
| $subKey = $null # Variable must exist before using [Ref] parameter | |
| $errorCode = Get-RegistrySubKey $baseKey $subKeyName ([Ref] $subKey) | |
| if ( $errorCode -eq $ERROR_SUCCESS ) { | |
| $valueKind = $null | |
| $errorCode = Get-RegistryValueKind $subKey $valueName ([Ref] $valueKind) | |
| if ( $errorCode -eq $ERROR_SUCCESS ) { | |
| $valueData = $subKey.GetValue($valueName,$null, | |
| [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames) | |
| # Return REG_DWORD as an unsigned 32-bit integer | |
| if ( $valueKind -eq [Microsoft.Win32.RegistryValueKind]::DWord ) { | |
| $valueData = [BitConverter]::ToUInt32([BitConverter]::GetBytes($valueData),0) | |
| } | |
| $valueDataAndKind.Value = [PSCustomObject] @{ | |
| "valueKind" = $valueKind | |
| "valueData" = $valueData | |
| } | |
| } | |
| $subKey.Close() | |
| } | |
| return $errorCode | |
| } | |
| # Gets a registry value and outputs an informational object with the results | |
| function Get-RegistryValue { | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Position = 0,Mandatory)] | |
| [String] | |
| $computerName, | |
| [Parameter(Position = 1,Mandatory)] | |
| [String] | |
| $subKeyName, | |
| [Parameter(Position = 2,Mandatory)] | |
| [AllowEmptyString()] | |
| [String] | |
| $valueName | |
| ) | |
| $outputObject = [PSCustomObject] @{ | |
| "ComputerName" = $computerName | |
| "SubKeyName" = $null | |
| "ValueName" = $null | |
| "ValueData" = $null | |
| "ValueType" = $null | |
| "ErrorCode" = $null | |
| "Status" = $null | |
| } | |
| $reMatch = [Regex]::Match($subKeyName.Trim(), | |
| '^(HKEY_(?:LOCAL_MACHINE|CURRENT_USER)|HKLM|HKCU):?(?:\\(.+))?$', | |
| [Text.RegularExpressions.RegexOptions]::IgnoreCase) | |
| if ( -not $reMatch.Success ) { | |
| Write-Error "The string '$subKeyName' is not a valid registry path." -Category InvalidArgument | |
| exit | |
| } | |
| $currentUser = "HKCU","HKEY_CURRENT_USER" -contains $reMatch.Groups[1].Value | |
| if ( $currentUser -and ($computerName -ne [Environment]::MachineName) ) { | |
| Write-Error "Reading from HKEY_CURRENT_USER is not supported on remote computers." -Category InvalidArgument | |
| return | |
| } | |
| $subKeyPath = $reMatch.Groups[2].Value | |
| $baseKey = $null | |
| $errorCode = Get-RegistryBaseKey $computerName ([Ref] $baseKey) -currentUser:$currentUser | |
| if ( $errorCode -eq $ERROR_SUCCESS ) { | |
| $outputObject.SubKeyName = "{0}\{1}" -f (("HKEY_LOCAL_MACHINE","HKEY_CURRENT_USER")[$currentUser],$subKeyPath) | |
| $outputObject.ValueName = $valueName | |
| $valueDataAndKind = $null | |
| $errorCode = Get-RegistryValueDataAndKind $baseKey $subKeyPath $valueName ([Ref] $valueDataAndKind) | |
| if ( $errorCode -eq $ERROR_SUCCESS ) { | |
| $outputObject.ValueData = $valueDataAndKind.valueData | |
| $outputObject.ValueType = $RegistryValueTypeNames[$valueDataAndKind.valueKind] | |
| } | |
| $baseKey.Close() | |
| } | |
| $outputObject.ErrorCode = $errorCode | |
| $outputObject.Status = ([ComponentModel.Win32Exception] $errorCode).Message | |
| $outputObject | |
| } | |
| } | |
| process { | |
| foreach ( $ComputerNameItem in $ComputerName ) { | |
| Get-RegistryValue $ComputerNameItem $SubKeyName $ValueName | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment