Public/Set-DPConfig.ps1
|
function Set-DPConfig { <# .SYNOPSIS Sets DLLPickle configuration options. .DESCRIPTION Modifies DLLPickle configuration settings stored in the current user's application data folder. Configuration is persisted as a JSON file. If the configuration file does not exist, it is created with default values, then the specified settings are applied. Individual parameters can be updated independently without affecting other settings. Use the -Reset parameter to restore all configuration to defaults. .PARAMETER CheckForUpdates Enable or disable automatic check for updates when importing the DLLPickle module. Default value is $true if not specified. .PARAMETER ShowLogo Show or hide the DLLPickle logo during execution. Default value is $true if not specified. .PARAMETER SkipLibraries Array of library (DLL) filenames to skip during Import-DPLibrary operations (use for testing exclusions). Filenames should be specified without path (e.g., 'DLLPickle1.dll', 'DLLPickle2.dll'). .PARAMETER Reset Reset all configuration settings to defaults. When specified, all other parameters are ignored and the configuration file is overwritten with defaults. .PARAMETER PassThru Returns the updated configuration object. By default, no output is generated. .EXAMPLE Set-DPConfig -CheckForUpdates $false Disables automatic update checks while preserving other configuration settings. .EXAMPLE Set-DPConfig -SkipLibraries @('DLLPickle1.dll', 'DLLPickle2.dll') Sets the list of libraries to skip during import operations. .EXAMPLE Set-DPConfig -Reset Resets all configuration to defaults. .EXAMPLE Set-DPConfig -ShowLogo $false -PassThru Disables the DLLPickle logo and returns the updated configuration object. .OUTPUTS PSCustomObject When the -PassThru parameter is specified, returns a configuration object with properties: - CheckForUpdates [bool] - ShowLogo [bool] - SkipLibraries [string[]] .NOTES The function follows XDG standard conventions or standard Windows locations for application data files. #> [CmdletBinding( SupportsShouldProcess = $true, ConfirmImpact = 'Low' )] # Suppress warnings about PSAvoidUsingWriteHost since we want to provide user feedback on successful updates. [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'Provide user feedback on successful updates.')] # Suppress ShouldProcess analyzer guidance for this helper-style config writer. [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSShouldProcess', '', Justification = 'SupportsShouldProcess is retained for consistency, but only reset operation participates in WhatIf/Confirm semantics.')] [OutputType([PSCustomObject])] param( [Parameter( HelpMessage = 'Enable or disable automatic check for updates.' )] [bool]$CheckForUpdates, [Parameter( HelpMessage = 'Show or hide the DLLPickle logo during execution.' )] [bool]$ShowLogo, [Parameter( HelpMessage = 'List of library (DLL) filenames to skip during Import-DPLibrary.' )] [ValidateNotNull()] [string[]]$SkipLibraries, [Parameter( HelpMessage = 'Reset configuration to module defaults.' )] [switch]$Reset, [Parameter( HelpMessage = 'Return the updated configuration object.' )] [switch]$PassThru ) process { # Define configuration paths using .NET for cross-platform compatibility $AppData = [System.Environment]::GetFolderPath([System.Environment+SpecialFolder]::ApplicationData) $ConfigDir = Join-Path -Path $AppData -ChildPath 'DLLPickle' $ConfigFile = Join-Path -Path $ConfigDir -ChildPath 'config.json' # Define factory default settings $DefaultSettings = @{ CheckForUpdates = $true ShowLogo = $true SkipLibraries = @() } # Create the configuration directory if it doesn't exist if (-not (Test-Path -LiteralPath $ConfigDir -PathType Container)) { Write-Verbose "Creating configuration directory at '$ConfigDir'." try { New-Item -ItemType Directory -Path $ConfigDir -Force -ErrorAction Stop | Out-Null } catch { $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( [System.InvalidOperationException]::new( "Failed to create configuration directory at '$ConfigDir'.", $_.Exception ), 'DPConfigDirectoryCreateFailed', [System.Management.Automation.ErrorCategory]::WriteError, $ConfigDir ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } } # Load existing configuration or use defaults if ($Reset) { Write-Verbose 'Resetting configuration to module defaults.' if (-not $PSCmdlet.ShouldProcess($ConfigFile, 'Reset to module defaults')) { return } $CurrentSettings = $DefaultSettings.Clone() } elseif (Test-Path -LiteralPath $ConfigFile -PathType Leaf) { Write-Verbose "Loading existing configuration from '$ConfigFile'." try { $RawContent = Get-Content -LiteralPath $ConfigFile -Raw -ErrorAction Stop $ParsedConfig = $RawContent | ConvertFrom-Json -ErrorAction Stop $CurrentSettings = @{} foreach ($Property in $ParsedConfig.PSObject.Properties) { $CurrentSettings[$Property.Name] = $Property.Value } } catch { $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( [System.InvalidOperationException]::new( "Failed to load configuration from '$ConfigFile'. Using module defaults.", $_.Exception ), 'DPConfigReadFailed', [System.Management.Automation.ErrorCategory]::InvalidData, $ConfigFile ) $PSCmdlet.WriteError($ErrorRecord) $CurrentSettings = $DefaultSettings.Clone() } } else { Write-Verbose 'No existing configuration found. Using factory defaults.' $CurrentSettings = $DefaultSettings.Clone() } # Update only the values provided by the user if ($PSBoundParameters.ContainsKey('CheckForUpdates')) { $CurrentSettings.CheckForUpdates = $CheckForUpdates Write-Verbose "Set CheckForUpdates = $CheckForUpdates" } if ($PSBoundParameters.ContainsKey('ShowLogo')) { $CurrentSettings.ShowLogo = $ShowLogo Write-Verbose "Set ShowLogo = $ShowLogo" } if ($PSBoundParameters.ContainsKey('SkipLibraries')) { $CurrentSettings.SkipLibraries = @([string[]]$SkipLibraries) Write-Verbose "Set SkipLibraries = $($CurrentSettings.SkipLibraries -join ', ')" } # Normalize configuration shape to ensure expected types are always present. [string[]]$NormalizedSkipLibraries = @() if ($null -ne $CurrentSettings.SkipLibraries) { $NormalizedSkipLibraries = @($CurrentSettings.SkipLibraries | ForEach-Object { [string]$_ }) } $CurrentSettings = @{ CheckForUpdates = if ($null -ne $CurrentSettings.CheckForUpdates) { [bool]$CurrentSettings.CheckForUpdates } else { [bool]$DefaultSettings.CheckForUpdates } ShowLogo = if ($null -ne $CurrentSettings.ShowLogo) { [bool]$CurrentSettings.ShowLogo } else { [bool]$DefaultSettings.ShowLogo } SkipLibraries = $NormalizedSkipLibraries } # Write configuration to disk with error handling try { $JsonContent = $CurrentSettings | ConvertTo-Json -ErrorAction Stop if ($PSEdition -eq 'Core') { Set-Content -LiteralPath $ConfigFile -Value $JsonContent -Encoding 'utf8NoBOM' -Force -ErrorAction Stop } else { Set-Content -LiteralPath $ConfigFile -Value $JsonContent -Encoding 'utf8' -Force -ErrorAction Stop } Write-Verbose "Configuration saved to '$ConfigFile'." } catch { $ErrorRecord = [System.Management.Automation.ErrorRecord]::new( [System.InvalidOperationException]::new( "Failed to save configuration to '$ConfigFile'.", $_.Exception ), 'DPConfigWriteFailed', [System.Management.Automation.ErrorCategory]::WriteError, $ConfigFile ) $PSCmdlet.ThrowTerminatingError($ErrorRecord) } # Return the configuration if PassThru is specified if ($PassThru) { [PSCustomObject]$CurrentSettings } else { Write-Host 'Configuration updated successfully.' -ForegroundColor Green } } } |