Public/Set-TbConfig.ps1

function Set-TbConfig {
    <#
    .SYNOPSIS
        Updates Toolbox module configuration settings.
     
    .DESCRIPTION
        Modifies configuration settings for the Toolbox module. Changes are saved
        to the configuration file and applied immediately.
     
    .PARAMETER Section
        Configuration section to update (e.g., "Execution", "Logging", "Tasks").
     
    .PARAMETER Property
        Property name to update within the specified section.
     
    .PARAMETER Value
        New value for the property.
     
    .PARAMETER Reset
        Resets the configuration to default values.
     
    .EXAMPLE
        Set-TbConfig -Section Execution -Property DefaultThrottle -Value 64
        Sets the default throttle to 64 concurrent runspaces.
     
    .EXAMPLE
        Set-TbConfig -Section Logging -Property LogLevel -Value "Verbose"
        Sets the log level to Verbose.
     
    .EXAMPLE
        Set-TbConfig -Reset
        Resets all configuration to default values.
     
    .EXAMPLE
        Set-TbConfig -Section Logging -Property MaxLogFileSizeMB -Value 100
        Increases maximum log file size to 100 MB.
     
    .EXAMPLE
        Set-TbConfig -Section Execution -Property DefaultTimeout -Value 300
        Sets default task timeout to 5 minutes (300 seconds).
     
    .EXAMPLE
        Set-TbConfig -Section Export -Property DefaultFormat -Value "Excel"
        Sets Excel as the default export format.
     
    .NOTES
        Changes are persisted to disk and take effect immediately.
        Use Get-TbConfig to view current settings before making changes.
        Invalid property names or values will generate errors.
    #>

    [CmdletBinding(SupportsShouldProcess, DefaultParameterSetName = "Update")]
    param(
        [Parameter(Mandatory, ParameterSetName = "Update", Position = 0)]
        [ValidateSet("Execution", "Logging", "Tasks", "Session", "Export")]
        [string]$Section,
        
        [Parameter(Mandatory, ParameterSetName = "Update", Position = 1)]
        [string]$Property,
        
        [Parameter(Mandatory, ParameterSetName = "Update", Position = 2)]
        [object]$Value,
        
        [Parameter(Mandatory, ParameterSetName = "Reset")]
        [switch]$Reset
    )
    
    # Ensure configuration is loaded
    if (-not $script:ModuleConfig) {
        Initialize-TbConfig
    }
    
    try {
        if ($Reset) {
            if ($PSCmdlet.ShouldProcess("Configuration", "Reset to defaults")) {
                # Load default configuration
                $defaultConfigPath = Join-Path $script:ModuleRoot "Config\Config.Default.json"
                $config = Get-Content -Path $defaultConfigPath -Raw | ConvertFrom-Json
                
                # Set dynamic paths
                $configDir = Split-Path $script:ConfigPath -Parent
                $config.Logging.LogPath = Join-Path $configDir "Logs"
                $config.Tasks.BuiltInTaskPath = Join-Path $script:ModuleRoot "Tasks\BuiltIn"
                $config.Tasks.SystemTaskPath = Join-Path $env:ProgramData "Toolbox\Tasks"
                $config.Tasks.UserTaskPath = Join-Path $env:APPDATA "Toolbox\Tasks"
                
                # Update module config
                $script:ModuleConfig = $config
                
                # Save to disk
                $config | ConvertTo-Json -Depth 10 | Set-Content -Path $script:ConfigPath -Force
                
                Write-Verbose "Configuration reset to defaults"
                return $script:ModuleConfig
            }
        }
        else {
            # Validate section exists
            if (-not $script:ModuleConfig.$Section) {
                Write-Error "Configuration section "$Section" not found"
                return
            }
            
            # Validate property exists
            if (-not ($script:ModuleConfig.$Section.PSObject.Properties.Name -contains $Property)) {
                Write-Error "Property "$Property" not found in section "$Section""
                return
            }
            
            # Get current value for comparison
            $currentValue = $script:ModuleConfig.$Section.$Property
            
            # Validate value type matches
            if ($null -ne $currentValue) {
                $expectedType = $currentValue.GetType()
                if ($Value.GetType() -ne $expectedType) {
                    # Try to convert
                    try {
                        $Value = $Value -as $expectedType
                        if ($null -eq $Value) {
                            Write-Error "Cannot convert value to expected type: $($expectedType.Name)"
                            return
                        }
                    }
                    catch {
                        Write-Error "Invalid value type. Expected: $($expectedType.Name)"
                        return
                    }
                }
            }
            
            # Perform validation based on property
            if (-not (Test-ConfigValue -Section $Section -Property $Property -Value $Value)) {
                return
            }
            
            if ($PSCmdlet.ShouldProcess("$Section.$Property", "Set to '$Value'")) {
                # Update the configuration
                $script:ModuleConfig.$Section.$Property = $Value
                
                # Save to disk
                $script:ModuleConfig | ConvertTo-Json -Depth 10 | Set-Content -Path $script:ConfigPath -Force
                
                Write-Verbose "Configuration updated: $Section.$Property = $Value"
                
                # Return the updated section
                return $script:ModuleConfig.$Section
            }
        }
    }
    catch {
        Write-Error "Failed to update configuration: $_"
    }
}

function Test-ConfigValue {
    <#
    .SYNOPSIS
        Validates configuration values.
    #>

    param(
        [string]$Section,
        [string]$Property,
        [object]$Value
    )
    
    # Validation rules
    switch ("$Section.$Property") {
        "Execution.DefaultThrottle" {
            if ($Value -lt 1 -or $Value -gt 256) {
                Write-Error "DefaultThrottle must be between 1 and 256"
                return $false
            }
        }
        "Execution.DefaultTimeout" {
            if ($Value -lt 1) {
                Write-Error "DefaultTimeout must be greater than 0"
                return $false
            }
        }
        "Execution.DefaultRetryCount" {
            if ($Value -lt 0) {
                Write-Error "DefaultRetryCount must be 0 or greater"
                return $false
            }
        }
        "Execution.RetryDelaySeconds" {
            if ($Value -lt 1) {
                Write-Error "RetryDelaySeconds must be greater than 0"
                return $false
            }
        }
        "Execution.RetryBackoffMultiplier" {
            if ($Value -lt 1.0) {
                Write-Error "RetryBackoffMultiplier must be 1.0 or greater"
                return $false
            }
        }
        "Logging.LogLevel" {
            $validLevels = @("Verbose", "Info", "Warning", "Error")
            if ($Value -notin $validLevels) {
                Write-Error "LogLevel must be one of: $($validLevels -join ", ")"
                return $false
            }
        }
        "Logging.MaxLogFileSizeMB" {
            if ($Value -lt 1) {
                Write-Error "MaxLogFileSizeMB must be greater than 0"
                return $false
            }
        }
        "Logging.MaxLogFiles" {
            if ($Value -lt 1) {
                Write-Error "MaxLogFiles must be greater than 0"
                return $false
            }
        }
        "Session.DefaultProtocol" {
            $validProtocols = @("WinRM", "SSH", "Auto")
            if ($Value -notin $validProtocols) {
                Write-Error "DefaultProtocol must be one of: $($validProtocols -join ", ")"
                return $false
            }
        }
        "Session.SessionTimeoutSeconds" {
            if ($Value -lt 60) {
                Write-Error "SessionTimeoutSeconds must be at least 60"
                return $false
            }
        }
        "Export.DefaultFormat" {
            $validFormats = @("CSV", "JSON", "XML", "Excel")
            if ($Value -notin $validFormats) {
                Write-Error "DefaultFormat must be one of: $($validFormats -join ", ")"
                return $false
            }
        }
    }
    
    return $true
}