PSWriteHTML.psm1

function Add-TableFiltering {
    [CmdletBinding()]
    param([bool] $Filtering,
        [ValidateSet('Top', 'Bottom', 'Both')][string]$FilteringLocation = 'Bottom')
    $Output = @{}
    if ($Filtering) {
        if ($FilteringLocation -eq 'Bottom') {
            $Output.FilteringTopCode = @"
                // Setup - add a text input to each footer cell
                `$('#$DataTableName tfoot th').each(function () {
                    var title = `$(this).text();
                    `$(this).html('<input type="text" placeholder="' + title + '" />');
                });
"@

            $Output.FilteringBottomCode = @"
                // Apply the search for footer cells
                table.columns().every(function () {
                    var that = this;
 
                    `$('input', this.footer()).on('keyup change', function () {
                        if (that.search() !== this.value) {
                            that.search(this.value).draw();
                        }
                    });
                });
"@

        } elseif ($FilteringLocation -eq 'Both') {
            $Output.FilteringTopCode = @"
                // Setup - add a text input to each header cell
                `$('#$DataTableName thead th').each(function () {
                    var title = `$(this).text();
                    `$(this).html('<input type="text" placeholder="' + title + '" />');
                });
                // Setup - add a text input to each footer cell
                `$('#$DataTableName tfoot th').each(function () {
                    var title = `$(this).text();
                    `$(this).html('<input type="text" placeholder="' + title + '" />');
                });
"@

            $Output.FilteringBottomCode = @"
                // Apply the search for header cells
                table.columns().eq(0).each(function (colIdx) {
                    `$('input', table.column(colIdx).header()).on('keyup change', function () {
                        table
                            .column(colIdx)
                            .search(this.value)
                            .draw();
                    });
 
                    `$('input', table.column(colIdx).header()).on('click', function (e) {
                        e.stopPropagation();
                    });
                });
                // Apply the search for footer cells
                table.columns().every(function () {
                    var that = this;
 
                    `$('input', this.footer()).on('keyup change', function () {
                        if (that.search() !== this.value) {
                            that.search(this.value).draw();
                        }
                    });
                });
"@

        } else {
            $Output.FilteringTopCode = @"
                // Setup - add a text input to each header cell
                `$('#$DataTableName thead th').each(function () {
                    var title = `$(this).text();
                    `$(this).html('<input type="text" placeholder="' + title + '" />');
                });
"@

            $Output.FilteringBottomCode = @"
                // Apply the search for header cells
                table.columns().eq(0).each(function (colIdx) {
                    `$('input', table.column(colIdx).header()).on('keyup change', function () {
                        table
                            .column(colIdx)
                            .search(this.value)
                            .draw();
                    });
 
                    `$('input', table.column(colIdx).header()).on('click', function (e) {
                        e.stopPropagation();
                    });
                });
"@

        }
    } else {$Output.FilteringTopCode = $Output.FilteringBottomCode = ''}
    return $Output
}
function Convert-ImagesToBinary {
    [CmdLetBinding()]
    param([string[]] $Content,
        [string] $Search,
        [string] $ReplacePath)
    if ($Content -like "*$Search*") {
        $Replace = "data:image/$FileType;base64," + [Convert]::ToBase64String((Get-Content -LiteralPath $ReplacePath -Encoding Byte))
        $Content = $Content.Replace($Search, $Replace)
    }
    $Content
}
function Convert-StyleContent {
    [CmdLetBinding()]
    param([string[]] $CSS,
        [string] $ImagesPath,
        [string] $SearchPath)
    $ImageFiles = Get-ChildItem -Path (Join-Path $ImagesPath '\*') -Include *.jpg, *.png, *.bmp
    foreach ($Image in $ImageFiles) {$CSS = Convert-ImagesToBinary -Content $CSS -Search "$SearchPath$($Image.Name)" -ReplacePath $Image.FullName}
    return $CSS
}
function Convert-StyleContent1 {
    param([PSCustomObject] $Options)
    if ($null -ne $Options.StyleContent) {
        Write-Verbose "Logos: $($Options.Logos.Keys -join ',')"
        foreach ($Logo in $Options.Logos.Keys) {
            $Search = "../images/$Logo.png", "DataTables-1.10.18/images/$Logo.png"
            $Replace = $Options.Logos[$Logo]
            foreach ($S in $Search) {
                Write-Verbose "Logos - replacing $S with binary representation"
                $Options.StyleContent = ($Options.StyleContent).Replace($S, $Replace)
            }
        }
    }
}
function Get-FeaturesInUse {
    [CmdletBinding()]
    param()
    foreach ($Key in $Script:HTMLSchema.Features.Keys) {if ($Script:HTMLSchema.Features[$Key]) {$Key}}
}
Function Get-HTMLColorSchemes {
    [CmdletBinding()]
    param
    ([Parameter(Mandatory = $false)][String]$SchemePath)
    if ([String]::IsNullOrEmpty($SchemePath)) {$SchemePath = "$PSScriptRoot\Resources\ColorSchemas"}
    $Schemes = @{}
    Write-Verbose "Retrieving *.rcs from $SchemePath"
    $SchemeFiles = @(Get-ChildItem $SchemePath -Filter '*.rcs' -Recurse)
    foreach ($SchemeFile in $SchemeFiles) {
        $SchemeContent = Import-Csv -Delimiter ';' -Path $SchemeFile.FullName
        $Schemes.Add($SchemeFile.BaseName, $SchemeContent)
    }
    $Schemes.add('Generated1', (Get-RandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated2', (Get-RandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated3', (Get-RandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated4', (Get-RandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated5', (Get-RandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated6', (Get-RandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated7', (Get-RandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated8', (Get-RandomColorScheme -NumberOfSchemes 80))
    Write-Output $Schemes
}
Function Get-HTMLLogos {
    <#
         .SYNOPSIS
            Get Base64 HTML
 
    #>

    [CmdletBinding()]
    param
    ([Parameter(Mandatory = $false)]
        [string]$LeftLogoName = "Sample",
        [string]$RightLogoName = "Alternate",
        [string]$LeftLogoString,
        [string]$RightLogoString)
    $LogoSources = @{}
    $LogoPath = @()
    if ([String]::IsNullOrEmpty($RightLogoString) -eq $false -or [String]::IsNullOrEmpty($LeftLogoString) -eq $false) {
        if ([String]::IsNullOrEmpty($RightLogoString) -eq $false) {$LogoSources.Add($RightLogoName, $RightLogoString)}
        if ([String]::IsNullOrEmpty($LeftLogoString) -eq $false) {$LogoSources.Add($LeftLogoName, $LeftLogoString)}
    } else {$LogoPath += "$PSScriptRoot\Resources\Images\Other"}
    $LogoPath += "$PSScriptRoot\Resources\Images\DataTables"
    $ImageFiles = Get-ChildItem -Path (join-path $LogoPath '\*') -Include *.jpg, *.png, *.bmp -Recurse
    foreach ($ImageFile in $ImageFiles) {
        if ($ImageFile.Extension -eq '.jpg') {$FileType = 'jpeg'} else {$FileType = $ImageFile.Extension.Replace('.', '')}
        Write-Verbose "Converting $($ImageFile.FullName) to base64 ($FileType)"
        $LogoSources.Add($ImageFile.BaseName, "data:image/$FileType;base64," + [Convert]::ToBase64String((Get-Content $ImageFile.FullName -Encoding Byte)))
    }
    Write-Output $LogoSources
}
function Get-HTMLPartContent {
    param([Array] $Content,
        [string] $Start,
        [string] $End,
        [ValidateSet('Before', 'Between', 'After')] $Type = 'Between')
    $NrStart = $Content.IndexOf($Start)
    $NrEnd = $Content.IndexOf($End)
    if ($Type -eq 'Between') {
        if ($NrStart -eq -1) {return}
        $Content[$NrStart..$NrEnd]
    }
    if ($Type -eq 'After') {
        if ($NrStart -eq -1) {return $Content}
        $Content[($NrEnd + 1)..($Content.Count - 1)]
    }
    if ($Type -eq 'Before') {
        if ($NrStart -eq -1) {return}
        $Content[0..$NrStart]
    }
}
Function Get-RandomColor {
    <#
    .SYNOPSIS
        Random colour Function
    #>

    param([int]$RMin = 0,
        [int]$RMax = 255,
        [int]$GMin = 0,
        [int]$GMax = 255,
        [int]$BMin = 0,
        [int]$BMax = 255)
    $R = (Get-Random -Maximum $RMax -Minimum $RMin)
    $G = (Get-Random -Maximum $GMax -Minimum $GMin)
    $B = (Get-Random -Maximum $BMax -Minimum $BMin)
    @($R, $G, $B)
}
Function Get-RandomColorScheme {
    <#
    .SYNOPSIS
    Generate a colour scheme
 
     
    .DESCRIPTION
    Generate a colour scheme
     
    .PARAMETER NumberOfSchemes
    Parameter description
     
    .EXAMPLE
    An example
     
    .NOTES
    General notes
    #>

    param
    ([Parameter(Mandatory = $false)][int]$NumberOfSchemes = 1,
        [int] $ColorSwing = 8,
        [string] $Hover = 0.3,
        [string] $color = 0.6,
        [string] $border = 1,
        [string] $background = 0.7)
    $ColorReference = Get-Random -Minimum 1 -Maximum 3
    $BaseColor = (Get-Random -Maximum (200 - $ColorSwing) -Minimum (50 + $ColorSwing))
    $BCMax = $BaseColor + $ColorSwing
    $BCMin = $BaseColor - $ColorSwing
    $i = 0
    while ($i -ne $NumberOfSchemes) {
        switch ($ColorReference) {
            1 {[int[]] $base = Get-RandomColor -rmin $BCMin -rmax $BCMax}
            2 {[int[]] $base = Get-RandomColor -gmin $BCMin -gmax $BCMax}
            3 {[int[]] $base = Get-RandomColor -bmin $BCMin -bcmax $BCMax}
        }
        [PSCustomObject] @{Background = "rgba($($base + $background -join ','))"
            Border = "rgba($($base + $border -join ','))"
            Colour = "rgba($($base + $color -join ','))"
            Hover = "rgba($($base + $Hover -join ','))"
        }
        $i++
    }
}
function Get-Resources {
    [CmdLetBinding()]
    param([switch] $UseCssLinks,
        [switch] $UseJavaScriptLinks,
        [switch] $NoScript,
        [ValidateSet('Header', 'Footer', 'HeaderAlways', 'FooterAlways')][string] $Location)
    DynamicParam {
        $Names = $Script:Configuration.Features.Keys
        $ParamAttrib = New-Object System.Management.Automation.ParameterAttribute
        $ParamAttrib.Mandatory = $true
        $ParamAttrib.ParameterSetName = '__AllParameterSets'
        $ReportAttrib = New-Object System.Collections.ObjectModel.Collection[System.Attribute]
        $ReportAttrib.Add($ParamAttrib)
        $ReportAttrib.Add((New-Object System.Management.Automation.ValidateSetAttribute($Names)))
        $ReportRuntimeParam = New-Object System.Management.Automation.RuntimeDefinedParameter('Features', [string[]], $ReportAttrib)
        $RuntimeParamDic = New-Object System.Management.Automation.RuntimeDefinedParameterDictionary
        $RuntimeParamDic.Add('Features', $ReportRuntimeParam)
        return $RuntimeParamDic
    }
    Process {
        [string[]] $Features = $PSBoundParameters.Features
        foreach ($Feature in $Features) {
            Write-Verbose "Get-Resources - Location: $Location - Feature: $Feature UseCssLinks: $UseCssLinks UseJavaScriptLinks: $UseJavaScriptLinks"
            if ($UseCssLinks) {New-HTMLResourceCSS -Link $Script:Configuration.Features.$Feature.$Location.'CssLink' -ResourceComment $Script:Configuration.Features.$Feature.Comment} else {
                $CSSOutput = New-HTMLResourceCSS -FilePath $Script:Configuration.Features.$Feature.$Location.'Css' -ResourceComment $Script:Configuration.Features.$Feature.Comment
                Convert-StyleContent -CSS $CSSOutput -ImagesPath "$PSScriptRoot\Resources\Images\DataTables" -SearchPath "DataTables-1.10.18/images/"
            }
            if ($UseJavaScriptLinks) {New-HTMLResourceJS -Link $Script:Configuration.Features.$Feature.$Location.'JsLink' -ResourceComment $Script:Configuration.Features.$Feature.Comment} else {New-HTMLResourceJS -FilePath $Script:Configuration.Features.$Feature.$Location.'Js' -ResourceComment $Script:Configuration.Features.$Feature.Comment}
            if ($NoScript) {
                [Array] $Output = @(if ($UseCssLinks) {New-HTMLResourceCSS -Link $Script:Configuration.Features.$Feature.$Location.'CssLinkNoScript' -ResourceComment $Script:Configuration.Features.$Feature.Comment} else {
                        $CSSOutput = New-HTMLResourceCSS -FilePath $Script:Configuration.Features.$Feature.$Location.'CssNoScript' -ResourceComment $Script:Configuration.Features.$Feature.Comment
                        Convert-StyleContent -CSS $CSSOutput -ImagesPath "$PSScriptRoot\Resources\Images\DataTables" -SearchPath "DataTables-1.10.18/images/"
                    })
                if (($Output.Count -gt 0) -and ($null -ne $Output[0])) {New-HTMLTag -Tag 'noscript' {$Output}}
            }
        }
    }
}
function New-ApexChart {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [ValidateSet('', 'central')][string] $Positioning)
    $Script:HTMLSchema.Features.ChartsApex = $true
    [string] $ID = "ChartID-" + (Get-RandomStringName -Size 8)
    $Div = New-HTMLTag -Tag 'div' -Attributes @{id = $ID; class = $Positioning}
    $Script = New-HTMLTag -Tag 'script' -Value {$JSON = $Options | ConvertTo-Json -Depth 5 | ForEach-Object {[System.Text.RegularExpressions.Regex]::Unescape($_)}
        "var options = $JSON"
        ""
        "var chart = new ApexCharts(document.querySelector('#$ID'),
            options
        );"

        "chart.render();"}
    $Div
    $Script:HTMLSchema.Charts.Add($Script)
}
function New-ChartArea {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend,
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category')
    $Options.chart = @{type = 'area'}
    $Options.series = @(New-HTMLChartDataSet -Data $Data -DataNames $DataNames)
    $Options.xaxis = [ordered] @{}
    if ($DataCategoriesType -ne '') {$Options.xaxis.type = $DataCategoriesType}
    if ($DataCategories.Count -gt 0) {$Options.xaxis.categories = $DataCategories}
}
function New-ChartAxisX {
    param([System.Collections.IDictionary] $Options,
        [string] $Title,
        [int] $MinValue,
        [int] $MaxValue,
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category',
        $DataCategories)
    if (-not $Options.Contains('xaxis')) {$Options.xaxis = @{}
    }
    if ($Title -ne '') {$Options.xaxis.title = @{}
        $Options.xaxis.title.text = $Title
    }
    if ($MinValue -gt 0) {$Options.xaxis.min = $MinValue}
    if ($MinValue -gt 0) {$Options.xaxis.max = $MaxValue}
    if ($DataCategoriesType -ne '') {$Options.xaxis.type = $DataCategoriesType}
    if ($DataCategories.Count -gt 0) {$Options.xaxis.categories = $DataCategories}
}
function New-ChartAxisY {
    param([System.Collections.IDictionary] $Options,
        [string] $Title,
        [int] $MinValue,
        [int] $MaxValue)
    if (-not $Options.Contains('yaxis')) {$Options.yaxis = @{}
    }
    if ($Title -ne '') {$Options.yaxis.title = @{}
        $Options.yaxis.title.text = $Title
    }
    if ($MinValue -gt 0) {$Options.yaxis.min = $MinValue}
    if ($MinValue -gt 0) {$Options.yaxis.max = $MaxValue}
}
Function New-ChartBar {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [bool] $Horizontal = $true,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors[]] $DataLabelsColor,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', '')][string] $TitleAlignment = '',
        [string] $Formatter,
        [ValidateSet('bar', 'barStacked', 'barStacked100Percent')] $Type = 'bar',
        [RGBColors[]] $Colors,
        [switch] $PatternedColors,
        [switch] $Distributed,
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend)
    if ($Type -eq 'bar') {$Options.chart = [ordered] @{type = 'bar'}
    } elseif ($Type -eq 'barStacked') {
        $Options.chart = [ordered] @{type = 'bar'
            stacked = $true
        }
    } else {
        $Options.chart = [ordered] @{type = 'bar'
            stacked = $true
            stackType = '100%'
        }
    }
    if ($Colors.Count -gt 0) {
        $RGBColor = ConvertFrom-Color -Color $Colors
        $Options.colors = @($RGBColor)
    }
    $Options.plotOptions = @{bar = @{horizontal = $Horizontal}}
    if ($Distributed) {$Options.plotOptions.bar.distributed = $Distributed.IsPresent}
    $Options.dataLabels = [ordered] @{enabled = $DataLabelsEnabled
        offsetX = $DataLabelsOffsetX
        style = @{fontSize = $DataLabelsFontSize}
    }
    if ($null -ne $DataLabelsColor) {
        $RGBColorLabel = ConvertFrom-Color -Color $DataLabelsColor
        $Options.dataLabels.style.colors = @($RGBColorLabel)
    }
    $Options.series = @(New-HTMLChartDataSet -Data $Data -DataNames $DataLegend)
    $Options.xaxis = [ordered] @{}
    if ($DataNames.Count -gt 0) {$Options.xaxis.categories = $DataNames}
    New-ChartTitle -Options $Options -Title $Title -TitleAlignment $TitleAlignment
    if ($PatternedColors) {
        $Options.fill = @{type = 'pattern'
            opacity = 1
            pattern = @{style = @('circles', 'slantedLines', 'verticalLines', 'horizontalLines')}
        }
    }
}
function New-ChartDataLabels {
    param([System.Collections.IDictionary] $Options,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors[]] $DataLabelsColor)
    $Options.dataLabels = [ordered] @{enabled = $DataLabelsEnabled
        offsetX = $DataLabelsOffsetX
        style = @{fontSize = $DataLabelsFontSize}
    }
    if ($DataLabelsColor.Count -gt 0) {$Options.dataLabels.style.colors = @(ConvertFrom-Color -Color $DataLabelsColor)}
}
function New-ChartGridColors {
    param([System.Collections.IDictionary] $Options,
        [RGBColors[]] $GridColors,
        [double] $GridOpacity)
    $Options.grid = @{}
    $Options.grid.row = @{}
    if ($GridColors.Count -gt 0) {$Options.grid.row.colors = @(ConvertFrom-Color -Color $GridColors)}
    if ($GridOpacity -ne 0) {$Options.grid.row.opacity = $GridOpacity}
}
function New-ChartLegend {
    param([System.Collections.IDictionary] $Options,
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', '')][string] $LegendPosition = '')
    if ($LegendPosition -eq '' -or $LegendPosition -eq 'bottom') {} elseif ($LegendPosition -eq 'right') {
        $Options.legend = [ordered]@{position = 'right'
            offsetY = 100
            height = 230
        }
    } elseif ($LegendPosition -eq 'top') {
        $Options.legend = [ordered]@{position = 'top'
            horizontalAlign = 'left'
            offsetX = 40
        }
    } elseif ($LegendPosition -eq 'topRight') {
        $Options.legend = [ordered]@{position = 'top'
            horizontalAlign = 'right'
            floating = true
            offsetY = -25
            offsetX = -5
        }
    }
}
function New-ChartLine {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Data,
        [Array] $DataNames,
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category')
    $Options.chart = @{type = 'line'}
    $Options.series = @(New-HTMLChartDataSet -Data $Data -DataNames $DataNames)
    $Options.xaxis = [ordered] @{}
    if ($DataCategoriesType -ne '') {$Options.xaxis.type = $DataCategoriesType}
    if ($DataCategories.Count -gt 0) {$Options.xaxis.categories = $DataCategories}
}
function New-ChartMarker {
    param([System.Collections.IDictionary] $Options,
        [int] $MarkerSize)
    if ($MarkerSize -gt 0) {$Options.markers = @{size = $MarkerSize}
    }
}
function New-ChartRadial {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Values,
        [Array] $Names,
        $Type)
    $Options.chart = @{type = 'radialBar'}
    if ($Type -eq '1') {New-ChartRadialType1 -Options $Options} elseif ($Type -eq '2') {New-ChartRadialType2 -Options $Options}
    $Options.series = @($Values)
    $Options.labels = @($Names)
}
function New-ChartRadialCircleType {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [ValidateSet('FullCircleTop', 'FullCircleBottom', 'FullCircleBottomLeft', 'FullCircleLeft', 'Speedometer', 'SemiCircleGauge')] $CircleType)
    if ($CircleType -eq 'SemiCircleGauge') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -90
            endAngle = 90
        }
    } elseif ($CircleType -eq 'FullCircleBottom') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -180
            endAngle = 180
        }
    } elseif ($CircleType -eq 'FullCircleLeft') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -90
            endAngle = 270
        }
    } elseif ($CircleType -eq 'FullCircleBottomLeft') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -135
            endAngle = 225
        }
    } elseif ($CircleType -eq 'Speedometer') {
        $Options.plotOptions.radialBar = [ordered] @{startAngle = -135
            endAngle = 135
        }
    } else {}
}
function New-ChartRadialDataLabels {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [string] $LabelAverage = 'Average')
    if ($LabelAverage -ne '') {
        $Options.plotOptions.radialBar.dataLabels = @{showOn = 'always'
            name = @{}
            value = @{}
            total = @{show = $true
                label = $LabelAverage
            }
        }
    }
}
function New-ChartRadialType1 {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Values,
        [Array] $Names)
    $Options.plotOptions = @{radialBar = [ordered] @{hollow = [ordered] @{margin = 0
                size = '70%'
                background = '#fff'
                image = 'undefined'
                imageOffsetX = 0
                imageOffsetY = 0
                position = 'front'
                dropShadow = @{enabled = $true
                    top = 3
                    left = 0
                    blur = 4
                    opacity = 0.24
                }
            }
            track = [ordered] @{background = '#fff'
                strokeWidth = '70%'
                margin = 0
                dropShadow = [ordered] @{enabled = $true
                    top = -3
                    left = 0
                    blur = 4
                    opacity = 0.35
                }
            }
        }
    }
    $Options.fill = [ordered] @{type = 'gradient'
        gradient = [ordered] @{shade = 'dark'
            type = 'horizontal'
            shadeIntensity = 0.5
            gradientToColors = @('#ABE5A1')
            inverseColors = true
            opacityFrom = 1
            opacityTo = 1
            stops = @(0, 100)
        }
    }
    $Options.stroke = [ordered] @{dashArray = 4}
}
function New-ChartRadialType2 {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [Array] $Values,
        [Array] $Names)
    $Options.plotOptions = @{radialBar = [ordered] @{hollow = [ordered] @{margin = 0
                size = '70%'
                background = '#fff'
                image = 'undefined'
                imageOffsetX = 0
                imageOffsetY = 0
                position = 'front'
                dropShadow = @{enabled = $true
                    top = 3
                    left = 0
                    blur = 4
                    opacity = 0.24
                }
            }
        }
    }
}
function New-ChartSize {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [nullable[int]] $Height = 350,
        [nullable[int]] $Width)
    if ($null -ne $Height) {$Options.chart.height = $Height}
    if ($null -ne $Width) {$Options.chart.width = $Width}
}
function New-ChartSpark {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [nullable[RGBColors]] $Color,
        [string] $Title,
        [string] $SubTitle,
        [int] $FontSizeTitle = 24,
        [int] $FontSizeSubtitle = 14,
        [Array] $Values)
    if ($Values.Count -eq 0) {Write-Warning 'Get-ChartSpark - Values Empty'}
    if ($null -ne $Color) {
        $ColorRGB = ConvertFrom-Color -Color $Color
        $Options.colors = @($ColorRGB)
    }
    $Options.chart = [ordered] @{type = 'area'
        sparkline = @{enabled = $true}
    }
    $Options.stroke = @{curve = 'straight'}
    $Options.title = [ordered] @{text = $Title
        offsetX = 0
        style = @{fontSize = "$($FontSizeTitle)px"
            cssClass = 'apexcharts-yaxis-title'
        }
    }
    $Options.subtitle = [ordered] @{text = $SubTitle
        offsetX = 0
        style = @{fontSize = "$($FontSizeSubtitle)px"
            cssClass = 'apexcharts-yaxis-title'
        }
    }
    $Options.yaxis = @{min = 0}
    $Options.fill = @{opacity = 0.3}
    $Options.series = @(if ($Values[0] -is [Array]) {foreach ($Value in $Values) {@{data = @($Value)}}
        } else {@{data = @($Values)}
        })
}
function New-ChartStrokeDefinition {
    param([System.Collections.IDictionary] $Options,
        [bool] $LineShow = $true,
        [ValidateSet('straight', 'smooth', 'stepline')] $LineCurve = 'straight',
        [int] $LineWidth,
        [RGBColors[]] $LineColor)
    $Options.stroke = [ordered] @{show = $LineShow
        curve = $LineCurve
    }
    if ($LineWidth -ne 0) {$Options.stroke.width = $LineWidth}
    if ($LineColor.Count -gt 0) {$Options.stroke.colors = @(ConvertFrom-Color -Color $LineColor)}
}
function New-ChartTitle {
    param([System.Collections.IDictionary] $Options,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', '')][string] $TitleAlignment = '')
    $Options.title = [ordered] @{}
    if ($TitleText -ne '') {$Options.title.text = $Title}
    if ($TitleAlignment -ne '') {$Options.title.align = $TitleAlignment}
}
function New-ChartToolbar {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [bool] $Show = $true,
        [bool] $Download = $true,
        [bool] $Selection = $true,
        [bool] $Zoom = $true,
        [bool] $ZoomIn = $true,
        [bool] $ZoomOut = $true,
        [bool] $Pan = $true,
        [bool] $Reset = $true)
    $Options.chart.toolbar = [ordered] @{show = $show
        tools = [ordered] @{download = $Download
            selection = $Selection
            zoom = $Zoom
            zoomin = $ZoomIn
            zoomout = $ZoomOut
            pan = $Pan
            reset = $Reset
        }
        autoSelected = 'zoom'
    }
}
function New-ChartZoom {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $Options,
        [switch] $Enabled)
    if ($Enabled) {
        $Options.chart.zoom = @{type = 'x'
            enabled = $Enabled.IsPresent
        }
    }
}
Function New-HTML {
    [CmdletBinding()]
    param([Parameter(Position = 0)][ValidateNotNull()][ScriptBlock] $HtmlData = $(Throw "Have you put the open curly brace on the next line?"),
        [switch] $UseCssLinks,
        [switch] $UseJavaScriptLinks,
        [String] $TitleText,
        [string] $Author,
        [string] $DateFormat = 'yyyy-MM-dd HH:mm:ss',
        [int] $AutoRefresh,
        [Parameter(Mandatory = $false)][string]$FilePath,
        [Parameter(Mandatory = $false)][switch]$ShowHTML,
        [ValidateSet('Unknown', 'String', 'Unicode', 'Byte', 'BigEndianUnicode', 'UTF8', 'UTF7', 'UTF32', 'Ascii', 'Default', 'Oem', 'BigEndianUTF32')] $Encoding = 'UTF8')
    [string] $CurrentDate = (Get-Date).ToString($DateFormat)
    $Script:HTMLSchema = @{TabsHeaders = [System.Collections.Generic.List[HashTable]]::new()
        Features = @{}
        Charts = [System.Collections.Generic.List[string]]::new()
    }
    $OutputHTML = Invoke-Command -ScriptBlock $HtmlData
    if ($null -ne $OutputHTML -and $OutputHTML.Count -gt 0) {
        $Logo = Get-HTMLPartContent -Content $OutputHTML -Start '<!-- START LOGO -->' -End '<!-- END LOGO -->' -Type Between
        $OutputHTML = Get-HTMLPartContent -Content $OutputHTML -Start '<!-- START LOGO -->' -End '<!-- END LOGO -->' -Type After
    }
    $Features = Get-FeaturesInUse
    $HTML = @('<!DOCTYPE html>'
        New-HTMLTag -Tag 'html' {'<!-- HEADER -->'
            New-HTMLTag -Tag 'head' {New-HTMLTag -Tag 'meta' -Attributes @{charset = "utf-8"} -SelfClosing
                New-HTMLTag -Tag 'meta' -Attributes @{name = 'viewport'; content = 'width=device-width, initial-scale=1'} -SelfClosing
                New-HTMLTag -Tag 'meta' -Attributes @{name = 'author'; content = $Author} -SelfClosing
                New-HTMLTag -Tag 'meta' -Attributes @{name = 'revised'; content = $CurrentDate} -SelfClosing
                New-HTMLTag -Tag 'title' {$TitleText}
                if ($Autorefresh -gt 0) {New-HTMLTag -Tag 'meta' -Attributes @{'http-equiv' = 'refresh'; content = $Autorefresh} -SelfClosing
                }
                Get-Resources -UseCssLinks:$true -UseJavaScriptLinks:$true -Location 'HeaderAlways' -Features Default, DefaultHeadings, Fonts, FontsAwesome
                Get-Resources -UseCssLinks:$false -UseJavaScriptLinks:$false -Location 'HeaderAlways' -Features Default, DefaultHeadings
                if ($null -ne $Features) {
                    Get-Resources -UseCssLinks:$true -UseJavaScriptLinks:$true -Location 'HeaderAlways' -Features $Features
                    Get-Resources -UseCssLinks:$false -UseJavaScriptLinks:$false -Location 'HeaderAlways' -Features $Features
                    Get-Resources -UseCssLinks:$true -UseJavaScriptLinks:$true -Location 'HeaderAlways' -Features $Features -NoScript
                    Get-Resources -UseCssLinks:$false -UseJavaScriptLinks:$false -Location 'HeaderAlways' -Features $Features -NoScript
                    Get-Resources -UseCssLinks:$UseCssLinks -UseJavaScriptLinks:$UseJavaScriptLinks -Location 'Header' -Features $Features
                }}
            '<!-- END HEADER -->'
            '<!-- BODY -->'
            New-HTMLTag -Tag 'body' {$Logo
                if ($Script:HTMLSchema.TabsHeaders) {New-HTMLTabHead}
                $OutputHTML
                foreach ($Chart in $Script:HTMLSchema.Charts) {$Chart}}
            '<!-- END BODY -->'
            '<!-- FOOTER -->'
            New-HTMLTag -Tag 'footer' {if ($null -ne $Features) {
                    Get-Resources -UseCssLinks:$true -UseJavaScriptLinks:$true -Location 'FooterAlways' -Features $Features
                    Get-Resources -UseCssLinks:$false -UseJavaScriptLinks:$false -Location 'FooterAlways' -Features $Features
                    Get-Resources -UseCssLinks:$UseCssLinks -UseJavaScriptLinks:$UseJavaScriptLinks -Location 'Footer' -Features $Features
                }}
            '<!-- END FOOTER -->'})
    if ($FilePath -ne '') {Save-HTML -HTML $HTML -FilePath $FilePath -ShowHTML:$ShowHTML -Encoding $Encoding} else {$HTML}
}
function New-HTMLAnchor {
    <#
    .SYNOPSIS
    Short description
     
    .DESCRIPTION
    Long description
     
    .PARAMETER Name
    Parameter description
     
    .PARAMETER Id
    Parameter description
     
    .PARAMETER Target
    Parameter description
     
    .PARAMETER Class
    Parameter description
     
    .PARAMETER HrefLink
    Parameter description
     
    .PARAMETER OnClick
    Parameter description
     
    .PARAMETER Style
    Parameter description
     
    .PARAMETER Text
    Parameter description
     
    .EXAMPLE
    New-HTMLAnchor -Target _parent
 
    New-HTMLAnchor -Id "show_$RandomNumber" -Href '#' -OnClick "show('$RandomNumber');" -Style "color: #ffffff; display:none;" -Text 'Show'
 
    Output:
    <a target = "_parent" />
     
    .NOTES
    General notes
    #>

    param([alias('AnchorName')][string] $Name,
        [string] $Id,
        [string] $Target,
        [string] $Class,
        [alias('Url', 'Link', 'UrlLink', 'Href')][string] $HrefLink,
        [string] $OnClick,
        [string] $Style,
        [alias('AnchorText', 'Value')][string] $Text)
    $Attributes = [ordered]@{'id' = $Id
        'name' = $Name
        'class' = $Class
        'target' = $Target
        'href' = $HrefLink
        'onclick' = $OnClick
        'style' = $Style
    }
    New-HTMLTag -Tag 'a' -Attributes $Attributes {$Text}
}
Function New-HTMLAnchorLink {
    <#
    .SYNOPSIS
    Creates Hyperlink for an Anchor
 
    .DESCRIPTION
    Long description
 
    .PARAMETER AnchorName
    The Actual name of the Anchor (Hidden)
 
    .PARAMETER AnchorText
    The HyperLink text. Will default to $AnchorNname if not specified
 
    .EXAMPLE
    Get-HTMLAnchorLink -AnchorName 'test'
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    Param
    ([Parameter(Mandatory = $true)][String] $AnchorName,
        [Parameter(Mandatory = $false)][String] $AnchorText)
    if ($AnchorText -eq $null -or $AnchorText -eq '') {$AnchorText = $AnchorName}
    New-HTMLAnchor -Name $AnchorName -HrefLink '#' -Class 'alink' -Text $AnchorText
}
Function New-HTMLAnchorName {
    <#
    .SYNOPSIS
    Creates an anchor
 
    .DESCRIPTION
    Long description
 
    .PARAMETER AnchorName
    Parameter description
 
    .EXAMPLE
    An example
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    Param ([Parameter(Mandatory = $true)][String] $AnchorName)
    New-HTMLAnchor -Name $AnchorName
}
function New-HTMLCanvas {
    [CmdletBinding()]
    param([alias('Value')][Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content = $(Throw "Open curly brace with Content"),
        [string] $ID,
        [string] $Width,
        [string] $Height,
        [string] $Style)
    $Canvas = [Ordered] @{Tag = 'canvas'
        Attributes = [ordered]@{'id' = $Id
            'width' = $Width
            'height' = $Height
            'style' = $Style
        }
        SelfClosing = $false
        Value = Invoke-Command -ScriptBlock $Content
    }
    $HTML = Set-Tag -HtmlObject $Canvas
    return $HTML
}
function New-HTMLChart {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [string] $Type = 'bar',
        [bool] $Horizontal = $true,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors] $DataLabelsColor,
        [Array] $Data = @(),
        [Array] $DataNames = @(),
        [Array] $DataCategories = @(),
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category',
        [string] $TitleText,
        [ValidateSet('center', 'left', 'right', '')][string] $TitleAlignment = '',
        [bool] $LineShow = $true,
        [ValidateSet('straight', 'smooth')] $LineCurve = 'straight',
        $LineWidth = 2,
        [RGBColors[]] $LineColor,
        [ValidateSet('', 'central')][string] $Positioning)
    $Options = [ordered] @{}
    $Options.chart = @{type = $Type}
    New-ChartSize -Options $Options -Height $Height -Width $Width
    New-ChartToolbar -Options $Options
    $Options.plotOptions = @{bar = @{horizontal = $Horizontal}}
    $Options.dataLabels = [ordered] @{enabled = $DataLabelsEnabled
        offsetX = $DataLabelsOffsetX
        style = @{fontSize = $DataLabelsFontSize
            colors = @($DataLabelsColor)
        }
    }
    if ('bar', 'line' -contains $Type) {$Options.series = @(New-HTMLChartDataSet -Data $Data -DataNames $DataNames)} else {
        $Options.series = $Data
        if ($null -ne $DataCategories) {$Options.labels = $DataCategories} else {$Options.labels = $DataNames}
    }
    $Options.xaxis = [ordered] @{}
    if ($DataCategoriesType -ne '') {$Options.xaxis.type = $DataCategoriesType}
    if ($DataCategories.Count -gt 0) {$Options.xaxis.categories = $DataCategories}
    $Options.stroke = [ordered] @{show = $LineShow
        curve = $LineCurve
        width = $LineWidth
        colors = @(ConvertFrom-Color -Color $LineColor)
    }
    $Options.legend = @{position = 'right'
        offsetY = 100
        height = 230
    }
    $Options.title = [ordered] @{}
    if ($TitleText -ne '') {$Options.title.text = $TitleText}
    if ($TitleAlignment -ne '') {$Options.title.align = $TitleAlignment}
    New-ChartSize -Options $Options -Height $Height -Width $Width
    New-ChartToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartArea {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('', 'central')][string] $Positioning,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors[]] $DataLabelsColor,
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category',
        [ValidateSet('straight', 'smooth', 'stepline')] $LineCurve = 'straight',
        [int] $LineWidth,
        [RGBColors[]] $LineColor,
        [RGBColors[]] $GridColors,
        [double] $GridOpacity,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', '')][string] $TitleAlignment = '',
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', '')][string] $LegendPosition = '',
        [string] $TitleX,
        [string] $TitleY,
        [int] $MarkerSize,
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend,
        [switch] $Zoom)
    $Options = [ordered] @{}
    New-ChartArea -Options $Options -Data $Data -DataNames $DataNames
    New-ChartStrokeDefinition -Options $Options -LineShow $true -LineCurve $LineCurve -LineWidth $LineWidth -LineColor $LineColor
    New-ChartDataLabels -Options $Options -DataLabelsEnabled $DataLabelsEnabled -DataLabelsOffsetX $DataLabelsOffsetX -DataLabelsFontSize $DataLabelsFontSize -DataLabelsColor $DataLabelsColor
    New-ChartAxisX -Options $Options -Title $TitleX -DataCategoriesType $DataCategoriesType -DataCategories $DataLegend
    New-ChartAxisY -Options $Options -Title $TitleY
    New-ChartMarker -Options $Options -MarkerSize $MarkerSize
    New-ChartTitle -Options $Options -Title $Title -TitleAlignment $TitleAlignment
    New-ChartGridColors -Options $Options -GridColors $GridColors -GridOpacity $GridOpacity
    New-ChartLegend -Options $Options -LegendPosition $LegendPosition
    New-ChartSize -Options $Options -Height $Height -Width $Width
    New-ChartZoom -Options $Options -Enabled:$Zoom
    New-ChartToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartBar {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('', 'central')][string] $Positioning,
        [ValidateSet('bar', 'barStacked', 'barStacked100Percent')] $Type = 'bar',
        [RGBColors[]] $Colors,
        [switch] $PatternedColors,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', '')][string] $TitleAlignment = '',
        [bool] $Horizontal = $true,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [nullable[RGBColors]] $DataLabelsColor,
        [switch] $Distributed,
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', '')][string] $LegendPosition = '',
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend)
    $Options = [ordered] @{}
    New-ChartBar -Options $Options -Horizontal $Horizontal -DataLabelsEnabled $DataLabelsEnabled -DataLabelsOffsetX $DataLabelsOffsetX -DataLabelsFontSize $DataLabelsFontSize -DataLabelsColor $DataLabelsColor -Data $Data -DataNames $DataNames -DataLegend $DataLegend -Title $Title -TitleAlignment $TitleAlignment -Type $Type -Colors $Colors -PatternedColors:$PatternedColors -Distributed:$Distributed
    New-ChartLegend -Options $Options -LegendPosition $LegendPosition
    New-ChartSize -Options $Options -Height $Height -Width $Width
    New-ChartToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartDataSet {
    [CmdletBinding()]
    param([Array] $Data,
        [Array] $DataNames)
    if ($null -ne $Data -and $null -ne $DataNames) {
        if ($Data[0] -is [Array]) {
            if ($Data[0].Count -eq $DataNames.Count) {
                for ($a = 0; $a -lt $Data.Count; $a++) {
                    @{name = $DataNames[$a]
                        data = $Data[$a]
                    }
                }
            } elseif ($Data.Count -eq $DataNames.Count) {
                for ($a = 0; $a -lt $Data.Count; $a++) {
                    @{name = $DataNames[$a]
                        data = $Data[$a]
                    }
                }
            } else {New-HTMLChartDataSet -Data $Data}
        } else {
            if ($null -ne $DataNames) {
                @{name = $DataNames
                    data = $Data
                }
            } else {@{data = $Data}
            }
        }
    } elseif ($null -ne $Data) {if ($Data[0] -is [Array]) {foreach ($D in $Data) {@{data = $D}}} else {@{data = $Data}
        }
    } else {
        Write-Warning -Message "New-HTMLChartDataSet - No Data provided. Unabled to create dataset."
        return @{}
    }
}
function New-HTMLChartLine {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('', 'central')][string] $Positioning,
        [bool] $DataLabelsEnabled = $true,
        [int] $DataLabelsOffsetX = -6,
        [string] $DataLabelsFontSize = '12px',
        [RGBColors[]] $DataLabelsColor,
        [ValidateSet('datetime', 'category', 'numeric')][string] $DataCategoriesType = 'category',
        [ValidateSet('straight', 'smooth', 'stepline')] $LineCurve = 'straight',
        [int] $LineWidth,
        [RGBColors[]] $LineColor,
        [RGBColors[]] $GridColors,
        [double] $GridOpacity,
        [string] $Title,
        [ValidateSet('center', 'left', 'right', '')][string] $TitleAlignment = '',
        [ValidateSet('top', 'topRight', 'left', 'right', 'bottom', '')][string] $LegendPosition = '',
        [string] $TitleX,
        [string] $TitleY,
        [int] $MarkerSize,
        [Array] $Data,
        [Array] $DataNames,
        [Array] $DataLegend)
    $Options = [ordered] @{}
    New-ChartLine -Options $Options -Data $Data -DataNames $DataNames
    New-ChartStrokeDefinition -Options $Options -LineShow $true -LineCurve $LineCurve -LineWidth $LineWidth -LineColor $LineColor
    New-ChartDataLabels -Options $Options -DataLabelsEnabled $DataLabelsEnabled -DataLabelsOffsetX $DataLabelsOffsetX -DataLabelsFontSize $DataLabelsFontSize -DataLabelsColor $DataLabelsColor
    New-ChartAxisX -Options $Options -Title $TitleX -DataCategoriesType $DataCategoriesType -DataCategories $DataLegend
    New-ChartAxisY -Options $Options -Title $TitleY
    New-ChartMarker -Options $Options -MarkerSize $MarkerSize
    New-ChartTitle -Options $Options -Title $Title -TitleAlignment $TitleAlignment
    New-ChartGridColors -Options $Options -GridColors $GridColors -GridOpacity $GridOpacity
    New-ChartLegend -Options $Options -LegendPosition $LegendPosition
    New-ChartSize -Options $Options -Height $Height -Width $Width
    New-ChartToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartRadial {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('', 'central')][string] $Positioning,
        [Array] $Names,
        [Array] $Values,
        $Type,
        [ValidateSet('FullCircleTop', 'FullCircleBottom', 'FullCircleBottomLeft', 'FullCircleLeft', 'Speedometer', 'SemiCircleGauge')] $CircleType = 'FullCircleTop',
        [string] $LabelAverage)
    $Options = [ordered] @{}
    New-ChartRadial -Options $Options -Names $Names -Values $Values -Type $Type
    New-ChartRadialCircleType -Options $Options -CircleType $CircleType
    New-ChartRadialDataLabels -Options $Options -Label $LabelAverage
    New-ChartSize -Options $Options -Height $Height -Width $Width
    New-ChartToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
function New-HTMLChartSpark {
    [CmdletBinding()]
    param([nullable[int]] $Height = 350,
        [nullable[int]] $Width,
        [ValidateSet('', 'central')][string] $Positioning,
        [Array] $Data,
        [string] $TitleText,
        [string] $SubTitleText,
        [int] $FontSizeTitle = 24,
        [int] $FontSizeSubtitle = 14,
        [nullable[RGBColors]] $Color)
    $Options = [ordered] @{}
    New-ChartSpark -Options $Options -Color $Color -Title $TitleText -SubTitle $SubTitleText -FontSizeTitle $FontSizeTitle -FontSizeSubtitle $FontSizeSubtitle -Values $Data
    New-ChartSize -Options $Options -Height $Height -Width $Width
    New-ChartToolbar -Options $Options
    New-ApexChart -Positioning $Positioning -Options $Options
}
Function New-HTMLCodeBlock {
    [CmdletBinding()]
    Param ([Parameter(Mandatory = $true)][String] $Code,
        [Parameter(Mandatory = $false)]
        [ValidateSet('assembly',
            'asm',
            'avrassembly',
            'avrasm',
            'c',
            'cpp',
            'c++',
            'csharp',
            'css',
            'cython',
            'cordpro',
            'diff',
            'docker',
            'dockerfile',
            'generic',
            'standard',
            'groovy',
            'go',
            'golang',
            'html',
            'ini',
            'conf',
            'java',
            'js',
            'javascript',
            'jquery',
            'mootools',
            'ext.js',
            'json',
            'kotlin',
            'less',
            'lua',
            'gfm',
            'md',
            'markdown',
            'octave',
            'matlab',
            'nsis',
            'php',
            'powershell',
            'prolog',
            'py',
            'python',
            'raw',
            'ruby',
            'rust',
            'scss',
            'sass',
            'shell',
            'bash',
            'sql',
            'squirrel',
            'swift',
            'typescript',
            'vhdl',
            'visualbasic',
            'vb',
            'xml',
            'yaml')]
        [String] $Style = 'powershell',
        [Parameter(Mandatory = $false)]
        [ValidateSet('enlighter',
            'standard',
            'classic',
            'bootstrap4',
            'beyond',
            'godzilla',
            'eclipse',
            'mootwo',
            'droide',
            'minimal',
            'atomic',
            'dracula',
            'rowhammer')][String] $Theme,
        [Parameter(Mandatory = $false)][String] $Group,
        [Parameter(Mandatory = $false)][String] $Title,
        [Parameter(Mandatory = $false)][String] $Highlight,
        [Parameter(Mandatory = $false)][nullable[bool]] $ShowLineNumbers,
        [Parameter(Mandatory = $false)][String] $LineOffset)
    $Script:HTMLSchema.Features.CodeBlocks = $true
    $Attributes = [ordered]@{'data-enlighter-language' = "$Style".ToLower()
        'data-enlighter-theme' = "$Theme".ToLower()
        'data-enlighter-group' = "$Group".ToLower()
        'data-enlighter-title' = "$Title"
        'data-enlighter-linenumbers' = "$ShowLineNumbers"
        'data-enlighter-highlight' = "$Highlight"
        'data-enlighter-lineoffset' = "$LineOffset".ToLower()
    }
    New-HTMLTag -Tag 'pre' -Attributes $Attributes {$Code}
}
Function New-HTMLContent {
    [CmdletBinding()]
    Param ([Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content = $(Throw "Open curly brace with Content"),
        [alias('ColumnCount', 'Columns')][ValidateSet('1', '2', '3', '4', '5 ', '6', '7', '8', '9', '10', '11', '12')][string] $Count = 1,
        [Parameter(Mandatory = $false)][string]$HeaderText,
        [RGBColors]$HeaderTextColor = [RGBColors]::White,
        [string][ValidateSet('center', 'left', 'right', 'justify')] $HeaderTextAlignment = 'center',
        [alias('BackgroundShade')][RGBColors]$BackgroundColor,
        [Parameter(Mandatory = $false)][switch] $CanCollapse,
        [Parameter(Mandatory = $false)][switch] $IsHidden,
        [switch] $Collapsed,
        [int] $Height,
        [switch] $Invisible)
    $RandomNumber = Get-Random
    $TextHeaderColorFromRGB = ConvertFrom-Color -Color $HeaderTextColor
    if ($null -ne $BackgroundColor) {
        $BackGroundColorFromRGB = ConvertFrom-Color -Color $BackgroundColor
        $BGStyleColor = "background-color:$BackGroundColorFromRGB;"
    } else {$BGStyleColor = ''}
    if ($CanCollapse) {
        $Script:HTMLSchema.Features.HideSection = $true
        if ($IsHidden) {
            $ShowStyle = "color: $TextHeaderColorFromRGB;"
            $HideStyle = "color: $TextHeaderColorFromRGB; display:none;"
        } else {
            if ($Collapsed) {
                $HideStyle = "color: $TextHeaderColorFromRGB; display:none;"
                $ShowStyle = "color: $TextHeaderColorFromRGB;"
                $HiddenDivStyle = 'display:none;'
            } else {
                $ShowStyle = "color: $TextHeaderColorFromRGB; display:none;"
                $HideStyle = "color: $TextHeaderColorFromRGB;"
            }
        }
    } else {
        if ($IsHidden) {
            $ShowStyle = "color: $TextHeaderColorFromRGB;"
            $HideStyle = "color: $TextHeaderColorFromRGB; display:none;"
        } else {
            $ShowStyle = "color: $TextHeaderColorFromRGB; display:none;"
            $HideStyle = "color: $TextHeaderColorFromRGB; display:none;"
        }
    }
    if ($Height -ne 0) {$StyleHeight = "height: $($Height)px"}
    $StyleWidth = "width: calc(100% / $Count - 15px)"
    if ($IsHidden) {$DivContentStyle = "display:none; $StyleWidth; $StyleHeight; $BGStyleColor"} else {$DivContentStyle = "$StyleWidth; $StyleHeight; $BGStyleColor"}
    $DivHeaderStyle = "text-align: $HeaderTextAlignment;"
    $HeaderStyle = "color: $TextHeaderColorFromRGB;"
    if ($Invisible) {New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultContainerOther'} -Value {New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultContainerOther defaultPanelOther'} -Value {Invoke-Command -ScriptBlock $Content}}
    } else {New-HTMLTag -Tag 'div' -Attributes @{'class' = "defaultSection defaultCard"; 'style' = $DivContentStyle} -Value {New-HTMLTag -Tag 'div' -Attributes @{'class' = "defaultHeader"; 'style' = $DivHeaderStyle} -Value {New-HTMLAnchor -Name $HeaderText -Text $HeaderText -Style $HeaderStyle
                New-HTMLAnchor -Id "show_$RandomNumber" -Href 'javascript:void(0)' -OnClick "show('$RandomNumber');" -Style $ShowStyle -Text '(Show)'
                New-HTMLAnchor -Id "hide_$RandomNumber" -Href 'javascript:void(0)' -OnClick "hide('$RandomNumber');" -Style $HideStyle -Text '(Hide)'}
            New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultContainerOther'; id = $RandomNumber; Style = $HiddenDivStyle} -Value {New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultContainer defaultPanelOther collapsable'; id = $RandomNumber} -Value {Invoke-Command -ScriptBlock $Content}}}
    }
}
Function New-HTMLHeading {
    [CmdletBinding()]
    Param ([validateset('h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7')][string]$Heading,
        [string]$HeadingText,
        [validateset('', 'central')][string] $Type,
        [switch] $Underline,
        [nullable[RGBColors]] $Color)
    if ($null -ne $Color) {
        $RGBcolor = ConvertFrom-Color -Color $Color
        $Attributes = @{style = "color: $RGBcolor;"}
    } else {$Attributes = @{}
    }
    if ($Type -eq 'central') {$Attributes.Class = 'central'}
    if ($Underline) {$Attributes.Class = "$($Attributes.Class) underline"}
    New-HTMLTag -Tag $Heading -Attributes $Attributes {$HeadingText}
}
function New-HTMLHorizontalLine {
    [CmdletBinding()]
    param()
    New-HTMLTag -Tag 'hr' -SelfClosing
}
function New-HTMLImage {
    <#
    .SYNOPSIS
    Short description
     
    .DESCRIPTION
    Long description
     
    .PARAMETER Source
    Parameter description
     
    .PARAMETER UrlLink
    Parameter description
     
    .PARAMETER AlternativeText
    Parameter description
     
    .PARAMETER Class
    Parameter description
     
    .PARAMETER Target
    Parameter description
     
    .PARAMETER Width
    Parameter description
     
    .PARAMETER Height
    Parameter description
     
    .EXAMPLE
    New-HTMLImage -Source 'https://evotec.pl/image.png' -UrlLink 'https://evotc.pl/' -AlternativeText 'My other text' -Class 'otehr' -Width '100%'
     
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param([string] $Source,
        [Uri] $UrlLink = '',
        [string] $AlternativeText = '',
        [string] $Class = 'Logo',
        [string] $Target = '_blank',
        [string] $Width,
        [string] $Height)
    New-HTMLTag -Tag 'div' -Attributes @{class = $Class.ToLower()} {$AAttributes = [ordered]@{'target' = $Target
            'href' = $UrlLink
        }
        New-HTMLTag -Tag 'a' -Attributes $AAttributes {$ImgAttributes = [ordered]@{'src' = "$Source"
                'alt' = "$AlternativeText"
                'width' = "$Height"
                'height' = "$Width"
            }
            New-HTMLTag -Tag 'img' -Attributes $ImgAttributes}}
}
function New-HTMLList {
    [CmdletBinding()]
    param([ScriptBlock]$ListItems,
        [ValidateSet('Unordered', 'Ordered')] [string] $Type = 'Unordered',
        [RGBColors] $Color,
        [RGBColors] $BackGroundColor,
        [int] $FontSize,
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string] $FontWeight,
        [ValidateSet('normal', 'italic', 'oblique')][string] $FontStyle,
        [ValidateSet('normal', 'small-caps')][string] $FontVariant,
        [string] $FontFamily,
        [ValidateSet('left', 'center', 'right', 'justify')][string] $Alignment,
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string] $TextDecoration,
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string] $TextTransform,
        [ValidateSet('rtl')][string] $Direction,
        [switch] $LineBreak)
    $newHTMLSplat = @{}
    if ($Alignment) {$newHTMLSplat.Alignment = $Alignment}
    if ($FontSize) {$newHTMLSplat.FontSize = $FontSize}
    if ($TextTransform) {$newHTMLSplat.TextTransform = $TextTransform}
    if ($Color) {$newHTMLSplat.Color = $Color}
    if ($FontFamily) {$newHTMLSplat.FontFamily = $FontFamily}
    if ($Direction) {$newHTMLSplat.Direction = $Direction}
    if ($FontStyle) {$newHTMLSplat.FontStyle = $FontStyle}
    if ($TextDecoration) {$newHTMLSplat.TextDecoration = $TextDecoration}
    if ($BackGroundColor) {$newHTMLSplat.BackGroundColor = $BackGroundColor}
    if ($FontVariant) {$newHTMLSplat.FontVariant = $FontVariant}
    if ($FontWeight) {$newHTMLSplat.FontWeight = $FontWeight}
    if ($LineBreak) {$newHTMLSplat.LineBreak = $LineBreak}
    [bool] $SpanRequired = $false
    foreach ($Entry in $newHTMLSplat.GetEnumerator()) {
        if ((Get-ObjectCount -Object $Entry.Value) -gt 0) {
            $SpanRequired = $true
            break
        }
    }
    if ($SpanRequired) {New-HTMLSpanStyle @newHTMLSplat {if ($Type -eq 'Unordered') {New-HTMLTag -Tag 'ul' {Invoke-Command -ScriptBlock $ListItems}} else {New-HTMLTag -Tag 'ol' {Invoke-Command -ScriptBlock $ListItems}}}} else {if ($Type -eq 'Unordered') {New-HTMLTag -Tag 'ul' {Invoke-Command -ScriptBlock $ListItems}} else {New-HTMLTag -Tag 'ol' {Invoke-Command -ScriptBlock $ListItems}}}
}
function New-HTMLListItem {
    [CmdletBinding()]
    param([string] $Text,
        [RGBColors[]] $Color = @(),
        [RGBColors[]] $BackGroundColor = @(),
        [int[]] $FontSize = @(),
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string[]] $FontWeight = @(),
        [ValidateSet('normal', 'italic', 'oblique')][string[]] $FontStyle = @(),
        [ValidateSet('normal', 'small-caps')][string[]] $FontVariant = @(),
        [string[]] $FontFamily = @(),
        [ValidateSet('left', 'center', 'right', 'justify')][string[]] $Alignment = @(),
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string[]] $TextDecoration = @(),
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string[]] $TextTransform = @(),
        [ValidateSet('rtl')][string[]] $Direction = @(),
        [switch] $LineBreak)
    $newHTMLTextSplat = @{Alignment = $Alignment
        FontSize = $FontSize
        TextTransform = $TextTransform
        Text = $Text
        Color = $Color
        FontFamily = $FontFamily
        Direction = $Direction
        FontStyle = $FontStyle
        TextDecoration = $TextDecoration
        BackGroundColor = $BackGroundColor
        FontVariant = $FontVariant
        FontWeight = $FontWeight
        LineBreak = $LineBreak
    }
    if (($FontSize.Count -eq 0) -or ($FontSize -eq 0)) {$Size = ''} else {$size = "$($FontSize)px"}
    $Style = @{style = @{'color' = ConvertFrom-Color -Color $Color
            'background-color' = ConvertFrom-Color -Color $BackGroundColor
            'font-size' = $Size
            'font-weight' = $FontWeight
            'font-variant' = $FontVariant
            'font-family' = $FontFamily
            'font-style' = $FontStyle
            'text-align' = $Alignment
            'text-decoration' = $TextDecoration
            'text-transform' = $TextTransform
            'direction' = $Direction
        }
    }
    New-HTMLTag -Tag 'li' -Attributes $Style -Value {New-HTMLText @newHTMLTextSplat -SkipParagraph}
}
function New-HTMLLogo {
    param([String] $LogoPath,
        [string] $LeftLogoName = "Sample",
        [string] $RightLogoName = "Alternate",
        [string] $LeftLogoString,
        [string] $RightLogoString,
        [switch] $HideLogos)
    $LogoSources = Get-HTMLLogos -RightLogoName $RightLogoName -LeftLogoName $LeftLogoName -LeftLogoString $LeftLogoString -RightLogoString $RightLogoString
    Convert-StyleContent1 -Options $Options
    $Options = [PSCustomObject] @{Logos = $LogoSources
        ColorSchemes = $ColorSchemes
    }
    if ($HideLogos -eq $false) {
        $Leftlogo = $Options.Logos[$LeftLogoName]
        $Rightlogo = $Options.Logos[$RightLogoName]
        '<!-- START LOGO -->'
        $LogoContent = @"
        <table><tbody>
        <tr>
            <td class="clientlogo"><img src="$Leftlogo" /></td>
            <td class="MainLogo"><img src="$Rightlogo" /></td>
        </tr>
        </tbody></table>
"@

        $LogoContent
        '<!-- END LOGO -->'
    }
}
function New-HTMLMessage {
    param([Parameter(Mandatory = $false, Position = 0)][alias('')][ScriptBlock] $Content,
        $Text)
    $Script:HTMLSchema.Features.Message = $true
    New-HTMLTag -Tag 'div' -Attributes @{class = 'message green'} {New-HTMLTag -Tag 'div' -Attributes @{class = 'message-icon'} {New-HTMLTag -Tag 'i' -Attributes @{class = 'fa fa-bell-o'}}
        New-HTMLTag -Tag 'div' -Attributes @{class = 'message-body'} {New-HTMLTag -Tag 'p' -Attributes @{class = ''} {$Text}}}
}
Function New-HTMLPanel {
    [alias('New-HTMLColumn')]
    [CmdletBinding()]
    param ([Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content = $(Throw "Open curly brace with Content"),
        [alias('ColumnCount', 'Columns')][ValidateSet('1', '2', '3', '4', '5 ', '6', '7', '8', '9', '10', '11', '12')][string] $Count = 1,
        [alias('BackgroundShade')][RGBColors]$BackgroundColor,
        [switch] $Invisible,
        [int] $Height)
    if ($Height -ne 0) {$StyleHeight = "height: $($Height)px"}
    $StyleWidth = "width: calc(100% / $Count - 10px)"
    if ($null -ne $BackgroundColor) {
        $BackGroundColorFromRGB = ConvertFrom-Color -Color $BackgroundColor
        $DivColumnStyle = "background-color:$BackGroundColorFromRGB; $StyleWidth; $StyleHeight;"
    } else {$DivColumnStyle = "$StyleWidth; $StyleHeight;"}
    if ($Invisible) {$DivColumnStyle = "$DivColumnStyle box-shadow: unset !important;"}
    New-HTMLTag -Tag 'div' -Attributes @{class = "defaultPanel defaultCard"; style = $DivColumnStyle} {Invoke-Command -ScriptBlock $Content}
}
function New-HTMLResourceCSS {
    [alias('New-ResourceCSS', 'New-CSS')]
    [CmdletBinding()]
    param([alias('ScriptContent')][Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content,
        [string] $Link,
        [string] $ResourceComment,
        [string] $FilePath)
    $Output = @("<!-- CSS $ResourceComment START -->"
        foreach ($File in $FilePath) {
            if ($File -ne '') {
                if (Test-Path -LiteralPath $File) {New-HTMLTag -Tag 'style' -Attributes @{type = 'text/css'} {Write-Verbose "New-HTMLResourceCSS - Reading file from $File"
                        Get-Content -LiteralPath $File}
                }
            }
        }
        foreach ($L in $Link) {
            if ($L -ne '') {
                Write-Verbose "New-HTMLResourceCSS - Adding link $L"
                New-HTMlTag -Tag 'link' -Attributes @{rel = "stylesheet"; type = "text/css"; href = $L} -SelfClosing
            }
        }
        "<!-- CSS $ResourceComment END -->")
    if ($Output.Count -gt 2) {$Output}
}
function New-HTMLResourceJS {
    [alias('New-ResourceJS', 'New-JavaScript')]
    [CmdletBinding()]
    param([alias('ScriptContent')][Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $Content,
        [string[]] $Link,
        [string] $ResourceComment,
        [string[]] $FilePath)
    $Output = @("<!-- JS $ResourceComment START -->"
        foreach ($File in $FilePath) {if ($File -ne '') {if (Test-Path -LiteralPath $File) {New-HTMLTag -Tag 'script' -Attributes @{type = 'text/javascript'} {Get-Content -LiteralPath $File}} else {return}}
        }
        foreach ($L in $Link) {if ($L -ne '') {New-HTMlTag -Tag 'script' -Attributes @{type = "text/javascript"; src = $L}} else {return}
        }
        "<!-- JS $ResourceComment END -->")
    if ($Output.Count -gt 2) {$Output}
}
function New-HTMLSpanStyle {
    [CmdletBinding()]
    param([ScriptBlock] $Content,
        [nullable[RGBColors]] $Color,
        [nullable[RGBColors]] $BackGroundColor,
        [int] $FontSize,
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string] $FontWeight,
        [ValidateSet('normal', 'italic', 'oblique')][string] $FontStyle,
        [ValidateSet('normal', 'small-caps')][string] $FontVariant,
        [string] $FontFamily,
        [ValidateSet('left', 'center', 'right', 'justify')][string] $Alignment,
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string] $TextDecoration,
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string] $TextTransform,
        [ValidateSet('rtl')][string] $Direction,
        [switch] $LineBreak)
    Write-Verbose 'New-SpanStyle - BEGIN'
    if ($FontSize -eq 0) {$Size = ''} else {$size = "$($FontSize)px"}
    $Style = @{style = @{'color' = ConvertFrom-Color -Color $Color
            'background-color' = ConvertFrom-Color -Color $BackGroundColor
            'font-size' = $Size
            'font-weight' = $FontWeight
            'font-variant' = $FontVariant
            'font-family' = $FontFamily
            'font-style' = $FontStyle
            'text-align' = $Alignment
            'text-decoration' = $TextDecoration
            'text-transform' = $TextTransform
            'direction' = $Direction
        }
    }
    if ($Alignment) {$StyleDiv = @{}
        $StyleDiv.Align = $Alignment
        New-HTMLTag -Tag 'div' -Attributes $StyleDiv {New-HTMLTag -Tag 'span' -Attributes $Style {Invoke-Command -ScriptBlock $Content}}
    } else {New-HTMLTag -Tag 'span' -Attributes $Style {Invoke-Command -ScriptBlock $Content}}
}
function New-HTMLStatus {
    param([Parameter(Mandatory = $false, Position = 0)][alias('')][ScriptBlock] $Content)
    $Script:HTMLSchema.Features.StatusButtonical = $true
    New-HTMLTag -Tag 'div' -Attributes @{class = 'buttonicalService'} {Invoke-Command -ScriptBlock $Content}
}
function New-HTMLStatusItem {
    param($ServiceName,
        $ServiceStatus,
        [ValidateSet('Dead', 'Bad', 'Good')]$Icon = 'Good',
        [ValidateSet('0%', '10%', '30%', '70%', '100%')][string] $Percentage = '100%')
    if ($Icon -eq 'Dead') {$IconType = 'performanceDead'} elseif ($Icon -eq 'Bad') {$IconType = 'performanceProblem'} elseif ($Icon -eq 'Good') {}
    if ($Percentage -eq '100%') {$Colors = 'background-color: #0ef49b;'} elseif ($Percentage -eq '70%') {$Colors = 'background-color: #d2dc69;'} elseif ($Percentage -eq '30%') {$Colors = 'background-color: #faa04b;'} elseif ($Percentage -eq '10%') {$Colors = 'background-color: #ff9035;'} elseif ($Percentage -eq '0%') {$Colors = 'background-color: #ff5a64;'}
    New-HTMLTag -Tag 'div' -Attributes @{class = 'buttonical'; style = $Colors} -Value {New-HTMLTag -Tag 'div' -Attributes @{class = 'label'} {New-HTMLTag -Tag 'span' -Attributes @{class = 'performance'} {$ServiceName}}
        New-HTMLTag -Tag 'div' -Attributes @{class = 'middle'}
        New-HTMLTag -Tag 'div' -Attributes @{class = 'status'} {New-HTMLTag -Tag 'input' -Attributes @{name = Get-Random; type = 'radio'; value = 'other-item'; checked = 'true'} -SelfClosing
            New-HTMLTag -Tag 'span' -Attributes @{class = "performance $IconType"} {$ServiceStatus}}}
}
function New-HTMLTab {
    [CmdletBinding()]
    param([Parameter(Mandatory = $false, Position = 0)][ValidateNotNull()][ScriptBlock] $HtmlData = $(Throw "No curly brace?)"),
        [Parameter(Mandatory = $false, Position = 1)][String]$TabHeading,
        [alias('Name')][string] $TabName)
    $Script:HTMLSchema.Features.Tabs = $true
    $Script:HTMLSchema.Features.JQuery = $true
    foreach ($Tab in $Script:HTMLSchema.TabsHeaders) {$Tab.Current = $false}
    $Tab = @{}
    $Tab.ID = "Tab-$(Get-RandomStringName -Size 8)"
    $Tab.Name = $TabName
    $Tab.Current = $true
    if ($Script:HTMLSchema.TabsHeaders | Where-Object {$_.Active -eq $true}) {$Tab.Active = $false} else {$Tab.Active = $true}
    $Script:HTMLSchema.TabsHeaders.Add($Tab)
    if ($Tab.Active) {$Class = 'tabs-content active'} else {$Class = 'tabs-content'}
    New-HTMLTag -Tag 'div' -Attributes @{id = $Tab.ID; class = $Class} {if (-not [string]::IsNullOrWhiteSpace($TabHeading)) {New-HTMLTag -Tag 'h7' {$TabHeading}}
        Invoke-Command -ScriptBlock $HtmlData}
}
function New-HTMLTabHead {
    [CmdletBinding()]
    Param ()
    New-HTMLTag -Tag 'div' -Attributes @{class = 'tabsWrapper'} {New-HTMLTag -Tag 'div' -Attributes @{class = 'tabs'} {New-HTMLTag -Tag 'div' -Attributes @{class = 'selector'}
            foreach ($Tab in $Script:HTMLSchema.TabsHeaders) {
                if ($Tab.Active) {
                    $AttributesA = @{'class' = 'active'
                        'href' = 'javascript:void(0)'
                        'data-id' = "$($Tab.Id)"
                    }
                    New-HTMLTag -Tag 'a' -Attributes $AttributesA {New-HTMLTag -Tag 'i' -Attributes @{class = 'fas fa-bomb'} -Value {$Tab.Name}}
                } else {
                    $AttributesA = @{'class' = ''
                        'href' = 'javascript:void(0)'
                        'data-id' = "$($Tab.Id)"
                    }
                    New-HTMLTag -Tag 'a' -Attributes $AttributesA {New-HTMLTag -Tag 'i' -Attributes @{class = 'fas fa-bomb'} -Value {$Tab.Name}}
                }
            }}}
}
function New-HTMLTable {
    [CmdletBinding()]
    param([Parameter(Mandatory = $false, Position = 0)][ScriptBlock] $ConditionalFormatting,
        [alias('ArrayOfObjects', 'Object', 'Table')][Array] $DataTable,
        [string[]][ValidateSet('copyHtml5', 'excelHtml5', 'csvHtml5', 'pdfHtml5')] $Buttons = @('copyHtml5', 'excelHtml5', 'csvHtml5', 'pdfHtml5'),
        [string[]][ValidateSet('numbers', 'simple', 'simple_numbers', 'full', 'full_numbers', 'first_last_numbers')] $PagingStyle = 'full_numbers',
        [int[]]$PagingOptions = @(15, 25, 50, 100),
        [switch]$DisablePaging,
        [switch]$DisableOrdering,
        [switch]$DisableInfo,
        [switch]$HideFooter,
        [switch]$DisableColumnReorder,
        [switch]$DisableProcessing,
        [switch]$DisableResponsiveTable,
        [switch]$DisableSelect,
        [switch]$DisableStateSave,
        [switch]$DisableSearch,
        [switch]$ScrollCollapse,
        [switch]$OrderMulti,
        [switch]$Filtering,
        [ValidateSet('Top', 'Bottom', 'Both')][string]$FilteringLocation = 'Bottom',
        [string[]][ValidateSet('display', 'cell-border', 'compact', 'hover', 'nowrap', 'order-column', 'row-border', 'stripe')] $Style = @('display', 'compact'),
        [switch]$Simplify,
        [string]$TextWhenNoData = 'No data available.',
        [int] $ScreenSizePercent = 0,
        [string[]] $DefaultSortColumn,
        [int[]] $DefaultSortIndex,
        [ValidateSet('Ascending', 'Descending')][string] $DefaultSortOrder = 'Ascending',
        [alias('Search')][string]$Find,
        [switch] $InvokeHTMLTags,
        [switch] $DisableNewLine)
    [string] $DataTableName = "DT-$(Get-RandomStringName -Size 8 -LettersOnly)"
    if ($null -eq $DataTable -or $DataTable.Count -eq 0) {$DataTable = $TextWhenNoData}
    if ($DataTable[0] -is [System.Collections.IDictionary]) {
        Write-Verbose 'New-HTMLTable - Working with IDictionary'
        [Array ] $Table = $($DataTable).GetEnumerator() | Select-Object Name, Value | ConvertTo-Html -Fragment | Select-Object -SkipLast 1 | Select-Object -Skip 2
    } elseif ($DataTable[0] -is [string]) {[Array] $Table = $DataTable | ForEach-Object {[PSCustomObject]@{'Name' = $_}} | ConvertTo-Html -Fragment | Select-Object -SkipLast 1 | Select-Object -Skip 2
    } else {
        Write-Verbose 'New-HTMLTable - Working with Objects'
        [Array] $Table = $DataTable | ConvertTo-Html -Fragment | Select-Object -SkipLast 1 | Select-Object -Skip 2
    }
    [string] $Header = $Table | Select-Object -First 1
    [string[]] $HeaderNames = $Header -replace '</th></tr>' -replace '<tr><th>' -split '</th><th>'
    $Table = $Table | Select-Object -Skip 1
    $Options = [ordered] @{dom = 'Bfrtip'
        buttons = @($Buttons)
        "colReorder" = -not $DisableColumnReorder.IsPresent
        "paging" = -not $DisablePaging
        "scrollCollapse" = $ScrollCollapse.IsPresent
        "pagingType" = $PagingStyle
        "lengthMenu" = @(@($PagingOptions, -1)
            @($PagingOptions, "All"))
        "ordering" = -not $DisableOrdering.IsPresent
        "order" = @()
        "info" = -not $DisableInfo.IsPresent
        "procesing" = -not $DisableProcessing.IsPresent
        "responsive" = @{details = -not $DisableResponsiveTable.IsPresent}
        "select" = -not $DisableSelect.IsPresent
        "searching" = -not $DisableSearch.IsPresent
        "stateSave" = -not $DisableStateSave.IsPresent
    }
    if ($OrderMulti) {$Options.orderMulti = $OrderMulti.IsPresent}
    if ($Find -ne '') {$Options.search = @{search = $Find}
    }
    if ($DefaultSortOrder -eq 'Ascending') {$Sort = 'asc'} else {$Sort = 'dsc'}
    if ($DefaultSortColumn.Count -gt 0) {
        $ColumnsOrder = foreach ($Column in $DefaultSortColumn) {
            $DefaultSortingNumber = ($HeaderNames).ToLower().IndexOf($Column.ToLower())
            if ($DefaultSortingNumber -ne -1) {, @($DefaultSortingNumber, $Sort)}
        }
    }
    if ($DefaultSortIndex.Count -gt 0 -and $DefaultSortColumn.Count -eq 0) {
        $ColumnsOrder = foreach ($Column in $DefaultSortIndex) {if ($Column -ne -1) {, @($Column, $Sort)}}
        $Options."order" = @($ColumnsOrder)
        $Options.colReorder = $false
    }
    if ($ScreenSizePercent -gt 0) {$Options."scrollY" = "$($ScreenSizePercent)vh"}
    if ($null -ne $ConditionalFormatting) {$Options.columnDefs = ''}
    $Options = $Options | ConvertTo-Json -Depth 6
    if ($null -ne $ConditionalFormatting) {$Conditional = Invoke-Command -ScriptBlock $ConditionalFormatting}
    $Options = New-TableConditionalFormatting -Options $Options -ConditionalFormatting $Conditional -Header $HeaderNames
    [Array] $Tabs = ($Script:HTMLSchema.TabsHeaders | Where-Object {$_.Current -eq $true})
    if ($Tabs.Count -eq 0) {$Tab = @{Active = $true}
    } else {$Tab = $Tabs[0]}
    if (-not $Simplify) {
        $Script:HTMLSchema.Features.DataTables = $true
        $Script:HTMLSchema.Features.DataTablesPDF = $true
        $Script:HTMLSchema.Features.DataTablesExcel = $true
        $TableAttributes = @{id = $DataTableName; class = "$($Style -join ' ')"}
        $FilteringOutput = Add-TableFiltering -Filtering $Filtering -FilteringLocation $FilteringLocation
        $FilteringTopCode = $FilteringOutput.FilteringTopCode
        $FilteringBottomCode = $FilteringOutput.FilteringBottomCode
        if ($Tab.Active -eq $true) {
            New-HTMlTag -Tag 'script' {@"
                `$(document).ready(function() {
                    $FilteringTopCode
                    // Table code
                    var table = `$('#$DataTableName').DataTable(
                        $($Options)
                    );
                    $FilteringBottomCode
                });
"@
}
        } else {
            [string] $TabName = $Tab.Id
            New-HTMlTag -Tag 'script' {@"
                    `$(document).ready(function() {
                        `$('.tabs').on('click', 'a', function (event) {
                            if (`$(event.currentTarget).attr("data-id") == "$TabName" && !$.fn.dataTable.isDataTable("#$DataTableName")) {
                                $FilteringTopCode
                                // Table code
                                var table = `$('#$DataTableName').DataTable(
                                    $($Options)
                                );
                                $FilteringBottomCode
                            };
                        });
                    });
"@
}
        }
    } else {$TableAttributes = @{class = 'sortable'}
    }
    if ($InvokeHTMLTags) {$Table = $Table -replace '&lt;', '<' -replace '&gt;', '>'}
    if (-not $DisableNewLine) {$Table = $Table -replace '(?m)\s+$', "<BR>"}
    New-HTMLTag -Tag 'div' -Attributes @{class = 'defaultPanelOther'} -Value {New-HTMLTag -Tag 'table' -Attributes $TableAttributes {New-HTMLTag -Tag 'thead' {$Header}
            New-HTMLTag -Tag 'tbody' {$Table}
            if (-not $HideFooter) {New-HTMLTag -Tag 'tfoot' {$Header}}}}
}
function New-HTMLTableCondition {
    [CmdletBinding()]
    param([alias('ColumnName')][string] $Name,
        [ValidateSet('number', 'string')][string] $Type,
        [ValidateSet('lt', 'le', 'eq', 'ge', 'gt')][string] $Operator,
        [Object] $Value,
        [switch] $Row,
        [nullable[RGBColors]] $Color,
        [nullable[RGBColors]] $BackgroundColor)
    return [PSCustomObject] @{Row = $Row; Type = $Type; Name = $Name; Operator = $Operator; Value = $Value; Color = $Color; BackgroundColor = $BackgroundColor}
}
function New-HTMLTag {
    [CmdletBinding()]
    param([Parameter(Mandatory = $false, Position = 0)][alias('Content')][ScriptBlock] $Value,
        [Parameter(Mandatory = $true, Position = 1)][string] $Tag,
        [System.Collections.IDictionary] $Attributes,
        [switch] $SelfClosing)
    $HTMLTag = [Ordered] @{Tag = $Tag
        Attributes = $Attributes
        Value = if ($null -eq $Value) {''} else {Invoke-Command -ScriptBlock $Value}
        SelfClosing = $SelfClosing
    }
    $HTML = Set-Tag -HtmlObject $HTMLTag
    return $HTML
}
function New-HTMLText {
    [CmdletBinding()]
    param([string[]] $Text,
        [RGBColors[]] $Color = @(),
        [RGBColors[]] $BackGroundColor = @(),
        [int[]] $FontSize = @(),
        [ValidateSet('normal', 'bold', 'bolder', 'lighter', '100', '200', '300', '400', '500', '600', '700', '800', '900')][string[]] $FontWeight = @(),
        [ValidateSet('normal', 'italic', 'oblique')][string[]] $FontStyle = @(),
        [ValidateSet('normal', 'small-caps')][string[]] $FontVariant = @(),
        [string[]] $FontFamily = @(),
        [ValidateSet('left', 'center', 'right', 'justify')][string[]] $Alignment = @(),
        [ValidateSet('none', 'line-through', 'overline', 'underline')][string[]] $TextDecoration = @(),
        [ValidateSet('uppercase', 'lowercase', 'capitalize')][string[]] $TextTransform = @(),
        [ValidateSet('rtl')][string[]] $Direction = @(),
        [switch] $LineBreak,
        [switch] $SkipParagraph)
    $DefaultColor = $Color[0]
    $DefaultFontSize = $FontSize[0]
    $DefaultFontWeight = if ($null -eq $FontWeight[0]) {''} else {$FontWeight[0]}
    $DefaultBackGroundColor = $BackGroundColor[0]
    $DefaultFontFamily = if ($null -eq $FontFamily[0]) {''} else {$FontFamily[0]}
    $DefaultFontStyle = if ($null -eq $FontStyle[0]) {''} else {$FontStyle[0]}
    $DefaultTextDecoration = if ($null -eq $TextDecoration[0]) {''} else {$TextDecoration[0]}
    $DefaultTextTransform = if ($null -eq $TextTransform[0]) {''} else {$TextTransform[0]}
    $DefaultFontVariant = if ($null -eq $FontVariant[0]) {''} else {$FontVariant}
    $DefaultDirection = if ($null -eq $Direction[0]) {''} else {$Direction[0]}
    $DefaultAlignment = if ($null -eq $Alignment[0]) {''} else {$Alignment[0]}
    $Output = for ($i = 0; $i -lt $Text.Count; $i++) {
        if ($null -eq $FontWeight[$i]) {$ParamFontWeight = $DefaultFontWeight} else {$ParamFontWeight = $FontWeight[$i]}
        if ($null -eq $FontSize[$i]) {$ParamFontSize = $DefaultFontSize} else {$ParamFontSize = $FontSize[$i]}
        if ($null -eq $Color[$i]) {$ParamColor = $DefaultColor} else {$ParamColor = $Color[$i]}
        if ($null -eq $BackGroundColor[$i]) {$ParamBackGroundColor = $DefaultBackGroundColor} else {$ParamBackGroundColor = $BackGroundColor[$i]}
        if ($null -eq $FontFamily[$i]) {$ParamFontFamily = $DefaultFontFamily} else {$ParamFontFamily = $FontFamily[$i]}
        if ($null -eq $FontStyle[$i]) {$ParamFontStyle = $DefaultFontStyle} else {$ParamFontStyle = $FontStyle[$i]}
        if ($null -eq $TextDecoration[$i]) {$ParamTextDecoration = $DefaultTextDecoration} else {$ParamTextDecoration = $TextDecoration[$i]}
        if ($null -eq $TextTransform[$i]) {$ParamTextTransform = $DefaultTextTransform} else {$ParamTextTransform = $TextTransform[$i]}
        if ($null -eq $FontVariant[$i]) {$ParamFontVariant = $DefaultFontVariant} else {$ParamFontVariant = $FontVariant[$i]}
        if ($null -eq $Direction[$i]) {$ParamDirection = $DefaultDirection} else {$ParamDirection = $Direction[$i]}
        if ($null -eq $Alignment[$i]) {$ParamAlignment = $DefaultAlignment} else {$ParamAlignment = $Alignment[$i]}
        $newSpanTextSplat = @{}
        $newSpanTextSplat.Color = $ParamColor
        $newSpanTextSplat.BackGroundColor = $ParamBackGroundColor
        $newSpanTextSplat.FontSize = $ParamFontSize
        if ($ParamFontWeight -ne '') {$newSpanTextSplat.FontWeight = $ParamFontWeight}
        $newSpanTextSplat.FontFamily = $ParamFontFamily
        if ($ParamFontStyle -ne '') {$newSpanTextSplat.FontStyle = $ParamFontStyle}
        if ($ParamFontVariant -ne '') {$newSpanTextSplat.FontVariant = $ParamFontVariant}
        if ($ParamTextDecoration -ne '') {$newSpanTextSplat.TextDecoration = $ParamTextDecoration}
        if ($ParamTextTransform -ne '') {$newSpanTextSplat.TextTransform = $ParamTextTransform}
        if ($ParamDirection -ne '') {$newSpanTextSplat.Direction = $ParamDirection}
        if ($ParamAlignment -ne '') {$newSpanTextSplat.Alignment = $ParamAlignment}
        $newSpanTextSplat.LineBreak = $LineBreak
        New-HTMLSpanStyle @newSpanTextSplat {if ($Text[$i] -match "\[([^\[]*)\)") {
                $RegexBrackets1 = [regex] "\[([^\[]*)\]"
                $RegexBrackets2 = [regex] "\(([^\[]*)\)"
                $RegexBrackets3 = [regex] "\[([^\[]*)\)"
                $Text1 = $RegexBrackets1.match($Text[$i]).Groups[1].value
                $Text2 = $RegexBrackets2.match($Text[$i]).Groups[1].value
                $Text3 = $RegexBrackets3.match($Text[$i]).Groups[0].value
                if ($Text1 -ne '' -and $Text2 -ne '') {
                    $Link = New-HTMLAnchor -HrefLink $Text2 -Text $Text1
                    $Text[$i].Replace($Text3, $Link)
                }
            } else {$Text[$i]}}
    }
    if ($SkipParagraph) {$Output -join ''} else {New-HTMLTag -Tag 'div' {$Output}}
    if ($LineBreak) {New-HTMLTag -Tag 'br' -SelfClosing}
}
function New-HTMLTimeline {
    param([Parameter(Mandatory = $false, Position = 0)][alias('TimeLineItems')][ScriptBlock] $Content)
    $Script:HTMLSchema.Features.TimeLine = $true
    New-HTMLTag -Tag 'div' -Attributes @{class = 'timelineSimpleContainer'} {if ($null -eq $Value) {''} else {Invoke-Command -ScriptBlock $Content}}
}
function New-HTMLTimelineItem {
    [CmdletBinding()]
    param([DateTime] $Date = (Get-Date),
        [string] $HeadingText,
        [string] $Text,
        [nullable[RGBColors]] $Color)
    $Attributes = @{class = 'timelineSimple-item'
        "date-is" = $Date
    }
    if ($null -ne $Color) {
        $RGBcolor = ConvertFrom-Color -Color $Color
        $Style = "color: $RGBcolor;"
    } else {$Style = ''}
    New-HTMLTag -Tag 'div' -Attributes $Attributes -Value {New-HTMLTag -Tag 'h1' -Attributes @{class = 'timelineSimple'; style = $style} {$HeadingText}
        New-HTMLTag -Tag 'p' -Attributes @{class = 'timelineSimple'} {$Text -Replace [Environment]::NewLine, '<br>' -replace '\n', '<br>'}}
}
function New-HTMLToast {
    [CmdletBinding()]
    param([string] $TextHeader,
        [string] $Text,
        [ValidateSet('Green', 'Blue', 'Orange')] $Color = "Green",
        [ValidateSet('Success', 'Information', 'Exclamation')][string] $Icon = 'Success')
    $Script:HTMLSchema.Features.Toast = $true
    $DivClass = "toast $($Color.ToLower()) central"
    New-HTMLTag -Tag 'div' -Attributes @{class = $DivClass} {New-HTMLTag -Tag 'div' -Attributes @{class = 'toast__icon'} {if ($Icon -eq 'Success') {New-IconSuccess} elseif ($Icon -eq 'Information') {New-IconInfo} elseif ($Icon -eq 'Exclamation') {New-IconExclamation}}
        New-HTMLTag -Tag 'div' -Attributes @{class = 'toast__content'} {New-HTMLTag -Tag 'p' -Attributes @{class = 'toast__type'} {$TextHeader}
            New-HTMLTag -Tag 'p' -Attributes @{class = 'toast__message'} {$Text}}}
}
function New-IconExclamation {
    <#
    .SYNOPSIS
    This function is used for New-HTMLToast
     
    .DESCRIPTION
    Long description
     
    .EXAMPLE
    An example
     
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param()
    $SvgAttributes = [ordered] @{version = "1.1"
        class = "toast__svg"
        xmlns = "http://www.w3.org/2000/svg"
        'xmlns:xlink' = "http://www.w3.org/1999/xlink"
        x = "0px"
        y = "0px"
        viewBox = "0 0 301.691 301.691"
        style = "enable-background:new 0 0 301.691 301.691;"
        'xml:space' = "preserve"
    }
    New-HTMLTag -Tag 'svg' -Attributes $SvgAttributes {$Points = @{points = "119.151,0 129.6,218.406 172.06,218.406 182.54,0 "}
        New-HTMLTag -Tag 'polygon' -Attributes $Points
        $React = @{x = "130.563"
            y = "261.168"
            width = "40.525"
            height = "40.523"
        }
        New-HTMLTag -Tag 'react' -Attributes $React}
}
function New-IconInfo {
    <#
    .SYNOPSIS
    This function is used for New-HTMLToast
     
    .DESCRIPTION
    Long description
     
    .EXAMPLE
    An example
     
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param()
    $SvgAttributes = [ordered] @{version = "1.1"
        class = "toast__svg"
        xmlns = "http://www.w3.org/2000/svg"
        'xmlns:xlink' = "http://www.w3.org/1999/xlink"
        x = "0px"
        y = "0px"
        viewBox = "0 0 32 32"
        style = "enable-background:new 0 0 32 32;"
        'xml:space' = "preserve"
    }
    New-HTMLTag -Tag 'svg' -Attributes $SvgAttributes {$PathAttributes = @{d = "M10,16c1.105,0,2,0.895,2,2v8c0,1.105-0.895,2-2,2H8v4h16v-4h-1.992c-1.102,0-2-0.895-2-2L20,12H8 v4H10z"}
        New-HTMLTag -Tag 'path' -Attributes $PathAttributes
        New-HTMLTag -Tag 'circle' -Attributes @{cx = "16"; cy = "4"; r = "4"}}
}
function New-IconSuccess {
    <#
    .SYNOPSIS
    This function is used for New-HTMLToast
     
    .DESCRIPTION
    Long description
     
    .EXAMPLE
    An example
     
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    param()
    $SvgAttributes = [ordered] @{version = "1.1"
        class = "toast__svg"
        xmlns = "http://www.w3.org/2000/svg"
        'xmlns:xlink' = "http://www.w3.org/1999/xlink"
        x = "0px"
        y = "0px"
        viewBox = "0 0 512 512"
        style = "enable-background:new 0 0 512 512;"
        'xml:space' = "preserve"
    }
    New-HTMLTag -Tag 'svg' -Attributes $SvgAttributes {$PathAttributes = @{d = "M504.502,75.496c-9.997-9.998-26.205-9.998-36.204,0L161.594,382.203L43.702,264.311c-9.997-9.998-26.205-9.997-36.204,0 c-9.998,9.997-9.998,26.205,0,36.203l135.994,135.992c9.994,9.997,26.214,9.99,36.204,0L504.502,111.7 C514.5,101.703,514.499,85.494,504.502,75.496z"}
        New-HTMLTag -Tag 'path' -Attributes $PathAttributes}
}
function New-TableConditionalFormatting {
    [CmdletBinding()]
    param([string] $Options,
        [Array] $ConditionalFormatting,
        [string[]] $Header)
    if ($ConditionalFormatting.Count -gt 0) {
        foreach ($Formatting in $ConditionalFormatting) {if ($Formatting.Operator -eq 'gt') {$Formatting.Operator = '>'} elseif ($Formatting.Operator -eq 'lt') {$Formatting.Operator = '<'} elseif ($Formatting.Operator -eq 'eq') {$Formatting.Operator = '=='} elseif ($Formatting.Operator -eq 'le') {$Formatting.Operator = '<='} elseif ($Formatting.Operator -eq 'ge') {$Formatting.Operator = '>='}}
        $Condition1 = '"createdRow": function (row, data, dataIndex, column) {'
        $Condition3 = foreach ($Condition in $ConditionalFormatting) {
            $ConditionHeaderNr = $Header.ToLower().IndexOf($($Condition.Name.ToLower()))
            [string] $ColorJSDefinition = ''
            [string] $ColorBackgroundJSDefinition = ''
            if ($null -ne $Condition.Color) {
                $RGBColor = (ConvertFrom-Color -Color $Condition.Color)
                $C = @{"color" = $RGBColor} | ConvertTo-Json
                $ColorJSDefinition = ".css($C)"
            }
            if ($null -ne $Condition.BackgroundColor) {
                $RGBBackgroundColor = (ConvertFrom-Color -Color $Condition.BackgroundColor)
                $BG = @{"background-color" = $RGBBackgroundColor} | ConvertTo-Json
                $ColorBackgroundJSDefinition = ".css($BG)"
            }
            if ($null -eq $Condition.Type -or $Condition.Type -eq 'number') {"if (data[$ConditionHeaderNr] $($Condition.Operator) $($Condition.Value)) {"} elseif ($Condition.Type -eq 'string') {"if (data[$ConditionHeaderNr] $($Condition.Operator) '$($Condition.Value)') {"} elseif ($Condition.Type -eq 'date') {"if (new Date(data[$ConditionHeaderNr]) $($Condition.Operator) new Date('$($Condition.Value)')) {"}
            if ($null -ne $Condition.Row -and $Condition.Row -eq $true) {"`$(column)$($ColorJSDefinition)$($ColorBackgroundJSDefinition);"} else {"`$(column[$ConditionHeaderNr])$($ColorJSDefinition)$($ColorBackgroundJSDefinition);"}
            "}"
        }
        $Condition5 = '}'
        $Test = $Condition1 + $Condition3 + $Condition5
        $Options = $Options -Replace ('"columnDefs": ""', $Test)
    }
    return $Options
}
function Out-HtmlView {
    <#
    .SYNOPSIS
    Small function that allows to send output to HTML
 
    .DESCRIPTION
    Small function that allows to send output to HTML. When displaying in HTML it allows data to output to EXCEL, CSV and PDF. It allows sorting, searching and so on.
 
    .PARAMETER Table
    Data you want to display
 
    .PARAMETER Title
    Title of HTML Window
 
    .PARAMETER DefaultSortColumn
    Sort by Column Name
 
    .PARAMETER DefaultSortIndex
    Sort by Column Index
 
    .EXAMPLE
    Get-Process | Select-Object -First 5 | Out-HtmlView
 
    .NOTES
    General notes
    #>

    [alias('Out-GridHtml', 'ohv')]
    [CmdletBinding()]
    param([Parameter(ValueFromPipeline = $true, Mandatory = $true)] $Table,
        [string[]] $PriorityProperties,
        [string] $Title = 'Out-HTMLView',
        [string[]] $DefaultSortColumn,
        [int[]] $DefaultSortIndex,
        [string] $FilePath,
        [switch] $DisablePaging,
        [switch] $PassThru,
        [switch]$Filtering,
        [ValidateSet('Top', 'Bottom', 'Both')][string]$FilteringLocation = 'Bottom',
        [alias('Search')][string]$Find,
        [switch] $InvokeHTMLTags,
        [switch] $DisableNewLine)
    Begin {
        $DataTable = [System.Collections.Generic.List[Object]]::new()
        if ($FilePath -eq '') {$FilePath = Get-FileName -Extension 'html' -Temporary}
    }
    Process {foreach ($T in $Table) {$DataTable.Add($T)}}
    End {
        if ($DataTable.Count -gt 0) {
            $Properties = $DataTable[0].PSObject.Properties.Name
            $RemainingProperties = foreach ($Property in $Properties) {if ($PriorityProperties -notcontains $Property) {$Property}}
            $AllProperties = $PriorityProperties + $RemainingProperties
            $DataTable = $DataTable | Select-Object -Property $AllProperties
        }
        New-HTML -FilePath $FilePath -UseCssLinks -UseJavaScriptLinks -TitleText $Title -ShowHTML {New-HTMLTable -DataTable $DataTable -DefaultSortColumn $DefaultSortColumn -DefaultSortIndex $DefaultSortIndex -DisablePaging:$DisablePaging -Filtering:$Filtering -FilteringLocation $FilteringLocation -Find $Find -InvokeHTMLTags:$InvokeHTMLTags -DisableNewLine:$DisableNewLine}
        if ($PassThru) {$DataTable}
    }
}
Function Save-HTML {
    <#
    .SYNOPSIS
    Short description
 
    .DESCRIPTION
    Long description
 
    .PARAMETER FilePath
    Parameter description
 
    .PARAMETER HTML
    Parameter description
 
    .PARAMETER ShowReport
    Parameter description
 
    .EXAMPLE
    An example
 
    .NOTES
    General notes
    #>

    [CmdletBinding()]
    Param
    ([Parameter(Mandatory = $false)][string]$FilePath,
        [Parameter(Mandatory = $true)][Array] $HTML,
        [Parameter(Mandatory = $false)][switch]$ShowHTML,
        [ValidateSet('Unknown', 'String', 'Unicode', 'Byte', 'BigEndianUnicode', 'UTF8', 'UTF7', 'UTF32', 'Ascii', 'Default', 'Oem', 'BigEndianUTF32')] $Encoding = 'UTF8',
        [bool] $Supress = $true)
    if ([string]::IsNullOrEmpty($FilePath)) {
        $FilePath = Get-FileName -Temporary -Extension 'html'
        Write-Warning "Save-HTML - FilePath parameter $FilePath is empty, using Temporary $FilePath"
    } else {if (Test-Path -LiteralPath $FilePath) {Write-Warning "Save-HTML - Path $FilePath already exists. Report will be overwritten."}}
    Write-Verbose "Save-HTML - Saving HTML to file $FilePath"
    try {
        $HTML | Set-Content -LiteralPath $FilePath -Force -Encoding $Encoding
        if (-not $Supress) {$FilePath}
    } catch {
        $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
        Write-Warning "Save-HTML - Failed with error: $ErrorMessage"
    }
    if ($ShowHTML) {
        try {Invoke-Item -LiteralPath $FilePath -ErrorAction Stop} catch {
            $ErrorMessage = $_.Exception.Message -replace "`n", " " -replace "`r", " "
            Write-Warning "Save-HTML - couldn't open file $FilePath in a browser. Error: $ErrorMessage"
        }
    }
}
$Script:Configuration = [ordered] @{Features = [ordered] @{Default = @{Comment = 'Always Required Default Visual Settings'
            HeaderAlways = @{Css = "$PSScriptRoot\Resources\CSS\default.css"}
        }
        DefaultHeadings = @{Comment = 'Always Required Default Headings'
            HeaderAlways = @{Css = "$PSScriptRoot\Resources\CSS\headings.css"}
        }
        Accordion = @{Comment = 'Accordion'
            HeaderAlways = @{Css = "$PSScriptRoot\Resources\CSS\accordion-1.css"}
        }
        CodeBlocks = @{Comment = 'EnlighterJS CodeBlocks'
            Header = @{CssLink = 'https://evotec.xyz/wp-content/uploads/pswritehtml/enlighterjs.min.css'
                Css = "$PSScriptRoot\Resources\CSS\enlighterjs.min.css"
                JsLink = 'https://evotec.xyz/wp-content/uploads/pswritehtml/enlighterjs.min.js'
                JS = "$PSScriptRoot\Resources\JS\enlighterjs.min.js"
            }
            Footer = @{}
            HeaderAlways = @{}
            FooterAlways = @{JS = "$PSScriptRoot\Resources\JS\enlighterjs-footer.js"}
        }
        Charts = @{Comment = 'Charts JS'
            Header = @{JsLink = 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.3/Chart.bundle.min.js'}
        }
        ChartsApex = @{Comment = 'Apex Charts'
            Header = @{JsLink = 'https://cdn.jsdelivr.net/npm/apexcharts@latest'
                JS = "$PSScriptRoot\Resources\JS\apexcharts.min.js"
            }
            HeaderAlways = @{}
        }
        Jquery = @{Comment = 'Jquery'
            Header = @{JsLink = 'http://code.jquery.com/jquery-3.3.1.min.js'
                Js = "$PSScriptRoot\Resources\JS\jquery-3.3.1.min.js"
            }
        }
        DataTables = @{Comment = 'DataTables'
            HeaderAlways = @{Css = "$PSScriptRoot\Resources\CSS\datatables.css"
                CssNoscript = "$PSScriptRoot\Resources\CSS\datatables.noscript.css"
            }
            Header = @{CssLink = 'https://cdn.datatables.net/v/dt/jq-3.3.1/dt-1.10.18/af-2.3.2/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/b-print-1.5.4/cr-1.5.0/fc-3.2.5/fh-3.1.4/kt-2.5.0/r-2.2.2/rg-1.1.0/rr-1.2.4/sc-1.5.0/sl-1.2.6/datatables.min.css'
                Css = "$PSScriptRoot\Resources\CSS\datatables.min.css"
                JsLink = "https://cdn.datatables.net/v/dt/jq-3.3.1/dt-1.10.18/af-2.3.2/b-1.5.4/b-colvis-1.5.4/b-html5-1.5.4/b-print-1.5.4/cr-1.5.0/fc-3.2.5/fh-3.1.4/kt-2.5.0/r-2.2.2/rg-1.1.0/rr-1.2.4/sc-1.5.0/sl-1.2.6/datatables.min.js"
                JS = "$PSScriptRoot\Resources\JS\datatables.min.js"
            }
        }
        DataTablesPDF = @{Comment = 'DataTables PDF Features'
            Header = @{JsLink = 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/pdfmake.min.js', 'https://cdnjs.cloudflare.com/ajax/libs/pdfmake/0.1.36/vfs_fonts.js'
                Js = "$PSScriptRoot\Resources\JS\pdfmake.min.js", "$PSScriptRoot\Resources\JS\vfs_fonts.min.js"
            }
        }
        DataTablesExcel = @{Comment = 'DataTables Excel Features'
            Header = @{JsLink = 'https://cdnjs.cloudflare.com/ajax/libs/jszip/2.5.0/jszip.min.js'
                JS = "$PSScriptRoot\Resources\JS\jszip.min.js"
            }
        }
        Fonts = @{Comment = 'Default fonts'
            HeaderAlways = @{CssLink = 'https://fonts.googleapis.com/css?family=Roboto|Hammersmith+One|Questrial|Oswald'}
        }
        FontsAwesome = @{Comment = 'Default fonts icons'
            HeaderAlways = @{CssLink = 'https://use.fontawesome.com/releases/v5.7.2/css/all.css'}
        }
        HideSection = @{Comment = 'Hide Section Code'
            HeaderAlways = @{JS = "$PSScriptRoot\Resources\JS\HideSection.js"}
        }
        Tabs = @{Comment = 'Elastic Tabs'
            HeaderAlways = @{Css = "$PSScriptRoot\Resources\CSS\tabs-elastic.css"}
            FooterAlways = @{JS = "$PSScriptRoot\Resources\JS\tabs-elastic.js"}
        }
        TimeLine = @{Comment = 'Timeline Simple'
            HeaderAlways = @{Css = "$PSScriptRoot\Resources\CSS\timeline-simple.css"}
        }
        StatusButtonical = @{Comment = 'Status Buttonical'
            HeaderAlways = @{Css = "$PSScriptRoot\Resources\CSS\status.css"}
        }
        Toast = @{Comment = 'Toasts Looking Messages'
            HeaderAlways = @{Css = "$PSScriptRoot\Resources\CSS\toasts.css"}
        }
        TuiGrid = @{Comment = 'Tui Grid'
            Header = @{Css = "$PSScriptRoot\Resources\CSS\tuigrid.css"
                CssLink = 'https://cdn.jsdelivr.net/npm/tui-grid@3.5.0/dist/tui-grid.css'
            }
        }
    }
}
function Set-Tag {
    [CmdletBinding()]
    param([System.Collections.IDictionary] $HtmlObject)
    $HTML = [System.Text.StringBuilder]::new()
    [void] $HTML.Append("<$($HtmlObject.Tag)")
    foreach ($Property in $HtmlObject.Attributes.Keys) {
        $PropertyValue = $HtmlObject.Attributes[$Property]
        if ($PropertyValue -is [System.Collections.IDictionary]) {
            $OutputSubProperties = foreach ($SubAttributes in $PropertyValue.Keys) {
                $SubPropertyValue = $PropertyValue[$SubAttributes]
                if ($null -ne $SubPropertyValue -and $SubPropertyValue -ne '') {"$($SubAttributes):$($SubPropertyValue)"}
            }
            $MyValue = $OutputSubProperties -join ';'
            if ($MyValue.Trim() -ne '') {[void] $HTML.Append(" $Property=`"$MyValue`"")}
        } else {if ($null -ne $PropertyValue -and $PropertyValue -ne '') {[void] $HTML.Append(" $Property=`"$PropertyValue`"")}}
    }
    if (($null -ne $HtmlObject.Value) -and ($HtmlObject.Value -ne '')) {
        [void] $HTML.Append(">")
        if ($HtmlObject.Value.Count -eq 1) {
            if ($HtmlObject.Value -is [System.Collections.IDictionary]) {
                [string] $NewObject = Set-Tag -HtmlObject ($HtmlObject.Value)
                [void] $HTML.Append($NewObject)
            } else {[void] $HTML.Append([string] $HtmlObject.Value)}
        } else {
            foreach ($Entry in $HtmlObject.Value) {
                if ($Entry -is [System.Collections.IDictionary]) {
                    [string] $NewObject = Set-Tag -HtmlObject ($Entry)
                    [void] $HTML.Append($NewObject)
                } else {[void] $HTML.AppendLine([string] $Entry)}
            }
        }
        [void] $HTML.Append("</$($HtmlObject.Tag)>")
    } else {if ($HtmlObject.SelfClosing) {[void] $HTML.Append("/>")} else {[void] $HTML.Append("></$($HtmlObject.Tag)>")}}
    $HTML.ToString()
}
Export-ModuleMember -Function @('New-HTML', 'New-HTMLAnchor', 'New-HTMLAnchorLink', 'New-HTMLAnchorName', 'New-HTMLChart', 'New-HTMLChartArea', 'New-HTMLChartBar', 'New-HTMLChartDataSet', 'New-HTMLChartLine', 'New-HTMLChartRadial', 'New-HTMLChartSpark', 'New-HTMLCodeBlock', 'New-HTMLContent', 'New-HTMLHeading', 'New-HTMLHorizontalLine', 'New-HTMLImage', 'New-HTMLList', 'New-HTMLListItem', 'New-HTMLLogo', 'New-HTMLMessage', 'New-HTMLPanel', 'New-HTMLResourceCSS', 'New-HTMLResourceJS', 'New-HTMLSpanStyle', 'New-HTMLStatus', 'New-HTMLStatusItem', 'New-HTMLTab', 'New-HTMLTabHead', 'New-HTMLTable', 'New-HTMLTableCondition', 'New-HTMLTag', 'New-HTMLText', 'New-HTMLTimeline', 'New-HTMLTimelineItem', 'New-HTMLToast', 'Out-HtmlView', 'Save-HTML') -Alias @('New-CSS', 'New-HTMLColumn', 'New-JavaScript', 'New-ResourceCSS', 'New-ResourceJS', 'ohv', 'Out-GridHtml')