internal/configurationschemata/metajson.ps1
Register-PSFConfigSchema -Name MetaJson -Schema { param ( [string] $Resource, [System.Collections.Hashtable] $Settings ) Write-PSFMessage -String 'Configuration.Schema.MetaJson.ProcessResource' -StringValues $Resource -ModuleName PSFramework #region Converting parameters $Peek = $Settings["Peek"] $ExcludeFilter = $Settings["ExcludeFilter"] $IncludeFilter = $Settings["IncludeFilter"] $AllowDelete = $Settings["AllowDelete"] $script:EnableException = $Settings["EnableException"] $script:cmdlet = $Settings["Cmdlet"] Set-Location -Path $Settings["Path"] $PassThru = $Settings["PassThru"] #endregion Converting parameters #region Utility Function function Read-V1Node { [CmdletBinding()] param ( $NodeData, [string] $Path, [Hashtable] $Result ) Write-PSFMessage -String 'Configuration.Schema.MetaJson.ProcessFile' -StringValues $Path -ModuleName PSFramework $basePath = Split-Path -Path $Path if ($NodeData.ModuleName) { $moduleName = "{0}." -f $NodeData.ModuleName } else { $moduleName = "" } #region Import Resources foreach ($property in $NodeData.Static.PSObject.Properties) { $Result["$($moduleName)$($property.Name)"] = $property.Value } foreach ($property in $NodeData.Object.PSObject.Properties) { $Result["$($moduleName)$($property.Name)"] = $property.Value | ConvertFrom-PSFClixml } foreach ($property in $NodeData.Dynamic.PSObject.Properties) { $Result["$($moduleName)$(Resolve-V1String -String $property.Name)"] = Resolve-V1String -String $property.Value } foreach ($property in $NodeData.Tree.PSObject.Properties) { Resolve-V1Tree -Property $property -Result $Result -BaseElement @() } foreach ($property in $NodeData.DynamicTree.PSObject.Properties) { Resolve-V1Tree -Property $property -Result $Result -BaseElement @() -Dynamic $true } #endregion Import Resources #region Import included / linked configuration files foreach ($include in $NodeData.Include) { $resolvedInclude = Resolve-V1String -String $include $uri = [uri]$resolvedInclude if ($uri.IsAbsoluteUri) { try { $newData = Get-Content $resolvedInclude -Raw -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop } catch { Stop-PSFFunction -String 'Configuration.Schema.MetaJson.InvalidJson' -StringValues $resolvedInclude -EnableException $script:EnableException -ModuleName PSFramework -ErrorRecord $_ -Continue -Cmdlet $script:cmdlet } try { $null = Read-V1Node -NodeData $newData -Result $Result -Path $resolvedInclude continue } catch { Stop-PSFFunction -String 'Configuration.Schema.MetaJson.NestedError' -StringValues $resolvedInclude -EnableException $script:EnableException -ModuleName PSFramework -ErrorRecord $_ -Continue -Cmdlet $script:cmdlet } } $joinedPath = Join-Path -Path $basePath -ChildPath ($resolvedInclude -replace '^\.\\', '\') try { $resolvedIncludeNew = Resolve-PSFPath -Path $joinedPath -Provider FileSystem -SingleItem } catch { Stop-PSFFunction -String 'Configuration.Schema.MetaJson.ResolveFile' -StringValues $joinedPath -EnableException $script:EnableException -ModuleName PSFramework -ErrorRecord $_ -Continue -Cmdlet $script:cmdlet } try { $newData = Get-Content $resolvedIncludeNew -Raw -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop } catch { Stop-PSFFunction -String 'Configuration.Schema.MetaJson.InvalidJson' -StringValues $resolvedIncludeNew -EnableException $script:EnableException -ModuleName PSFramework -ErrorRecord $_ -Continue -Cmdlet $script:cmdlet } try { $null = Read-V1Node -NodeData $newData -Result $Result -Path $resolvedIncludeNew continue } catch { Stop-PSFFunction -String 'Configuration.Schema.MetaJson.NestedError' -StringValues $resolvedIncludeNew -EnableException $script:EnableException -ModuleName PSFramework -ErrorRecord $_ -Continue -Cmdlet $script:cmdlet } } #endregion Import included / linked configuration files $Result } function Resolve-V1String { <# .SYNOPSIS Resolves a string by inserting placeholders for environment variables. .DESCRIPTION Resolves a string by inserting placeholders for environment variables. .PARAMETER String The string to resolve. .EXAMPLE PS C:\> Resolve-V1String -String '.\%COMPUTERNAME%\config.json' Resolves the specified string, inserting the local computername for %COMPUTERNAME%. #> [CmdletBinding()] param ( $String ) if ($String -isnot [string]) { return $String } $scriptblock = { param ( $Match ) $script:envData[$Match.Value] } [regex]::Replace($String, $script:envDataNamesRGX, $scriptblock) } function Resolve-V1Tree { [CmdletBinding()] param ( $Property, [Hashtable] $Result, [bool] $Dynamic, [AllowEmptyCollection()] [string[]] $BaseElement ) if ($Property.TypeNameOfValue -ne 'System.Management.Automation.PSCustomObject') { $name = (@($BaseElement) + @($Property.Name)) -join "." if ($Dynamic) { $Result[(Resolve-V1String -String $name)] = Resolve-V1String -String $Property.Value } else { $Result[$name] = $Property.Value } return } if ($Property.Value.'!Condition') { $conditionSet = $null if ($Property.Value.'!ConditionSet') { $module, $name = $Property.Value.'!ConditionSet' -split ' ', 2 $conditionSet = Get-PSFFilterConditionSet -Module $module -Name $name | Select-Object -First 1 } else { $conditionSet = Get-PSFFilterConditionSet -Module PSFramework -Name Environment } if (-not $conditionSet) { throw "Unable to resolve Condition Set: $($Property.Value.'!ConditionSet')" } $filter = New-PSFFilter -Expression $Property.Value.'!Condition' -ConditionSet $conditionSet if (-not $filter.Evaluate()) { return } } foreach ($propertyObject in $Property.Value.PSObject.Properties) { if ($propertyObject.Name -eq '!Condition') { continue } if ($propertyObject.Name -eq '!ConditionSet') { continue } if ($Property.Value.'!Condition') { Resolve-V1Tree -Property $propertyObject -Result $Result -Dynamic $Dynamic -BaseElement $BaseElement } else { Resolve-V1Tree -Property $propertyObject -Result $Result -Dynamic $Dynamic -BaseElement (@($BaseElement) + @($Property.Name)) } } } #endregion Utility Function #region Utility Computation $script:envData = @{ } foreach ($envItem in (Get-ChildItem env:\)) { $script:envData["%$($envItem.Name)%"] = $envItem.Value } $script:envDataNamesRGX = $script:envData.Keys -join '|' #endregion Utility Computation #region Accessing Content try { $resolvedPath = Resolve-PSFPath -Path $Resource -Provider FileSystem -SingleItem } catch { Stop-PSFFunction -String 'Configuration.Schema.MetaJson.ResolveFile' -StringValues $Resource -ModuleName PSFramework -FunctionName 'Schema: MetaJson' -EnableException $EnableException -ErrorRecord $_ -Cmdlet $script:cmdlet return } try { $importData = Get-Content -Path $resolvedPath -Raw -ErrorAction Stop | ConvertFrom-Json -ErrorAction Stop } catch { Stop-PSFFunction -String 'Configuration.Schema.MetaJson.InvalidJson' -StringValues $Resource -ModuleName PSFramework -FunctionName 'Schema: MetaJson' -EnableException $EnableException -ErrorRecord $_ -Cmdlet $script:cmdlet return } #endregion Accessing Content switch ($importData.Version) { 1 { $configurationHash = Read-V1Node -NodeData $importData -Path $resolvedPath -Result @{ } $configurationItems = $configurationHash.Keys | ForEach-Object { [pscustomobject]@{ FullName = $_ Value = $configurationHash[$_] } } foreach ($configItem in $configurationItems) { if ($ExcludeFilter | Where-Object { $configItem.FullName -like $_ }) { continue } if ($IncludeFilter -and -not ($IncludeFilter | Where-Object { $configItem.FullName -like $_ })) { continue } if ($Peek) { $configItem continue } Set-PSFConfig -FullName $configItem.FullName -Value $configItem.Value -AllowDelete:$AllowDelete -PassThru:$PassThru } } default { Stop-PSFFunction -String 'Configuration.Schema.MetaJson.UnknownVersion' -StringValues $Resource, $importData.Version -ModuleName PSFramework -FunctionName 'Schema: MetaJson' -EnableException $EnableException -Cmdlet $script:cmdlet return } } } |