private/functions/Export-PowerStubConfiguration.ps1
|
<# .SYNOPSIS Exports configuration to the configuration file. .DESCRIPTION Serializes the current configuration (excluding internal keys) to JSON and writes it to the config file using atomic write (temp + rename). .INPUTS None. You cannot pipe objects to this function. .OUTPUTS None. #> function Export-PowerStubConfiguration { $noExport = Get-PowerStubConfigurationKey 'InternalConfigKeys' $fileName = Get-PowerStubConfigurationKey 'ConfigFile' # Ensure config directory exists $configDir = Split-Path $fileName -Parent if (-not (Test-Path $configDir)) { New-Item -ItemType Directory -Path $configDir -Force | Out-Null } $exportConfig = @{} foreach ($key in $Script:PSTBSettings.Keys) { #do not export values for internal keys if ($noExport -contains $key) { continue } $exportConfig[$key] = $Script:PSTBSettings[$key] } $tempFile = Join-Path $configDir "$([System.IO.Path]::GetFileName($fileName)).$PID.$([guid]::NewGuid()).tmp" $lock = $null try { $lock = Enter-PowerStubConfigurationLock # Atomic write: write to a process-unique temp file, then rename into place. $exportConfig | ConvertTo-Json -Depth 20 | Set-Content -LiteralPath $tempFile -Encoding UTF8 # File.Move with overwrite replaces the destination in one step. Move-Item -Force # deletes the destination first, leaving a window where readers see no config. # The move fails briefly while another process has the config open for reading, so retry. for ($attempt = 1; ; $attempt++) { try { [System.IO.File]::Move($tempFile, $fileName, $true) break } catch [System.UnauthorizedAccessException], [System.IO.IOException] { if ($attempt -ge 20) { throw } Start-Sleep -Milliseconds 25 } } $Script:PSTBSettings['ConfigFileLastWriteUtc'] = (Get-Item -LiteralPath $fileName).LastWriteTimeUtc } finally { if (Test-Path -LiteralPath $tempFile) { Remove-Item -LiteralPath $tempFile -Force -ErrorAction SilentlyContinue } Exit-PowerStubConfigurationLock $lock } } |