Classes/specregistry.ps1

# Define enum for RegistryType
enum RegistryType {
    String
    ExpandString
    Binary
    DWord
    MultiString
    QWord
}

# Define the specRegistry class
class specRegistry {
    <#
    .SYNOPSIS
        The specRegistry class provides methods for interacting with the Windows Registry, including retrieving, adding, modifying, and deleting Registry keys and values.
 
    .DESCRIPTION
        This class allows users to manipulate Registry keys and values in the Windows Registry. It supports various value types, including strings, binary, DWORD, QWORD, and more.
        Users can retrieve Registry data, create new keys or values, modify existing values, and delete Registry entries. Error handling is provided to manage cases where Registry paths or names do not exist.
 
    .PARAMETER Hive
        The root hive of the Registry (e.g., 'HKCU', 'HKLM'). Must end with a colon (e.g., 'HKCU:'). This is handled by the `EnsureHiveFormat` method.
 
    .PARAMETER KeyPath
        The path of the Registry key relative to the specified Hive (e.g., 'Software\MyApp').
 
    .PARAMETER ValueName
        The name of the Registry value to interact with.
 
    .PARAMETER ValueData
        The data associated with the Registry value. This is optional and only required for methods like `AddData` and `ModifyData`.
 
    .PARAMETER ValueType
        The type of the specRegistry value. This can be one of the following:
        - String
        - ExpandString
        - Binary
        - DWord
        - MultiString
        - QWord
 
    .OUTPUTS
        Varies depending on the method used. Methods may return strings, booleans, or throw errors.
 
    .NOTES
        The class provides utility methods for common specRegistry operations, such as:
        - Retrieving data (`GetData`)
        - Adding new Registry keys (`AddKey`)
        - Modifying existing values (`ModifyData`)
        - Deleting Registry entries (`DeleteData`)
 
    .EXAMPLE
        # Example: Retrieve a Registry value
        $reg = [specRegistry]::new("HKCU:", "Software\MyApp", "AppVersion")
        $appVersion = $reg.GetData()
        Write-Output $appVersion
 
        This example retrieves the "AppVersion" value from the Registry path "HKCU:\Software\MyApp".
 
    .EXAMPLE
        # Example: Add a new Registry value
        $reg = [specRegistry]::new("HKCU:", "Software\MyApp", "AppVersion", "1.0", [RegistryType]::String)
        $reg.AddData()
 
        This example adds a new "AppVersion" specRegistry value of type `String` with the data "1.0" in the specRegistry path "HKCU:\Software\MyApp".
 
    .EXAMPLE
        # Example: Modify an existing Registry value
        $reg = [specRegistry]::new("HKCU:", "Software\MyApp", "AppVersion", "2.0", [RegistryType]::String)
        $reg.ModifyData()
 
        This example modifies the "AppVersion" value in "HKCU:\Software\MyApp" to "2.0".
 
    .EXAMPLE
        # Example: Delete a Registry value
        $reg = [specRegistry]::new("HKCU:", "Software\MyApp", "AppVersion")
        $reg.DeleteData()
 
        This example deletes the "AppVersion" value from the Registry path "HKCU:\Software\MyApp".
 
    .EXAMPLE
        # Example: Add a new Registry key
        $reg = [specRegistry]::new("HKCU:", "Software\NewApp", $null)
        $reg.AddKey()
 
        This example creates a new Registry key "HKCU:\Software\NewApp".
 
    .EXAMPLE
        # Example: Check if a Registry value exists
        $reg = [specRegistry]::new("HKCU:", "Software\MyApp", "AppVersion")
        $exists = $reg.NameExists()
        if ($exists) {
            Write-Output "The Registry value exists."
        } else {
            Write-Output "The Registry value does not exist."
        }
 
        This example checks whether the "AppVersion" value exists in the specRegistry path "HKCU:\Software\MyApp".
 
    .NOTES
        Author: owen.heaume
        Version: 1.0 - Initial release
                 1.1 - Change write-host to 'throw' for better error-handling in calling script
    #>


    [string]$Hive
    [string]$KeyPath
    [string]$ValueName
    [string]$ValueData
    [RegistryType]$ValueType


    # Constructor for GetData
    specRegistry([string]$Hive, [string]$KeyPath) {
        $this.Hive = $Hive
        $this.KeyPath = $KeyPath
    }



    # Constructor for GetData
    specRegistry([string]$Hive, [string]$KeyPath, [string]$ValueName) {
        $this.Hive = $Hive
        $this.KeyPath = $KeyPath
        $this.ValueName = $ValueName
    }





    # Constructor for other methods (Using Null as default values so one constructor fits all!)
    specRegistry([string]$Hive, [string]$KeyPath, [string]$ValueName, [string]$ValueData = $null, [RegistryType]$ValueType = $null) {
        $this.Hive = $Hive
        $this.KeyPath = $KeyPath
        $this.ValueName = $ValueName
        $this.ValueData = $ValueData
        $this.ValueType = $ValueType
    }


    # Private method to ensure the hive ends with a colon
    Hidden [string]EnsureHiveFormat() {
        if (!($this.Hive.EndsWith(':'))) {
            $this.Hive += ':'
        }
        return $this.Hive
    }

    [bool]GetKeyPath() {
        if (!(Test-Path -Path "$($this.Hive)\$($this.KeyPath)")) {
            return $false
        } else {
            return $true
        }
    }

    # Method to get a Registry value (data)
    [string]GetData() {

        # Format the Hive
        $this.EnsureHiveFormat()

        if (-not $this.GetKeyPath()) {
            throw "Registry path '$($this.Hive)\$($this.KeyPath)' does not exist."
        }

        try {
            # Attempt to get the Registry name
            $item = Get-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -ErrorAction Stop
            return $item.$($this.ValueName)
        } catch {
            # Handle errors
            throw "Unable to retrieve the value. Error: $_"
        }
    }

    # Method to get the Registry data type
    [String]GetDataType() {
        # Format the Hive
        $this.EnsureHiveFormat()

        if (-not $this.GetKeyPath()) {
            throw "Registry path '$($this.Hive)\$($this.KeyPath)' does not exist."
        }

        # Open the Registry key
        try {
            $registryPath = "$($this.Hive)\$($this.KeyPath)"
            $registryKey = Get-Item -Path $registryPath

            # Get the value type
            $valueKind = $registryKey.GetValueKind($this.ValueName)

            switch ($valueKind) {
                'String' {
                    return 'REG_SZ'
                }
                'ExpandString' {
                    return 'REG_EXPAND_SZ'
                }
                'Binary' {
                    return 'REG_BINARY'
                }
                'DWord' {
                    return 'REG_DWORD'
                }
                'MultiString' {
                    return 'REG_MULTI_SZ'
                }
                'QWord' {
                    return 'REG_QWORD'
                }
                default {
                    return "Unknown Registry value type: $valueKind"
                }
            }
        } catch {
            throw "Unable to retrieve the value type. Error: $_"
        }
        return $null # Gah..stupid powershell - or I just don't understand! Without this the method generates an error saying not all paths return, which is STUPID as we have a 'default' in the switch!!!
    }

    # Method to add a new key
    [bool]AddKey() {
        # Format the Hive
        $this.EnsureHiveFormat()

        if ($this.GetKeyPath()) {
            throw "Registry path '$($this.Hive)\$($this.KeyPath)' already exists."
        }

        try {
            # Create the new Registry key
            New-Item -Path "$($this.Hive)\$($this.KeyPath)" -Force | Out-Null
            return $true
        } catch {
            throw "Unable to create the Registry key. Error: $_"
        }
    }

    # method to test if the value name already exists
    [bool]NameExists() {
        # Format the Hive
        $this.EnsureHiveFormat()

        # Attempt to get the Registry name without raising an error
        $item = Get-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -ErrorAction SilentlyContinue

        return $null -ne $item
    }

    # Method to add a new value (data)
    [bool]AddData() {
        # Format the Hive
        $this.EnsureHiveFormat()

        # If any part of the fullpath exists including the valuename, then throw an error
        if ($this.NameExists()) {
            throw "Registry name '$($this.Hive)\$($this.KeyPath)\$($this.ValueName)' already exists."
        }

        # If the key path doesn't exist then create it
        if (-not $this.GetKeyPath()) {
            $this.AddKey()
        }

        try {
            # Create the new Registry value with data and type using a switch to cover all data types
            switch ($this.ValueType) {
                'String' {
                    New-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value $this.ValueData -PropertyType String -Force | Out-Null
                    return $true
                }
                'ExpandString' {
                    New-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value $this.ValueData -PropertyType ExpandString -Force | Out-Null
                    return $true
                }
                'Binary' {
                    New-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value $this.ValueData -PropertyType Binary -Force | Out-Null
                    return $true
                }
                'DWord' {
                    New-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value ([int]$this.ValueData) -PropertyType DWord -Force | Out-Null
                    return $true
                }
                'MultiString' {
                    New-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value $this.ValueData -PropertyType MultiString -Force | Out-Null
                    return $true
                }
                'QWord' {
                    New-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value ([long]$this.ValueData) -PropertyType QWord -Force | Out-Null
                    return $true
                }
                default {
                    throw "Unknown Registry value type: $($this.ValueType)"
                }
            }
        } catch {
            throw "Unable to create the Registry value. Error: $_"
        }
        return $null
    }

    # Method to modify an existing value (data)
    [bool]ModifyData() {
        # Format the Hive
        $this.EnsureHiveFormat()

        # If the key path doesn't exist then create it
        if (-not $this.GetKeyPath()) {
            $this.AddKey()
        }

        try {
            # Modify the Registry value with data and type using a switch to cover all data types
            switch ($this.ValueType) {
                'String' {
                    Set-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value $this.ValueData -Type String -Force | Out-Null
                    return $true
                }
                'ExpandString' {
                    Set-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value $this.ValueData -Type ExpandString -Force | Out-Null
                    return $true
                }
                'Binary' {
                    Set-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value $this.ValueData -Type Binary -Force | Out-Null
                    return $true
                }
                'DWord' {
                    Set-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value ([int]$this.ValueData) -Type DWord -Force | Out-Null
                    return $true
                }
                'MultiString' {
                    Set-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value $this.ValueData -Type MultiString -Force | Out-Null
                    return $true
                }
                'QWord' {
                    Set-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Value ([long]$this.ValueData) -Type QWord -Force | Out-Null
                    return $true
                }
                default {
                    throw "Unknown Registry value type: $($this.ValueType)"
                }
            }
        } catch {
            throw "Unable to modify the Registry value. Error: $_"
        }
        return $null
    }

    # Method to delete a Registry name and data
    [bool]DeleteData() {
        # Format the Hive
        $this.EnsureHiveFormat()

        # If the key path doesn't exist, throw an error
        if (-not (Test-Path -Path "$($this.Hive)\$($this.KeyPath)")) {
            throw "Registry path '$($this.Hive)\$($this.KeyPath)' does not exist."
        }

        # If the value name doesn't exist, throw an error
        $item = Get-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -ErrorAction SilentlyContinue
        if ($null -eq $item) {
            throw "Registry name '$($this.Hive)\$($this.KeyPath)\$($this.ValueName)' does not exist."
        }

        try {
            # Delete the Registry value
            Remove-ItemProperty -Path "$($this.Hive)\$($this.KeyPath)" -Name $this.ValueName -Force | Out-Null
            return $true
        } catch {
            throw "Unable to delete the Registry value. Error: $_"
        }
    }
}