Private/Core/ConfigManager.ps1
|
function ConvertTo-DATHashtable { <# .SYNOPSIS Recursively converts a PSCustomObject (from ConvertFrom-Json) to a hashtable. Required for PowerShell 5.1 compatibility since -AsHashtable was added in PS 6.0. #> param( [Parameter(ValueFromPipeline)] $InputObject ) process { if ($null -eq $InputObject) { return $null } if ($InputObject -is [System.Management.Automation.PSCustomObject]) { $Hash = @{} foreach ($Prop in $InputObject.PSObject.Properties) { $Hash[$Prop.Name] = ConvertTo-DATHashtable $Prop.Value } return $Hash } elseif ($InputObject -is [System.Collections.IEnumerable] -and $InputObject -isnot [string]) { $List = [System.Collections.Generic.List[object]]::new() foreach ($Item in $InputObject) { $List.Add((ConvertTo-DATHashtable $Item)) } return @(,$List.ToArray()) } else { return $InputObject } } } function Get-DATConfig { <# .SYNOPSIS Reads the DAT configuration from JSON file, merging with defaults. .PARAMETER ConfigFile Path to a specific config file. If not provided, uses the default settings path. #> [CmdletBinding()] param( [string]$ConfigFile ) if (-not $ConfigFile) { $ConfigFile = Join-Path $script:SettingsPath 'config.json' } # Load defaults first $Defaults = @{} if (Test-Path $script:DefaultsPath) { $Defaults = Get-Content $script:DefaultsPath -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue | ConvertTo-DATHashtable if (-not $Defaults) { $Defaults = @{} } } # Overlay user config if it exists if (Test-Path $ConfigFile) { $UserConfig = Get-Content $ConfigFile -Raw | ConvertFrom-Json -ErrorAction SilentlyContinue | ConvertTo-DATHashtable if ($UserConfig) { $Merged = Merge-DATHashtable -Base $Defaults -Override $UserConfig return $Merged } } return $Defaults } function Save-DATConfig { <# .SYNOPSIS Saves the current configuration to JSON file. #> [CmdletBinding()] param( [Parameter(Mandatory)] [hashtable]$Config, [string]$ConfigFile ) if (-not $ConfigFile) { $ConfigFile = Join-Path $script:SettingsPath 'config.json' } $Dir = Split-Path $ConfigFile -Parent if (-not (Test-Path $Dir)) { New-Item -Path $Dir -ItemType Directory -Force | Out-Null } $Config | ConvertTo-Json -Depth 10 | Set-Content -Path $ConfigFile -Encoding UTF8 Write-DATLog -Message "Configuration saved to $ConfigFile" -Severity 1 } function Merge-DATHashtable { <# .SYNOPSIS Deep-merges two hashtables, with Override values taking precedence. #> [CmdletBinding()] param( [hashtable]$Base, [hashtable]$Override ) $Result = $Base.Clone() foreach ($Key in $Override.Keys) { if ($Result.ContainsKey($Key) -and $Result[$Key] -is [hashtable] -and $Override[$Key] -is [hashtable]) { $Result[$Key] = Merge-DATHashtable -Base $Result[$Key] -Override $Override[$Key] } else { $Result[$Key] = $Override[$Key] } } return $Result } function Get-DATOEMSources { <# .SYNOPSIS Loads OEM catalog source URLs from OEMSources.json. #> [CmdletBinding()] param() if (-not (Test-Path $script:OEMSourcesPath)) { Write-DATLog -Message "OEMSources.json not found at $($script:OEMSourcesPath)" -Severity 3 throw "OEMSources.json not found. Run Update-DATCatalogSources to create it." } $Sources = Get-Content $script:OEMSourcesPath -Raw | ConvertFrom-Json | ConvertTo-DATHashtable return $Sources } function Get-DATWindowsBuilds { <# .SYNOPSIS Returns the Windows build mapping from OEMSources.json. #> [CmdletBinding()] param() $Sources = Get-DATOEMSources if ($Sources.windowsBuilds) { return $Sources.windowsBuilds } Write-DATLog -Message "No windowsBuilds section found in OEMSources.json" -Severity 2 return @{} } function Test-DATConfigValid { <# .SYNOPSIS Validates a configuration hashtable has required fields for a sync operation. .OUTPUTS Returns an array of validation error strings. Empty array means valid. #> [CmdletBinding()] param( [Parameter(Mandatory)] [hashtable]$Config ) $Errors = [System.Collections.Generic.List[string]]::new() if (-not $Config.manufacturers -or $Config.manufacturers.Count -eq 0) { $Errors.Add('No manufacturers specified.') } if (-not $Config.operatingSystem) { $Errors.Add('No operating system specified.') } if (-not $Config.paths) { $Errors.Add('No paths section in configuration.') } else { if (-not $Config.paths.download) { $Errors.Add('No download path specified.') } if (-not $Config.paths.package) { $Errors.Add('No package path specified.') } } if ($Config.sccm) { if (-not $Config.sccm.siteServer) { $Errors.Add('SCCM site server not specified.') } if (-not $Config.sccm.siteCode) { $Errors.Add('SCCM site code not specified.') } } return $Errors } function Convert-DATLegacySettings { <# .SYNOPSIS Migrates legacy DATSettings.xml to the new JSON config format. .PARAMETER XmlPath Path to the legacy DATSettings.xml file. .PARAMETER OutputPath Path for the new JSON config file. #> [CmdletBinding()] param( [Parameter(Mandatory)] [string]$XmlPath, [string]$OutputPath ) if (-not $OutputPath) { $OutputPath = Join-Path $script:SettingsPath 'config.json' } if (-not (Test-Path $XmlPath)) { throw "Legacy settings file not found: $XmlPath" } Write-DATLog -Message "Migrating legacy settings from $XmlPath" -Severity 1 [xml]$Xml = Get-Content $XmlPath -Raw $Config = @{ manufacturers = @() operatingSystem = '' architecture = 'x64' sccm = @{ siteServer = '' siteCode = '' useSSL = $false distributionPoints = @() distributionPointGroups = @() } paths = @{ download = '' package = '' } options = @{ removeLegacy = $false enableBDR = $true cleanSource = $false replicationPriority = 'Normal' } proxy = @{ enabled = $false server = '' } } # Map XML elements to config $SiteSettings = $Xml.Settings.SiteSettings if ($SiteSettings) { $Config.sccm.siteServer = $SiteSettings.Server $Config.sccm.siteCode = $SiteSettings.SiteCode if ($SiteSettings.WinRMSSL -eq 'True') { $Config.sccm.useSSL = $true } } $DownloadSettings = $Xml.Settings.DownloadSettings if ($DownloadSettings) { $Config.operatingSystem = $DownloadSettings.OSValue $Config.architecture = $DownloadSettings.ArchitectureValue } $StorageSettings = $Xml.Settings.StorageSettings if ($StorageSettings) { $Config.paths.download = $StorageSettings.DownloadPath $Config.paths.package = $StorageSettings.PackagePath } $ManufacturerSettings = $Xml.Settings.Manufacturer if ($ManufacturerSettings) { if ($ManufacturerSettings.Dell -eq 'True') { $Config.manufacturers += 'Dell' } if ($ManufacturerSettings.Lenovo -eq 'True') { $Config.manufacturers += 'Lenovo' } } $OptionsSettings = $Xml.Settings.Options if ($OptionsSettings) { if ($OptionsSettings.RemoveLegacyDrivers -eq 'True') { $Config.options.removeLegacy = $true } if ($OptionsSettings.EnableBinaryDif -eq 'True') { $Config.options.enableBDR = $true } if ($OptionsSettings.CleanUnused -eq 'True') { $Config.options.cleanSource = $true } } $ProxySettings = $Xml.Settings.ProxySettings if ($ProxySettings) { if ($ProxySettings.UseProxy -eq 'True') { $Config.proxy.enabled = $true $Config.proxy.server = $ProxySettings.ProxyServer } } Save-DATConfig -Config $Config -ConfigFile $OutputPath Write-DATLog -Message "Legacy settings migrated successfully to $OutputPath" -Severity 1 return $Config } |