config.psm1
Set-StrictMode -Version Latest function Find-LocalConfigPath { param ( [Parameter(Mandatory)][String] $Dir, [Parameter(Mandatory)][String] $Name ) while ($true) { if ($Dir -eq $Env:USERPROFILE -or [String]::IsNullOrEmpty($Dir)) { $null return } $test = Join-Path $Dir $Name if (Test-Path $test) { $test return } $Dir = Split-Path $Dir -Parent } } function Copy-HashtableDeeply { param ( [Hashtable] $Hashtable ) $result = @{} foreach ($key in $Hashtable.Keys) { $item = $Hashtable[$key] if ($item -is [Hashtable]) { $result.Add($key, (Copy-HashtableDeeply $item)) continue } if ($item -is [System.ICloneable]) { $result.Add($key, $item.Clone()) continue } $result.Add($key, $item) } $result } # right-biased. function Join-Hashtables { param ( [Hashtable[]] $Hashtables, [Switch] $Breaking = $false ) if ($null -eq $Hashtables -or @() -eq $Hashtables) { $null return } $result = $null foreach ($h in $Hashtables) { if ($null -eq $h) { continue } if ($null -eq $result) { if ($Breaking) { $result = $h } else { $result = Copy-HashtableDeeply $h } continue } foreach ($key in $h.Keys) { $value = $h[$key] if ($result.ContainsKey($key)) { if ($value -is [Hashtable]) { if ($null -ne $result[$key]) { [void] (Join-Hashtables $result[$key], $value -Breaking) } else { $result.Remove($key) $result.Add($key, $h[$key]) } } else { $result.Remove($key) $result.Add($key, $h[$key]) } } else { $result.Add($key, $h[$key]) } } } $result } # .SYNOPSIS # Find and read configurations. This returns a joined hashtable. # # .PARAMETER $Name # A name of an application. # # .DESCRIPTION # When the Name parameter is “foo”, this searches configuration files that named “config.yaml” in “$Env:ProgramData\$Name”, “$Env:APPDATA\$Name” # and “$Name.yaml” in the current working directory or its parents recursively. function Get-Config { param ( [Parameter(Mandatory)][String] $Name ) $systemGlobalDataPath = "$Env:ProgramData\$Name" $userGlobalDataPath = "$Env:APPDATA\$Name" $localConfigName = "$Name.yaml" $globalConfigName = 'config.yaml' $localConfigPath = Find-LocalConfigPath (Get-Location) $localConfigName $configPaths = "$systemGlobalDataPath\$globalConfigName", "$userGlobalDataPath\$globalConfigName", $localConfigPath $configs = @() foreach ($path in $configPaths) { if ($null -ne $path -and (Test-Path $path)) { $configs += ConvertFrom-Yaml (Get-Content $path -Raw) } } Join-Hashtables $configs } # .SYNOPSIS # Get an specified item in a hashtable. # # .PARAMETER Name # An array of nested keys. # # .PARAMETER Hashtable # A target. function Get-HashtaleItem { param ( [Parameter(Mandatory)][Object[]] $Name, [Hashtable] $Hashtable ) $item = $Hashtable foreach ($n in $Name) { if ($null -eq $item) { $null return } $item = $item[$n] } $item } Export-ModuleMember -Function Get-Config, Get-HashtaleItem |