Skip to content

Commit

Permalink
New functions for removing keys from the registry + Improved tests (#11)
Browse files Browse the repository at this point in the history
* add delete subkey functions

* add Integration tests for `remove-RegistrySubKey`

* improve pester tests

* added integration tests for Backup-RegistryKey
  • Loading branch information
LarryWisherMan authored Sep 17, 2024
1 parent 25b5927 commit c5f244c
Show file tree
Hide file tree
Showing 18 changed files with 1,364 additions and 76 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- `Get-RegistrySubKey` to replace `Open-RegistrySubKey`. This implementation follows
the .net class better

- `Invoke-DeleteSubKey` and `Invoke-DeleteSubKeyTree` private functions for removing
subkeys

- `Remove-RegistrySubKey` and `Removing-RegistryKeyTree` public
public implementation

- New Private function `Get-RegistrySubKeyOperation` for managing the logic of
opening a key or using an existing one provided in `Remove-RegistrySubKey`

### Fixed

- Error Handling for `[System.Security.SecurityException]` in `Open-RegistryKey`
Expand Down
2 changes: 1 addition & 1 deletion build.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ Pester:
#- FunctionalQuality
#- TestQuality
Tag:
CodeCoverageThreshold: 85 # Set to 0 to bypass
CodeCoverageThreshold: 75 # Set to 0 to bypass
#CodeCoverageOutputFile: JaCoCo_$OsShortName.xml
#CodeCoverageOutputFileEncoding: ascii
# Use this if code coverage should be merged from several pipeline test jobs.
Expand Down
81 changes: 81 additions & 0 deletions source/Private/Get-RegistrySubKeyOperation.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
<#
.SYNOPSIS
Prepares the registry subkey operation by opening the relevant registry key based on the parameter set.
.DESCRIPTION
This function prepares the environment for removing a registry subkey. It opens the correct registry key either by
registry hive and path or by an existing registry key object, and returns the parent key and subkey name for further processing.
.PARAMETER RegistryPath
Specifies the path to the registry key to open. This is used only when the 'ByHive' parameter set is selected.
.PARAMETER RegistryHive
Specifies the registry hive where the key resides. This is used only when the 'ByHive' parameter set is selected.
.PARAMETER ComputerName
Specifies the name of the computer on which to perform the registry operation. This is used only when the 'ByHive' parameter set is selected.
Defaults to the local machine if not specified.
.PARAMETER ParentKey
Specifies an existing registry key object from which to delete the subkey. This is used only when the 'ByKey' parameter set is selected.
.PARAMETER SubKeyName
Specifies the name of the subkey to delete.
.PARAMETER ParameterSetName
Specifies which parameter set is being used. It should be either 'ByHive' or 'ByKey'.
.Outputs
System.Collections.Hashtable
.EXAMPLE
$details = Get-RegistrySubKeyOperation -RegistryPath 'SOFTWARE\MyApp' -RegistryHive LocalMachine -ComputerName 'RemotePC' -ParameterSetName 'ByHive'
This example prepares a registry operation on a remote computer by opening the 'SOFTWARE\MyApp' subkey in HKEY_LOCAL_MACHINE.
.EXAMPLE
$parentKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SOFTWARE\MyApp', $true)
$details = Get-RegistrySubKeyOperation -ParentKey $parentKey -SubKeyName 'Settings' -ParameterSetName 'ByKey'
This example prepares a registry operation by passing an already opened parent key and the subkey 'Settings'.
#>
function Get-RegistrySubKeyOperation
{
param (
[string]$RegistryPath,
[Microsoft.Win32.RegistryHive]$RegistryHive,
[string]$ComputerName,
[Microsoft.Win32.RegistryKey]$ParentKey,
[string]$SubKeyName,
[string]$ParameterSetName
)

if ($ParameterSetName -eq 'ByHive')
{
# Split path and get subkey name
$parentPath = Split-Path -Path $RegistryPath -Parent
$subKeyName = Split-Path -Path $RegistryPath -Leaf

# Open the registry key
try
{
$ParentKey = Open-RegistryKey -RegistryPath $parentPath -RegistryHive $RegistryHive -ComputerName $ComputerName -Writable $true
}
catch
{
throw "Failed to open registry key: $($RegistryHive)\$parentPath. $_"
}

return @{ ParentKey = $ParentKey; SubKeyName = $subKeyName }
}
elseif ($ParameterSetName -eq 'ByKey')
{
if ($null -eq $ParentKey)
{
throw [System.ArgumentNullException]::new("ParentKey cannot be null.")
}
return @{ ParentKey = $ParentKey; SubKeyName = $SubKeyName }
}

throw [System.ArgumentException]::new("Invalid parameter set.")
}
69 changes: 69 additions & 0 deletions source/Private/Invoke-DeleteSubKeyTree.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<#
.SYNOPSIS
Deletes a registry subkey and all of its child subkeys from the specified parent key.
.DESCRIPTION
The `Invoke-DeleteSubKeyTree` function deletes a specified subkey and all of its child subkeys from a provided registry key. It allows control over whether to throw an error if the subkey is missing.
.PARAMETER ParentKey
The parent registry key from which the subkey tree will be deleted. This parameter cannot be null.
.PARAMETER SubKeyName
The name of the subkey to delete, including all of its child subkeys. This parameter cannot be null or empty.
.PARAMETER ThrowOnMissingSubKey
Specifies whether an exception should be thrown if the subkey does not exist. Defaults to `$true`.
.EXAMPLE
$parentKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SOFTWARE\MyApp', $true)
Invoke-DeleteSubKeyTree -ParentKey $parentKey -SubKeyName 'Settings'
This command deletes the 'Settings' subkey and all its child subkeys under 'HKEY_LOCAL_MACHINE\SOFTWARE\MyApp'.
.EXAMPLE
$parentKey = [Microsoft.Win32.Registry]::CurrentUser.OpenSubKey('SOFTWARE\MyApp', $true)
Invoke-DeleteSubKeyTree -ParentKey $parentKey -SubKeyName 'TempSettings' -ThrowOnMissingSubKey $false
This command deletes the 'TempSettings' subkey and all its child subkeys under 'HKEY_CURRENT_USER\SOFTWARE\MyApp', and does not throw an exception if the subkey does not exist.
.NOTES
This function uses the .NET `Microsoft.Win32.RegistryKey` class to interact with the Windows registry. Ensure you have appropriate permissions to perform registry modifications.
#>

Function Invoke-DeleteSubKeyTree
{

param(
[Microsoft.Win32.RegistryKey]$ParentKey,
[string]$SubKeyName,
[bool]$ThrowOnMissingSubKey = $true
)

if ($null -eq $ParentKey)
{
throw [System.ArgumentNullException]::new("ParentKey cannot be null.")
}

if ([string]::IsNullOrEmpty($SubKeyName))
{
throw [System.ArgumentNullException]::new("SubKeyName cannot be null or empty.")
}

try
{
if ($ThrowOnMissingSubKey)
{
$ParentKey.DeleteSubKeyTree($SubKeyName)
}
else
{
$ParentKey.DeleteSubKeyTree($SubKeyName, $false)
}
}
catch
{
throw $_
}

}
73 changes: 73 additions & 0 deletions source/Private/Invoke-DeleteSubkey.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
<#
.SYNOPSIS
Deletes a specified subkey from the Windows registry.
.DESCRIPTION
The `Invoke-DeleteSubKey` function deletes a subkey from the Windows registry.
It provides flexibility to either pass a registry hive and path or an existing registry key object to delete the subkey.
It supports deleting subkeys on both local and remote computers.
This function is used internally by the `Remove-RegistrySubKey` cmdlet to delete a subkey from the Windows registry.
It is not intended to be used directly by end users.
.PARAMETER ParentKey
Specifies the parent registry key object from which to delete the subkey.
.PARAMETER SubKeyName
Specifies the name of the subkey to delete.
.PARAMETER ThrowOnMissingSubKey
Indicates whether the function should throw an error if the subkey to delete does not exist.
If set to `$false`, no error will be thrown when attempting to delete a non-existent subkey. Defaults to `$true`.
.INPUTS
Microsoft.Win32.RegistryKey
.OUTPUTS
None
.EXAMPLE
$parentKey = [Microsoft.Win32.Registry]::LocalMachine.OpenSubKey('SOFTWARE\MyApp', $true)
Invoke-DeleteSubKey -ParentKey $parentKey -SubKeyName 'Settings'
This command deletes the 'Settings' subkey under 'HKEY_LOCAL_MACHINE\SOFTWARE\MyApp' using the parent key object.
.NOTES
This function uses the .NET `Microsoft.Win32.RegistryKey` class to interact with the Windows registry.
It is recommended to run this function with appropriate permissions, as registry edits may require elevated privileges.
#>
function Invoke-DeleteSubKey
{
param(
[Microsoft.Win32.RegistryKey]$ParentKey,
[string]$SubKeyName,
[bool]$ThrowOnMissingSubKey = $true
)

if ($ParentKey -eq $null)
{
throw [System.ArgumentNullException]::new("ParentKey cannot be null.")
}

if ([string]::IsNullOrEmpty($SubKeyName))
{
throw [System.ArgumentNullException]::new("SubKeyName cannot be null or empty.")
}

try
{
if ($ThrowOnMissingSubKey)
{
$ParentKey.DeleteSubKey($SubKeyName, $true)
}
else
{
$ParentKey.DeleteSubKey($SubKeyName, $false)
}
}

catch
{
throw $_
}
}
2 changes: 1 addition & 1 deletion source/Public/Backup-RegistryKey.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ function Backup-RegistryKey
[string]$ComputerName = $env:COMPUTERNAME,
[Parameter(Mandatory = $true)]
[string]$RegistryPath, # Now dynamic, can back up any registry path
[string]$BackupDirectory = "C:\LHStuff\UserProfileTools\RegProfBackup"
[string]$BackupDirectory = $ENV:RegBackupDirectory
)

# Determine if the operation is local or remote
Expand Down
4 changes: 0 additions & 4 deletions source/Public/Export-RegistryKey.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,6 @@ function Export-RegistryKey

try
{




#$exportCommand = "reg export `"$RegistryPath`" `"$ExportPath`""
$result = Invoke-RegCommand -RegistryPath $RegistryPath -ExportPath $ExportPath
#Invoke-Expression $exportCommand
Expand Down
Loading

0 comments on commit c5f244c

Please sign in to comment.