dconf.psm1
#region private function Get-DconfPath { <# .DESCRIPTION Get all dconf paths that exist in the system. #> [CmdletBinding()] param ( [switch]$Flush ) if ($Flush -or -not $Script:DconfPaths) { $Dump = dconf dump / if (-not $?) { throw ($Dump | Out-String).Trim() } $KeyPaths = $Dump | Select-String '^\[(?<path>.*)\]$' | ForEach-Object Matches | ForEach-Object Groups | Where-Object Name -eq "path" | ForEach-Object Value # dconf dump omits paths that do not contain keys. For completions, we want those paths. # Assumption: dump output is ordered heirarchically $Last = "" $Script:DconfPaths = $KeyPaths | ForEach-Object { $Current = $_ while ($Last -and $Current -notmatch "^$Last/.*") { $Last = $Last -replace '[^/]+?$' -replace '/$' } while ($Current -ne $Last) { $NextSegment = $Current -replace $Last -replace '^/' -replace '/.*' $Last = $Last, $NextSegment -join '/' -replace '^/' $Last } } } $Script:DconfPaths } function Resolve-DconfPath { <# .DESCRIPTION Replaces relative paths with full paths in output from dconf dump. #> [CmdletBinding()] param ( [Parameter(Mandatory, Position = 0)] [Alias('Path')] [string]$BasePath, [Parameter(ValueFromPipeline, Mandatory, Position = 1)] [AllowEmptyString()] [string]$Text ) process { $Lines = $Text -split '\r?\n' foreach ($Line in $Lines) { # This path is relative to the path passed to dconf dump if ($Line -match '^\[(?<Path>.+)\]\s*$') { $Path = $BasePath, $Matches.Path -join '/' -replace '/{2,}', '/' -replace '^/' -replace '/$' "[$Path]" } else { $Line } } } end {""} } function Set-Dconf { <# .DESCRIPTION Imports dconf settings. .EXAMPLE dconf dump / > dump.txt Get-Content dump.txt | Set-Dconf #> [CmdletBinding()] param ( [Parameter(Position = 0)] [string]$Path = '/', [Parameter(Mandatory, ValueFromPipeline, Position = 1)] [AllowEmptyString()] [string[]]$InputObject, [string[]]$Filter ) end { $Path = $Path -replace '^/?', '/' -replace '(?<=[^/])$', '/' $_Path = $Path if ($Filter) { $Filter = @($Filter) -replace '^/?', '/' -replace '(?<=[^/])$', '/' } if ($MyInvocation.ExpectingInput) { $InputObject = $input } # Can't get past error: "Key file contains line [some_group] which is not a key-value pair, group, or comment" # So we use dconf write instead of dconf load $Lines = ($InputObject | Out-String).Trim() -split '\r?\n' foreach ($Line in $Lines) { if ([string]::IsNullOrWhiteSpace($Line) -or $Line.StartsWith('#')) { continue } elseif ($Line -match '^\[(?<Path>.+)\]\s*$') { $_Path = $( $MatchedPath = $Matches.Path if ($MatchedPath -eq '/') { $Path -replace '/$' } elseif ($MatchedPath -match '^/.') { $MatchedPath } else { $Path, $MatchedPath -join '/' -replace '/{2,}', '/' } ) $ShouldSkip = $Filter -and -not ($Filter | Where-Object {$_Path -ilike "$_*"}) if ($ShouldSkip) {Write-Verbose "Skipping $_Path"} continue } if ($ShouldSkip) {continue} $Key, $Value = $Line -split '=', 2 $FullKey = $_Path, $Key -join '/' -replace '/{2,}', '/' dconf write $FullKey "$Value" if (-not $?) { Write-Error "Failed to write '$Value' to '$FullKey'" } } } } #endregion private #region public function Export-Dconf { <# .SYNOPSIS Exports dconf settings. .DESCRIPTION Exports dconf settings within a given dconf path to stdout or to file. Wraps `dconf dump` and converts dconf paths to absolute paths. .PARAMETER Path The dconf path to export. .PARAMETER OutFile The file to export to. By default, this command writes to stdout. .EXAMPLE Export-Dconf org/gnome/shell/extensions ./dconf.dump Exports settings under `/org/gnome/shell/extensions/` to `dconf.dump`. #> [CmdletBinding()] param ( [Parameter(Position = 0)] [string[]]$Path = "/", [Parameter(Position = 1)] [string]$OutFile ) $Content = @() foreach ($_Path in $Path) { $_Path = $_Path -replace '^/?', '/' -replace '(?<=[^/])$', '/' $Content += dconf dump $_Path | Resolve-DconfPath -Path $_Path } $Content = ($Content | Out-String).Trim() if ($OutFile) { $Content > $OutFile } elseif ($Content) { $Content } } function Import-Dconf { <# .SYNOPSIS Imports dconf settings from file. .DESCRIPTION Imports dconf settings from file. Backs up all settings before importing. .PARAMETER File Path to file containing dconf settings. The file can be generated with `Export-Dconf` or with `dconf dump /`. Content should be key-value pairs, section headers in square brackets. Note that when using `dconf dump`, the section headers will be relative to the path passed to `dconf dump`. If this was not `/` (the root path), then the import will succeed, but incorrect paths and keys will be created. Export-Dconf prevents this by resolving paths to absolute paths. .PARAMETER Filter Limit the dconf paths to import. Only keys that are children of the dconf paths will be imported. .PARAMETER SkipBackup Do not back up dconf settings before import. .PARAMETER BackupPath Path to backup file. By default, this will be `/tmp/dconf.xxxxxxxxxxxxxxxxxx`. .EXAMPLE Import-Dconf -File ./dconf.dump Imports all settings from `dconf.dump`. .EXAMPLE Import-Dconf -File ./dconf.dump -Filter org/gnome/shell/extensions Imports settings under `/org/gnome/shell/extensions/` from `dconf.dump`. #> [CmdletBinding()] param ( [Parameter(Mandatory, Position = 0)] [string]$File, [string[]]$Filter, [switch]$SkipBackup, [string]$BackupPath = (Join-Path ([IO.Path]::GetTempPath()) "dconf.$([datetime]::UtcNow.Ticks)") ) end { if (-not $SkipBackup) { Export-Dconf / -OutFile $BackupPath "Backed up dconf settings to $BackupPath" | Write-Verbose } $Content = Get-Content $File -ErrorAction Stop $Content | Set-Dconf -Filter $Filter } } #endregion public $PathCompleter = { param ($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters) $HasLeadingSlash = $wordToComplete -match '^/' $wordToComplete = $wordToComplete -replace '^/' $Paths = @(Get-DconfPath) -ilike "*$wordToComplete*" $DirectChildren = @($Paths) -imatch "^$wordToComplete([^/]*)$" $Paths = $DirectChildren, $Paths | Write-Output | Select-Object -Unique if ($HasLeadingSlash) { $Paths = @($Paths) -replace '^/?', '/' } $Paths } Register-ArgumentCompleter -CommandName Set-Dconf, Export-Dconf -ParameterName Path -ScriptBlock $PathCompleter Register-ArgumentCompleter -CommandName Import-Dconf -ParameterName Filter -ScriptBlock $PathCompleter |