Skip to content

Instantly share code, notes, and snippets.

@Bill-Stewart
Created December 18, 2025 18:50
Show Gist options
  • Select an option

  • Save Bill-Stewart/1014e295faedf840b56f060ddee49806 to your computer and use it in GitHub Desktop.

Select an option

Save Bill-Stewart/1014e295faedf840b56f060ddee49806 to your computer and use it in GitHub Desktop.
# 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