Modules/businessdev.ALbuild.Core/Public/Set-ALbuildConfig.ps1
|
function Set-ALbuildConfig { <# .SYNOPSIS Sets one or more ALbuild configuration values. .DESCRIPTION Applies overrides on top of the current configuration. By default the override lives for the session only; with -Persist it is written to a config file so it survives future sessions. -Persist writes the MACHINE-WIDE file by default. These are properties of the server - which drive holds the artifact cache, where the AL Tool lives - and every account has to agree on them. Writing them per user is what let one server carry two artifact caches: the agent account had 'G:\alb' in its own profile while an administrator read the built-in default 'C:\alb'. Only settings that DIFFER from the built-in defaults are written. The file therefore stays a short, readable statement of what this machine does differently, and a value ALbuild changes in a later release (a licensing endpoint, a retry count) still reaches the agent instead of being frozen by a file that once captured every key. .PARAMETER Settings A hashtable of setting name/value pairs to apply. .PARAMETER Persist Persists the configuration to the file for -Scope. .PARAMETER Scope Machine (default) - the shared file under the common application-data folder ('C:\ProgramData\ALbuild\config.json'). Requires elevation on Windows, which is the point: a machine-wide setting should take an administrator. User - the per-user file under the roaming application-data folder. Ranks BELOW the machine file when both exist (see Get-ALbuildConfig), so use it for a personal developer box, never to configure a build agent. ALBUILD_CONFIG, when set, overrides both. .EXAMPLE Set-ALbuildConfig -Settings @{ ProcessRetryCount = 5; TelemetryEnabled = $true } .EXAMPLE Set-ALbuildConfig -Settings @{ BaseFolder = 'G:\alb'; ArtifactCacheFolder = 'G:\alb\artifacts'; PackageCacheFolder = 'G:\alb\packages'; BcArtifactCacheFolder = 'G:\bcartifacts.cache' } -Persist Points the whole machine at drive G:. Run elevated; every account then sees it. .OUTPUTS System.Collections.Specialized.OrderedDictionary (the updated configuration). #> [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')] param( [Parameter(Mandatory, Position = 0)] [ValidateNotNull()] [hashtable] $Settings, [switch] $Persist, [ValidateSet('Machine', 'User')] [string] $Scope = 'Machine' ) if (-not $script:ALbuildConfigOverrides) { $script:ALbuildConfigOverrides = @{} } # Validate against the known settings before storing, so an invalid key never poisons state. $known = ([ALbuildConfig]::new()).Keys() foreach ($key in $Settings.Keys) { if ($known -notcontains $key) { throw "Unknown ALbuild configuration setting '$key'. Known settings: $($known -join ', ')." } $script:ALbuildConfigOverrides[$key] = $Settings[$key] } # Rebuild the cached effective config so callers see the change immediately. $effective = Get-ALbuildConfig -Refresh if ($Persist) { $configPath = Get-ALbuildConfigPath -Scope $Scope # Fail BEFORE touching anything, with the remedy in the message. Writing under ProgramData without # elevation otherwise ends in a bare UnauthorizedAccessException that says nothing about scope. if ($Scope -eq 'Machine' -and -not $env:ALBUILD_CONFIG -and -not (Test-ALbuildElevated)) { $who = try { [System.Security.Principal.WindowsIdentity]::GetCurrent().Name } catch { $env:USERNAME } throw ("Writing the machine-wide ALbuild configuration to '$configPath' requires an elevated " + "session (current user: $who). Start PowerShell as administrator, or use -Scope User for a " + 'per-user setting - but note that a per-user file does NOT apply to build agents or other ' + 'accounts on this machine.') } if ($PSCmdlet.ShouldProcess($configPath, "Persist ALbuild configuration ($Scope scope)")) { try { $dir = Split-Path -Path $configPath -Parent if (-not (Test-Path -LiteralPath $dir)) { New-Item -Path $dir -ItemType Directory -Force | Out-Null } # Sparse: only what differs from the built-in defaults. $defaults = ([ALbuildConfig]::new()).ToOrderedDictionary() $current = $effective.ToOrderedDictionary() $toWrite = [ordered] @{} foreach ($key in $current.Keys) { if ("$($current[$key])" -ne "$($defaults[$key])") { $toWrite[$key] = $current[$key] } } ($toWrite | ConvertTo-Json -Depth 10) | Set-Content -LiteralPath $configPath -Encoding UTF8 Write-Verbose "ALbuild: persisted $($toWrite.Count) non-default setting(s) to '$configPath' ($Scope scope)." } catch { throw "Failed to persist ALbuild configuration to '$configPath': $($_.Exception.Message)" } } } return $effective } |