Private/ConvertTo-NSPFortiGateRow.ps1
|
function ConvertTo-NSPFortiGateRow { <# .SYNOPSIS Flattens every instance of one config section into uniform CSV rows. .DESCRIPTION All rows share one property set (schema columns, then every other setting seen in any entry, then nested blocks), because Export-Csv takes its header from the first object only. -Include limits output to entries whose object key (see Get-NSPFortiGateObjectKey) is listed. #> [CmdletBinding()] param( [Parameter(Mandatory)][object[]]$Section, [string]$Delimiter = '; ', [switch]$IncludeSecrets, [switch]$NoDefaults, [System.Collections.Generic.HashSet[string]]$Include ) $path = $Section[0].Path $schemas = Get-NSPFortiGateSchema $schema = if ($schemas.Contains($path)) { $schemas[$path] } else { @{ IdColumn = 'Id'; Columns = [ordered]@{}; Defaults = @{} } } $childColumns = if ($schema.ChildColumns) { $schema.ChildColumns } else { [ordered]@{} } $records = New-Object System.Collections.Generic.List[object] foreach ($instance in $Section) { $sequence = 0 foreach ($entry in $instance.Entries) { $sequence++ if ($null -ne $Include -and -not $Include.Contains((Get-NSPFortiGateObjectKey -Vdom $entry.Vdom -Path $path -Name $entry.Name))) { continue } $records.Add(@{ Vdom = $entry.Vdom; Sequence = $sequence; Id = $entry.Name; Settings = $entry.Settings; Sections = $entry.Sections }) } # Sections such as 'system global' hold settings directly instead of edit entries. if ($instance.Entries.Count -eq 0 -and $instance.Settings.Count -and $null -eq $Include) { $records.Add(@{ Vdom = $instance.Vdom; Sequence = 1; Id = ''; Settings = $instance.Settings; Sections = $instance.Sections }) } } if ($records.Count -eq 0) { return } $knownKeys = @($schema.Columns.Values | Where-Object { $null -ne $_ }) $knownChildren = @($childColumns.Values | ForEach-Object { $_.Section }) $reserved = New-Object 'System.Collections.Generic.HashSet[string]' ([StringComparer]::OrdinalIgnoreCase) foreach ($name in @('Vdom', 'Sequence', $schema.IdColumn) + @($schema.Columns.Keys) + @($childColumns.Keys)) { [void]$reserved.Add($name) } $extraKeys = New-Object System.Collections.Generic.List[string] $seenKeys = New-Object 'System.Collections.Generic.HashSet[string]' ([StringComparer]::OrdinalIgnoreCase) $childPaths = New-Object System.Collections.Generic.List[string] $seenChildren = New-Object 'System.Collections.Generic.HashSet[string]' ([StringComparer]::OrdinalIgnoreCase) foreach ($record in $records) { foreach ($key in $record.Settings.Keys) { if ($knownKeys -notcontains $key -and $seenKeys.Add($key)) { $extraKeys.Add($key) } } foreach ($child in $record.Sections) { if ($knownChildren -notcontains $child.Path -and $seenChildren.Add($child.Path)) { $childPaths.Add($child.Path) } } } $showVdom = @($records | Where-Object { $_.Vdom }).Count -gt 0 foreach ($record in $records) { $row = [ordered]@{} if ($showVdom) { $row['Vdom'] = $record.Vdom } $row['Sequence'] = $record.Sequence $row[$schema.IdColumn] = $record.Id foreach ($column in $schema.Columns.Keys) { $key = $schema.Columns[$column] $row[$column] = if ($null -eq $key) { Get-NSPFortiGateObjectSummary -Path $path -Settings $record.Settings } elseif ($record.Settings.Contains($key)) { Format-NSPFortiGateValue -Key $key -Value $record.Settings[$key] -Delimiter $Delimiter -IncludeSecrets:$IncludeSecrets } elseif (-not $NoDefaults -and $schema.Defaults.Contains($key)) { $schema.Defaults[$key] } else { '' } } foreach ($column in $childColumns.Keys) { $spec = $childColumns[$column] $row[$column] = Format-NSPFortiGateChild -Section @($record.Sections | Where-Object Path -eq $spec.Section) -Keys $spec.Keys -Separator $spec.Separator -Delimiter $Delimiter -IncludeSecrets:$IncludeSecrets } foreach ($key in $extraKeys) { $column = if ($reserved.Contains($key)) { "$key (set)" } else { $key } $row[$column] = if ($record.Settings.Contains($key)) { Format-NSPFortiGateValue -Key $key -Value $record.Settings[$key] -Delimiter $Delimiter -IncludeSecrets:$IncludeSecrets } else { '' } } foreach ($childPath in $childPaths) { $row["config $childPath"] = Format-NSPFortiGateChild -Section @($record.Sections | Where-Object Path -eq $childPath) -Delimiter $Delimiter -IncludeSecrets:$IncludeSecrets } [pscustomobject]$row } } |