[powershell] Test if registry value exists

In my powershell script I'm creating one registry entry for each element I run script on and I would like to store some additional info about each element in registry (if you specify optional parameters once then by default use those params in the future).

The problem I've encountered is that I need to perform Test-RegistryValue (like here--see comment) but it doesn't seem to do the trick (it returns false even if entry exists). I tried to "build on top of it" and only thing I came up is this:

Function Test-RegistryValue($regkey, $name) 
{
    try
    {
        $exists = Get-ItemProperty $regkey $name -ErrorAction SilentlyContinue
        Write-Host "Test-RegistryValue: $exists"
        if (($exists -eq $null) -or ($exists.Length -eq 0))
        {
            return $false
        }
        else
        {
            return $true
        }
    }
    catch
    {
        return $false
    }
}

That unfortunately also doesn't do what I need as it seems it always selects some (first?) value from the registry key.

Anyone has idea how to do this? It just seems too much to write managed code for this...

This question is related to powershell registry

The answer is


This works for me:

Function Test-RegistryValue 
{
    param($regkey, $name)
    $exists = Get-ItemProperty "$regkey\$name" -ErrorAction SilentlyContinue
    Write-Host "Test-RegistryValue: $exists"
    if (($exists -eq $null) -or ($exists.Length -eq 0))
    {
        return $false
    }
    else
    {
        return $true
    }
}

I took the Methodology from Carbon above, and streamlined the code into a smaller function, this works very well for me.

    Function Test-RegistryValue($key,$name)
    {
         if(Get-Member -InputObject (Get-ItemProperty -Path $key) -Name $name) 
         {
              return $true
         }
         return $false
    }

My version, matching the exact text from the caught exception. It will return true if it's a different exception but works for this simple case. Also Get-ItemPropertyValue is new in PS 5.0

Function Test-RegValExists($Path, $Value){
$ee = @() # Exception catcher
try{
    Get-ItemPropertyValue -Path $Path -Name $Value | Out-Null
   }
catch{$ee += $_}

    if ($ee.Exception.Message -match "Property $Value does not exist"){return $false}
else {return $true}
}

I would go with the function Get-RegistryValue. In fact it gets requested values (so that it can be used not only for testing). As far as registry values cannot be null, we can use null result as a sign of a missing value. The pure test function Test-RegistryValue is also provided.

# This function just gets $true or $false
function Test-RegistryValue($path, $name)
{
    $key = Get-Item -LiteralPath $path -ErrorAction SilentlyContinue
    $key -and $null -ne $key.GetValue($name, $null)
}

# Gets the specified registry value or $null if it is missing
function Get-RegistryValue($path, $name)
{
    $key = Get-Item -LiteralPath $path -ErrorAction SilentlyContinue
    if ($key) {
        $key.GetValue($name, $null)
    }
}

# Test existing value
Test-RegistryValue HKCU:\Console FontFamily
$val = Get-RegistryValue HKCU:\Console FontFamily
if ($val -eq $null) { 'missing value' } else { $val }

# Test missing value
Test-RegistryValue HKCU:\Console missing
$val = Get-RegistryValue HKCU:\Console missing
if ($val -eq $null) { 'missing value' } else { $val }

OUTPUT:

True
54
False
missing value

The Carbon PowerShell module has a Test-RegistryKeyValue function that will do this check for you. (Disclosure: I am the owner/maintainer of Carbon.)

You have to check that that the registry key exists, first. You then have to handle if the registry key has no values. Most of the examples here are actually testing the value itself, instead of the existence of the value. This will return false negatives if a value is empty or null. Instead, you have to test if a property for the value actually exists on the object returned by Get-ItemProperty.

Here's the code, as it stands today, from the Carbon module:

function Test-RegistryKeyValue
{
    <#
    .SYNOPSIS
    Tests if a registry value exists.

    .DESCRIPTION
    The usual ways for checking if a registry value exists don't handle when a value simply has an empty or null value.  This function actually checks if a key has a value with a given name.

    .EXAMPLE
    Test-RegistryKeyValue -Path 'hklm:\Software\Carbon\Test' -Name 'Title'

    Returns `True` if `hklm:\Software\Carbon\Test` contains a value named 'Title'.  `False` otherwise.
    #>
    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$true)]
        [string]
        # The path to the registry key where the value should be set.  Will be created if it doesn't exist.
        $Path,

        [Parameter(Mandatory=$true)]
        [string]
        # The name of the value being set.
        $Name
    )

    if( -not (Test-Path -Path $Path -PathType Container) )
    {
        return $false
    }

    $properties = Get-ItemProperty -Path $Path 
    if( -not $properties )
    {
        return $false
    }

    $member = Get-Member -InputObject $properties -Name $Name
    if( $member )
    {
        return $true
    }
    else
    {
        return $false
    }

}

The -not test should fire if a property doesn't exist:

$prop = (Get-ItemProperty $regkey).$name
if (-not $prop)
{
   New-ItemProperty -Path $regkey -Name $name -Value "X"
}

The best way to test if a registry value exists is to do just that - test for its existence. This is a one-liner, even if it's a little hard to read.

PS C:> (Get-ItemProperty $regkey).PSObject.Properties.Name -contains $name

If you actually look up its data, then you run into the complication of how Powershell interprets 0.


$regkeypath= "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run" 
$value1 = (Get-ItemProperty $regkeypath -ErrorAction SilentlyContinue).Zoiper -eq $null 
If ($value1 -eq $False) {
Write-Host "Value Exist"
} Else {
Write-Host "The value does not exist"
}

If you are simply interested to know whether a registry value is present or not then how about:

[bool]((Get-itemproperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").PathName)

will return: $true while

[bool]((Get-itemproperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion").ValueNotThere)

will return: $false as it's not there ;)

You could adapt it into a scriptblock like:

$CheckForRegValue = { Param([String]$KeyPath, [String]$KeyValue)
return [bool]((Get-itemproperty -Path $KeyPath).$KeyValue) }

and then just call it by:

& $CheckForRegValue "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion" PathName

Have fun,

Porky


One-liner:

$valueExists = (Get-Item $regKeyPath -EA Ignore).Property -contains $regValueName

My version:

Function Test-RegistryValue($Key, $Name)
{
    (Get-ChildItem (Split-Path -Parent -Path $Key) | Where-Object {$_.PSChildName -eq (Split-Path -Leaf $Key)}).Property -contains $Name
}

Probably an issue with strings having whitespace. Here's a cleaned up version that works for me:

Function Test-RegistryValue($regkey, $name) {
    $exists = Get-ItemProperty -Path "$regkey" -Name "$name" -ErrorAction SilentlyContinue
    If (($exists -ne $null) -and ($exists.Length -ne 0)) {
        Return $true
    }
    Return $false
}