Useful Little PowerShell Functions - Set-RegistryItemValue

Well hello again everyone! For this installment of "over-engineered PowerShell code", we have a robust little function that has one job; ensure that a registry item exists with a specified name and value in a specified key. Let me start first with the code.

function Set-RegistryItemValue
{
	param (
		#The full path of the registry key
		[Parameter(Mandatory = $true)]
		[String]$RegistryKeyPath,
		# The name of the registry item
		[Parameter(Mandatory = $true)]
		[string]$RegistryItemName,
		# The value of the registry item
		[Parameter(Mandatory = $true)]
		[String]$RegistryItemValue,
		# The type of registry value
		[Parameter(Mandatory = $true)]
		[String]$RegistryItemType
	)
	[int]$RegistryKeyExistsCounter = 0
	[bool]$RegistryKeyCurrentlyExists = $false
	while(($RegistryKeyExistsCounter -le 1) -and ($RegistryKeyCurrentlyExists -eq $false))
	{
		[bool]$TestPathResult = $false
		try
		{
			$TestPathResult = Test-Path -Path "Registry::$($RegistryKeyPath)" -ErrorAction Stop
		}
		catch
		{
			return $Error[0]
		}
		if($TestPathResult -eq $true)
		{
			$RegistryKeyCurrentlyExists = $true
		}
		else
		{
			try
			{
				New-Item -Path "Registry::$($RegistryKeyPath)" -ErrorAction Stop | Out-Null
			}
			catch
			{
				return $Error[0]
			}
		}
		$RegistryKeyExistsCounter = $RegistryKeyExistsCounter + 1
	}
	if ($RegistryKeyCurrentlyExists -eq $false)
	{
		return 1
	}
	[int]$RegistryItemExistsCounter = 0
	[Bool]$RegistryItemCurrentlyExists = $false
	while(($RegistryItemCurrentlyExists -le 1) -and ($RegistryItemCurrentlyExists -eq $false))
	{
		$CurrentRegistryItemValue = $null
		try
		{
			$CurrentRegistryItemValue = Get-ItemProperty -Path $RegistryKeyPath -Name $RegistryItemName -ErrorAction Stop
		}
		catch
		{
			return $Error[0]
		}
		if ($null -ne $CurrentRegistryItemValue)
		{
			$RegistryItemCurrentlyExists -eq $true
		}
		else
		{
			try
			{
				New-ItemProperty -Path $RegistryKeyPath -Name $RegistryItemName -Value $RegistryItemValue -PropertyType $RegistryItemType -ErrorAction Stop
			}
			catch
			{
				return $Error[0]
			}
		}
		$RegistryItemExistsCounter = $RegistryItemExistsCounter + 1
	}
	if ($RegistryItemCurrentlyExists -eq $false)
	{
		return 1
	}
	[int]$RegistryItemTypeCorrectCounter = 0
	[bool]$RegistryItemTypeCorrect = $false
	while (($RegistryItemTypeCorrectCounter -le 1) -and ($RegistryItemTypeCorrect -eq $false))
	{
		$CurrentRegistryItemValue = $null
		try
		{
			$CurrentRegistryItemValue = Get-ItemProperty -Path $RegistryKeyPath -Name $RegistryItemName -ErrorAction Stop
		}
		catch
		{
			return $Error[0]
		}
		if (($CurrentRegistryItemValue."$($RegistryItemName)").GetType() -eq $RegistryItemType)
		{
			$RegistryItemTypeCorrect = $true
		}
		else
		{
			try
			{
				Remove-ItemProperty -Path "Registry::$($RegistryKeyPath)" -Name $RegistryItemName -ErrorAction Stop | Out-Null
			}
			catch
			{
				return $Error[0]
			}

			try
			{
				New-ItemProperty -Path $RegistryKeyPath -Name $RegistryItemName -Value $RegistryItemValue -PropertyType $RegistryItemType -ErrorAction Stop | Out-Null
			}
			catch
			{
				return $Error[0]
			}
		}
		$RegistryItemTypeCorrectCounter = $RegistryItemTypeCorrectCounter + 1
	}
	if ($RegistryItemTypeCorrect -eq $false)
	{
		return 1
	}
	[int]$RegistryItemSetValueCounter = 0
	[bool]$RegistryItemValueSet = $false
	while(($RegistryItemSetValueCounter -le 1) -and ($RegistryItemValueSet -eq $false))
	{
		$CurrentRegistryItemValue = $null
		try
		{
			$CurrentRegistryItemValue = Get-ItemProperty -Path $RegistryKeyPath -Name $RegistryItemName -ErrorAction Stop
		}
		catch
		{
			return $Error[0]
		}
		if ($CurrentRegistryItemValue -eq $RegistryItemValue)
		{
			$RegistryItemValueSet = $true
		}
		else
		{
			try
			{
				Set-ItemProperty -Path "Registry::$($RegistryKeyPath)" -Name $RegistryItemName -Value $RegistryItemValue -ErrorAction Stop | Out-Null
			}
			catch
			{
				return $Error[0]
			}
		}
		$RegistryItemSetValueCounter = $RegistryItemSetValueCounter + 1
	}
	if ($RegistryItemValueSet -eq $false)
	{
		return 1
	}
	return 0
}        

To continue with the pattern we established last time, we take the end goal of "make sure a registry item with a specified name and a specified value exists in the specified key", and break it down to the most basic steps needed to get there. We then build code that will perform each step, check to ensure that the step was actually successful, and then move on to the next step.

Why build this function at all?

This really big project I've been working on has a few requirements. The first one is that we need to keep track of state between script executions. The script will reboot the computer a bunch of times, and then a scheduled task will run on boot or on login that relaunches the script. The script will need to be able to store details that future executions of the script will need. The registry is a pretty good spot to do that in, because it survives reboots and doesn't require us to parse anything.

The basic algorithm

Ok, so what are the things we need to make happen to ensure that a registry item with a specified value exists? Let's break it down:

  1. Check if the destination registry key exists. If it does not, try to create it. If the registry key fails to get created correctly, return 1
  2. Check if a registry item with the specified name exists. If it does not, try to create it. If the registry item fails to get created correctly, return 1
  3. Check if the registry item is the correct type. If it is not, try to delete the existing key and recreate it with the correct type. If the registry item fails to get created correctly, return 1
  4. Check if the registry item has the correct value. If it does not, try to set it to the correct value. If the registry item fails to get set to the correct value, return 1
  5. return 0

Why check each individual part?

This is a perfectly reasonable question. Why not just check the registry key once and if it's wrong at all, blow it away and recreate it? Well, I don't really have a good answer, other than that I like casting really wide nets. Because each individual component gets checked as we go down the algorithm, we can know with something like 100% certainty that the thing we tried to do actually worked correctly.

Now, maybe an improvement in this function might be to check each part of the registry item, and then have one single Boolean value that determines whether it needs to be recreated at all. Then we could write the code to create the registry item only once.

Other future improvement ideas

One thing I have considered doing is using parameter validation to ensure that we're getting valid data from the function call. Strictly speaking, that functionality wasn't necessary in this code, but it would be an improvement.

Another improvement might be to automatically mount and dismount the HKU hive if that hive is passed in from the function call. That hive doesn't get mounted automatically in PowerShell.

Wrapping up

There's not really a ton to this function other than what's already been described. Let me know what you guys think. As always, I'm open to taking any advice I can get.

To view or add a comment, sign in

More articles by William Ogle

Insights from the community

Others also viewed

Explore topics