CmdLets/Master/Sync-RegistrySettings.ps1

Function Sync-RegistrySettings 
 {
<#
.SYNOPSIS
    Applies and synchronizes a collection of registry settings, including prerequisite checks and custom script execution.
 
.DESCRIPTION
    The Sync-RegistrySettings function loops through an array of registry configuration objects,
    displaying a progress bar during execution. For each setting, it validates required properties
    (Path, Name, Value, and Type), executes any PreScriptBlocks, ensures the target registry path exists
    (creating it via New-ItemWrapper if necessary), updates or creates the registry property with the correct value
    and type, and finally runs any PostScriptBlocks.
 
.PARAMETER RegistrySettings
    An optional collection or array of registry setting objects. Each object typically includes:
    - Name: The name of the registry property/value.
    - Path: The registry path (e.g., "HKLM:\Software\MyApp").
    - Value: The value to set for the registry property.
    - Type: The registry type (e.g., String, DWord, Binary).
    - PreScriptBlocks: Optional array of string-based scripts to run before applying the setting.
    - PostScriptBlocks: Optional array of string-based scripts to run after applying the setting.
 
.EXAMPLE
    $Settings = @(
        [PSCustomObject]@{
            Name = "LogLevel"
            Path = "HKLM:\Software\MyApp"
            Value = 2
            Type = "DWord"
        }
    )
    Sync-RegistrySettings -RegistrySettings $Settings
     
    Description:
    Applies the specified registry setting, creating the path and property if they do not already exist.
 
.NOTES
    Prerequisites:
    - Depends on the New-ItemWrapper helper function for automatic parent registry key creation.
    - Requires administrative privileges to modify system-level registry keys (e.g., HKLM).
 
.LINK
    https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-itemproperty
#>

    [CmdletBinding()]
    Param(
        [Parameter(Mandatory=$False)]
            $RegistrySettings
    )

    ForEach ($RegistrySetting in $RegistrySettings) {
        $i++; Write-Progress -ID 0 -Activity "Synching Registry Settings" -Status "Syncing: $($RegistrySetting.Name)" -PercentComplete (($i/$RegistrySettings.Count)*100);
        Write-Host "Syncing: $($RegistrySetting.Name)"

        ForEach ($ScriptBlock in $RegistrySettings.PreScriptBlocks) { 
            Write-Verbose $ScriptBlock
            Invoke-Command -ScriptBlock ([ScriptBlock]::Create($ScriptBlock)) -NoNewScope
        }

        ForEach ($Property in @("Path","Name","Value","Type")) {
            If ($Property -notIn $RegistrySetting.psobject.Properties.Name) {
                Throw "Property $Property not found"
            } elseIf ($null -eq ($RegistrySetting.psobject.Properties | Where-Object { $_.Name -eq $Property }).Value){
                Throw "Property $Property is null"
            }
        }

        if (!(Test-Path $RegistrySetting.Path )) {
            New-ItemWrapper $RegistrySetting.Path 
        }
        If ((Get-Item $RegistrySetting.Path).Property -Contains $RegistrySetting.Name) {
            Set-ItemProperty `
                -Path $RegistrySetting.Path `
                -Name $RegistrySetting.Name `
                -Value $RegistrySetting.Value
        } else {
            New-ItemProperty `
                -Path $RegistrySetting.Path `
                -Name $RegistrySetting.Name `
                -Value $RegistrySetting.Value `
                -PropertyType $RegistrySetting.Type | out-null
        }
        ForEach ($ScriptBlock in $RegistrySettings.PostScriptBlocks) { 
            Write-Verbose $ScriptBlock
            Invoke-Command -ScriptBlock ([ScriptBlock]::Create($ScriptBlock)) -NoNewScope
        }
    }
    Write-Progress -ID 0 -Activity "Synching Registry Settings"  -Completed


}