ReportHTMLCRB.psm1

#region Included Base64 Sources

$Script:SAMPLE_LOGO_SOURCE=@"
data:image/jpeg;base64,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
"@


$Script:CORPORATE_LOGO_SOURCE=@"
data:image/jpeg;base64,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
"@


$Script:ALTERNATE_LOGO_SOURCE=@'
data:image/jpeg;base64,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
'@


#endregion

#region Report Options

Function New-HTMLReportOptions
{
    [CmdletBinding(DefaultParameterSetName='NoSave')]
    param 
    (
        [Parameter(Mandatory=$false,ParameterSetName='NoSave')]
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        [System.Collections.Hashtable]
        $LogoSources,
        [Parameter(Mandatory=$false,ParameterSetName='NoSave')]
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        [System.Collections.Hashtable]
        $ColorSchemes,
        [Parameter(Mandatory=$false,ParameterSetName='NoSave')]
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        $CSSName = "default",
        [Parameter(Mandatory=$false,ParameterSetName='NoSave')]
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        [String]
        $CSSPath,
        [Parameter(Mandatory=$false,ParameterSetName='NoSave')]
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        [String]
        $ScriptPath,
        [Parameter(Mandatory=$false,ParameterSetName='NoSave')]
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        [String]
        $ColorSchemePath,
        [Parameter(Mandatory=$false,ParameterSetName='NoSave')]
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        [String]
        $LogoPath,
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        [String]$SaveOptionsPath,
        [Parameter(Mandatory=$false,ParameterSetName='NoSave')]
        [Parameter(Mandatory=$false,ParameterSetName='Save')]
        [String]
        $ReportPath
    )

    if($LogoSources -eq $null)
    {
        $LogoSources = get-htmllogos -Logopath $LogoPath    
    }
    
    if($ColorSchemes -eq $null)
    {
        $ColorSchemes=Get-HTMLColorSchemes -SchemePath $ColorSchemePath
    }
    if ($LogoSources -eq $null)
    {
        $LogoSources = Get-HTMLLogos -LogoPath $LogoPath
    }
    $ScriptHeaderContent=Get-HTMLJavaScripts -ScriptPath $ScriptPath
    $CSSFiles = Get-HTMLCSS -CSSPath $CSSPath
    get-content ($CSSFiles | ? {$_.name -eq "$CSSName.css"}).fullname | ForEach-Object{$StyleHeaderContent  += "`r`n" + $_  }
    

    $Options=New-Object psobject -Property @{
        Logos=$LogoSources;
        ScriptContent=$ScriptHeaderContent;
        StyleContent=$StyleHeaderContent;
        ColorSchemes=$ColorSchemes;
    }
    set-variable -Name GlobalColorSchemes -Value $ColorSchemes -Scope Global
    if ([string]::IsNullOrEmpty($SaveOptionsPath)) {
        Write-Output $Options
    }

    if(![string]::IsNullOrEmpty($SaveOptionsPath))
    {
        if([String]::IsNullOrEmpty($SaveOptionsPath))
        {
            if([string]::IsNullOrEmpty($PSScriptRoot))
            {
                $SaveOptionsPath=$PSCmdlet.SessionState.Path.CurrentLocation.Path
            }
            else
            {
                $SaveOptionsPath=$PSScriptRoot
            }
        }

        Write-Verbose "Saving Report CSS to $SaveOptionsPath" 
        $StyleHeaderContent|Set-Content -Path (Join-Path $SaveOptionsPath default.css)
        Write-Verbose "Saving Report Color Schemes to $SaveOptionsPath" 
        foreach ($SchemeName in $ColorSchemes.Keys)
        {
            $ColorSchemes[$SchemeName]| ConvertTo-Csv  -NoTypeInformation -Delimiter ';' | % {$_.Replace('"','')} | Out-File (Join-Path $SaveOptionsPath "$schemeName.rcs")
        }
        foreach ($LogoSource in $LogoSources.keys)
        {
            [IO.File]::WriteAllBytes((Join-Path $SaveOptionsPath "$LogoSource.jpg"), [Convert]::FromBase64String($LogoSources[$LogoSource].split(',')[1]))             
        }
        foreach ($CSSFile in $CSSFiles)
        {
            get-content $CSSFile.FullName | set-content (Join-Path $SaveOptionsPath $CSSFile.name)
        }
        
    }
}


Function Get-HTMLLogos
{
    <#
         .SYNOPSIS
            Get Base64 HTML
     
    #>

     [CmdletBinding()]
    param 
    (
        [Parameter(Mandatory=$false)]
        [String]
        $LogoPath
    )
    if([String]::IsNullOrEmpty($LogoPath))
    {
        if([string]::IsNullOrEmpty($PSScriptRoot))
        {
            $LogoPath=$PSCmdlet.SessionState.Path.CurrentLocation.Path
        }
        else
        {
            $LogoPath = $PSScriptRoot 
            #$LogoPath = 'C:\Users\matt.quickenden\Documents\GitHub\AzureFieldNotes\ReportHTML\ReportHTML'
        } 
    }

    $LogoSources = @{}
    $ImageFiles = Get-ChildItem -Path (join-path $LogoPath '\*') -Include *.jpg,*.png,*.bmp
    foreach ($ImageFile in $ImageFiles)
    {
        Write-Verbose "Importing base64 for $($ImageFile.Name) from $ScriptPath"
        $LogoSources.Add($ImageFile.BaseName,'data:image/jpeg;base64,' + [Convert]::ToBase64String((Get-Content $ImageFile.FullName -Encoding Byte)))
    }
    Write-Output $LogoSources

}

Function Get-HTMLCSS
{
    <#
        .SYNOPSIS
            Get's HTML Cascading Style Sheet
        .PARAMETER CSSName
            Name of the CSS
    #>

    [CmdletBinding()]
    param 
    (
        [Parameter(Mandatory=$false)]
        [String]
        $CSSPath,
        [Parameter(Mandatory=$false)]
        [String]
        $CSSName
    )
    if([String]::IsNullOrEmpty($CSSPath))
    {
        if([string]::IsNullOrEmpty($PSScriptRoot))
        {
            $CSSPath=$PSCmdlet.SessionState.Path.CurrentLocation.Path
        }
        else
        {
            $CSSPath=$PSScriptRoot
        }   
    }
    Write-Verbose "Retrieving *.css from $CSSPath"
    $CSSFiles = @((get-childitem $CSSPath -Filter '*.css'))
    if ([string]::IsNullOrEmpty($CSSName))
    {
        Write-Output $CSSFiles
    }
    Else
    {
        get-content ($CSSFiles | ? {$_.basename -eq $CSSName}).fullname
    }
}

Function Get-HTMLJavaScripts
{
<#
    .SYNOPSIS
        Get's Script File from module directory
#>

    [CmdletBinding()]
    param 
    (
        [Parameter(Mandatory=$false)]
        [String]
        $ScriptPath
    )
    if([String]::IsNullOrEmpty($ScriptPath))
    {
        if([string]::IsNullOrEmpty($PSScriptRoot))
        {
            $ScriptPath=$PSCmdlet.SessionState.Path.CurrentLocation.Path
        }
        else
        {
            $ScriptPath=$PSScriptRoot
        } 
    }
    Write-Verbose "Retrieving *.js from $ScriptPath"
    $ScriptFiles = @((get-childitem $ScriptPath -Filter '*.js' ).fullname)
    
    $ScriptHeaders = @()
    foreach ($ScriptFile in $ScriptFiles) {
        Write-Verbose "Generating Script Header from $ScriptFile"
        $ScriptHeaders += "`r`n" + '<script type="text/javascript"> '+ "`r`n" 
        Get-Content $ScriptFile | ForEach-Object{$ScriptHeaders += $_ + "`r`n"  }
        $ScriptHeaders += '</script> '
    }
    
    Write-Output $ScriptHeaders

}

Function Get-HTMLColorSchemes
{
    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$false)]
        [String]$SchemePath
    )
    if([String]::IsNullOrEmpty($SchemePath))
    {
        if([string]::IsNullOrEmpty($PSScriptRoot))
        {
            $SchemePath=$PSCmdlet.SessionState.Path.CurrentLocation.Path
        }
        else
        {
            $SchemePath=$PSScriptRoot
        } 
    }
    $Schemes=@{}
    Write-Verbose "Retrieving *.rcs from $SchemePath"
    $SchemeFiles = @(get-childitem $SchemePath -Filter '*.rcs' )
    foreach ($SchemeFile in $SchemeFiles)
    {
        $SchemeContent=Import-Csv -Delimiter ';' -Path $SchemeFile.FullName
        $Schemes.Add($SchemeFile.BaseName,$SchemeContent)
    }
    $Schemes.add('Generated1',(GenerateRandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated2',(GenerateRandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated3',(GenerateRandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated4',(GenerateRandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated5',(GenerateRandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated6',(GenerateRandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated7',(GenerateRandomColorScheme -NumberOfSchemes 80))
    $Schemes.add('Generated8',(GenerateRandomColorScheme -NumberOfSchemes 80))
    Write-Output $Schemes
}

Function Connect-HTMLToAzure
{

    [CmdletBinding()]
    Param 
    (
        $connectionName = "AzureRunAsConnection"
    )
    Write-Output ("Prepare Azure Connection")
    
    try
    {
        # Get the connection "AzureRunAsConnection "
        $servicePrincipalConnection=Get-AutomationConnection -Name $connectionName         

        #"Logging in to Azure..."
        Add-AzureRmAccount `
            -ServicePrincipal `
            -TenantId $servicePrincipalConnection.TenantId `
            -ApplicationId $servicePrincipalConnection.ApplicationId `
            -CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint | Out-Null 
    }
    catch {
        if (!$servicePrincipalConnection)
        {
            $ErrorMessage = "Connection $connectionName not found."
            throw $ErrorMessage
        } else{
            Write-Error -Message $_.Exception
            throw $_.Exception
        }
    }
}

#endregion

#region Internal Functions

Function Get-Functions 
{
    PAram ($pattern, $path="$pwd\*", [switch]$Recurse = $false) 
      $parser = [System.Management.Automation.PSParser]
      Get-ChildItem (join-Path $path '\*') -Recurse:$Recurse -Include *.ps1, *.psm1 | ForEach {
            $content = [IO.File]::ReadAllText($_.FullName)
            $tokens = $parser::Tokenize($content, [ref] $null)
            $count = $tokens.Count
            $(
                  for($idx=0; $idx -lt $count; $idx += 1) {
                        if($tokens[$idx].Content -eq 'function') {
                              $targetToken = $tokens[$idx+1]
                              New-Object PSObject -Property @{
                                    FileName = $_.FullName
                                    FunctionName = $targetToken.Content 
      
                              Line = $targetToken.StartLine
                              } | Select FunctionName, FileName, Line
                        }
                  }
            ) #| Where {$_.FunctionName -match $pattern}
      }
}

function Get-Parameters 
{
    Param ( $Cmdlet, [switch]$ShowCommon, [switch]$Full ) 
      $command = Get-Command $Cmdlet -ea silentlycontinue 

      # resolve aliases (an alias can point to another alias)
      while ($command.CommandType -eq "Alias") {
            $command = Get-Command ($command.definition)
      }
      if (-not $command) { return }

      foreach ($paramset in $command.ParameterSets){
            $Output = @()
            foreach ($param in $paramset.Parameters) {
                  if ( ! $ShowCommon ) {
                        if ($param.aliases -match "vb|db|ea|wa|ev|wv|ov|ob|wi|cf") { continue }
                  }
                  $process = "" | Select-Object Name, Type, ParameterSet, Aliases, Position, IsMandatory,
                  Pipeline, PipelineByPropertyName
                  $process.Name = $param.Name
                  if ( $param.ParameterType.Name -eq "SwitchParameter" ) {
                        $process.Type = "Boolean"
                  }
                  else {
                        switch -regex ( $param.ParameterType ) {
                              "Nullable``1\[(.+)\]" { $process.Type = $matches[1].Split('.')[-1] + " (nullable)" ; break }
                              default { $process.Type = $param.ParameterType.Name }
                        }
                  }
                  if ( $paramset.name -eq "__AllParameterSets" ) { $process.ParameterSet = "Default" }
                  else { $process.ParameterSet = $paramset.Name }
                  $process.Aliases = $param.aliases
                  if ( $param.Position -lt 0 ) { $process.Position = $null }
                  else { $process.Position = $param.Position }
                  $process.IsMandatory = $param.IsMandatory
                  $process.Pipeline = $param.ValueFromPipeline
                  $process.PipelineByPropertyName = $param.ValueFromPipelineByPropertyName
                  $output += $process
            }
            if ( ! $Full ) { 
                  $Output | Select-Object Name, Type, ParameterSet, IsMandatory, Pipeline
            }
            else { Write-Output $Output }
      }
}

Function grc 
{
<#
.SYNOPSIS
    Random colour Function
#>

    param(
        [int]$Min =0,
        [int]$max =255
    )
    Write-Output ([string](Get-Random -Maximum $max -Minimum $Min) + ',' )
}

Function GenerateRandomColorScheme
{    
<#
.SYNOPSIS
    Generate a colour scheme
.PARAMETER $NumberOfSchemes
#>

    param
    (
        [Parameter(Mandatory=$false)]
        [int]
        $NumberOfSchemes =1,
        $ColorSwing = 8
    )
    
    $Hover = '0.3)'
    $color = '0.6)'
    $border = '1)'
    $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
    
    $ColorScheme = @()
    $i = 0
    while ($i -ne $NumberOfSchemes ) {
        switch ($ColorReference)
        {
            1 {$base = 'rgba('+ (grc -min  $BCMin -max $BCMax) + (grc) + (grc) }
            2 {$base = 'rgba('+ (grc) + (grc -min  $BCMin -max $BCMax) + (grc) }
            3 {$base = 'rgba('+ (grc) + (grc) + (grc -min  $BCMin -max $BCMax) }
        }
        
        $Scheme = '' | select Colour,Background, Hover ,Border
        $Scheme.Background     = $base + $background
        $Scheme.Border         = $base + $border
        $Scheme.Colour         = $base + $color
        $Scheme.Hover         = $base + $Hover
        $ColorScheme += $Scheme
        $i++
    }
    
    Write-Output $ColorScheme
}


#endregion

#Region HTML Functions

Function Get-HTMLOpenPage
{
<#
    .SYNOPSIS
        Get's HTML for the header of the HTML report
    .PARAMETER TitleText
        The title of the report
    .PARAMETER CSSLocation
        Directory containing CSS files. used in conjuction with CSSName
    .PARAMETER CSSName
        If only used with CSSLocation path will search for CSS file with CSSName, otherwise the CSSName can refernce one of the three built in templates.
        This function will Append .css extension
#>


    [CmdletBinding(DefaultParameterSetName='options')]
    param
    (
        [Parameter(Mandatory=$false,ParameterSetName='options')]        
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [String]$TitleText,
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [String]$CSSPath,
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [String]$CSSName = "default",
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [String]$ScriptPath,
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [String]$ColorSchemePath,
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [String]$LogoPath,
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [string]$LeftLogoName = "Sample",
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [string]$RightLogoName = "Alternate",
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [string]$LeftLogoString,
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [string]$RightLogoString,
        [Parameter(Mandatory=$false,ParameterSetName='options')]
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [switch]$HideLogos,
        [Parameter(Mandatory=$false,ParameterSetName='options')]
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [switch]$HideTitle,
        [Parameter(Mandatory=$false,ParameterSetName='options')]
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [switch]$NoScript,
        [Parameter(Mandatory=$false,ParameterSetName='options')]
        [PSobject]$Options,
        [Parameter(Mandatory=$false,ParameterSetName='explicit')]
        [string]$PrimaryColorHex
    )

    if($PSCmdlet.ParameterSetName -eq 'options')
    {
        if($Options -eq $null)
        {
            $Options=New-HTMLReportOptions
        }
    }
    else
    {
        if([String]::IsNullOrEmpty($RightLogoString) -eq $false -or [String]::IsNullOrEmpty($LeftLogoString) -eq $false)
        {
            $LogoSources=@{}
            if([String]::IsNullOrEmpty($RightLogoString) -eq $false)
            {
                $LogoSources.Add($RightLogoName,$RightLogoString)
            }
            if([String]::IsNullOrEmpty($LeftLogoString) -eq $false)
            {
                $LogoSources.Add($LeftLogoName,$LeftLogoString)
            }
        }
        if(!([String]::IsNullOrEmpty($LogoPath))){
            $LogoSources = Get-HTMLLogos -logopath $LogoPath
         
        }
        
        
        $Options=New-HTMLReportOptions -LogoSources $LogoSources -CSSName $CSSName `
            -CSSPath $CSSPath -ScriptPath $ScriptPath -ColorSchemePath $ColorSchemePath
    }  
    if($HideLogos.IsPresent -eq $false)
    {
        $Leftlogo=$Options.Logos[$LeftLogoName]
        $Rightlogo=$Options.Logos[$RightLogoName]
        $LogoContent=@"
            <table><tbody>
            <tr>
                <td class="clientlogo"><img src="$Leftlogo" /></td>
                <td class="MainLogo"><img src="$Rightlogo" /></td>
            </tr>
            </tbody></table>
"@

    }

$HtmlContent=@"
    <!DOCTYPE HTML>
    <!--- This page was autogenerated $CurrentDate By $env:USERNAME -->
    <html>
        <!-- Header -->
        <head>
         
"@

if ($hideTitle.ispresent -eq $false)
{
$HtmlContent += " <Title>$TitleText</Title>"
}

$HtmlContent += @"
            <!-- Styles -->
            $($Options.StyleContent)
            <!-- Scripts -->
            $($Options.ScriptContent)
            <script lang="javascript" src="https://cdn.sheetjs.com/xlsx-0.18.9/package/dist/xlsx.mini.min.js">
            </script>
            <script>
            function exportTableF(clicked_object) {
                /* Create worksheet from HTML DOM TABLE */
                var tt = clicked_object.getAttribute('tabletag');
                var wb = XLSX.utils.table_to_book(document.getElementById(tt));
                var tname = clicked_object.getAttribute('tablename');
                /* Export to file (start a download) */
                XLSX.writeFile(wb, tname + ".xlsx");
            };
            </script>
             
        </head>
        <!-- Body -->
        <body onload="hide();">
"@

if ($hideTitle.ispresent -eq $false)
{
$HtmlContent += @"
 
            <!-- Report Header -->
            $LogoContent
            <div class="pageTitle">$TitleText</div>
            <hr />
            <div class="ReportCreated">Report created on $(Get-Date -format "MMM d, yyyy hh:mm tt")</div>
 
"@

}
    if (!([string]::IsNullOrEmpty($PrimaryColorHex))) 
    {
        if ($PrimaryColorHex.Length -eq 7)
        {
            $HtmlContent = $HtmlContent -replace '#337E94', $PrimaryColorHex
        }
        else
        {
            Write-Warning '$PrimaryColorHex must be 7 characters with hash eg "#337E94"'
        }
    }
    
    Write-Output $HtmlContent
}

Function Get-HTMLClosePage
{
<#
    .SYNOPSIS
        Get's the closing segment for the HTML
        .PARAMETER ClientLogoType
            The type of logo
        .PARAMETER AdditionalContent
             Some additional pish
#>

    [CmdletBinding()]
    param(
        [String]$FooterText
    )
if ($FooterText -eq $null) 
{
    $Report = @"
<hr />
<!-- FOOTER -->
<div class="footer">Copyright &#169; $([DateTime]::Now.Year) Azure Cloud Enablement. All Rights Reserved.</div>
 
<!-- END BODY -->
</body>
</html>
 
"@

}
else
{
$Report = @"
<hr />
<!-- FOOTER -->
<div class="footer">$FooterText</div>
 
<!-- END BODY -->
</body>
</html>
 
"@

}
    Write-Output $Report
}

Function Get-HTMLContentOpen 
{
<#
    .SYNOPSIS
        Creates a section in HTML
        .PARAMETER HeaderText
            The heading for the section
        .PARAMETER IsHidden
            Switch parameter to define if the section can collapse
        .PARAMETER BackgroundShade
            An int for 1 to 6 that defines background shading
#>

    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$false)]
        [string]$HeaderText,
        [Parameter(Mandatory=$false)]
        [switch]$IsHidden,
        [Parameter(Mandatory=$false)]
        [string]$Anchor,
        [Parameter(Mandatory=$false)]
        [validateset(1,2,3,4,5,6)]
        [int]$BackgroundShade
    )

    switch ($BackgroundShade)
    {
        1 { $bgColorCode = "#F8F8F8" }
        2 { $bgColorCode = "#D0D0D0" }
        3 { $bgColorCode = "#A8A8A8" }
        4 { $bgColorCode = "#888888" }
        5 { $bgColorCode = "#585858" }
        6 { $bgColorCode = "#282828" }
        default { $bgColorCode = "#ffffff" }
    }

    if ([String]::IsNullOrEmpty($Anchor)) {
        $InsertAnchor = 'name="' + $Anchor +'"'
    }
$Global:CurrentHeaderName = $HeaderText
if ($IsHidden) {
    $RandomNumber = Get-Random
    $Report = @"
<div class="section">
<div class="header">
    <a name="$($HeaderText)">$($HeaderText)</a> (<a id="show_$RandomNumber" href="#" onclick="show('$RandomNumber');" style="color: #ffffff;">Show</a><a id="hide_$RandomNumber" href="#" onclick="hide('$RandomNumber');" style="color: #ffffff; display:none;">Hide</a>)
</div>
<div class="content" id="$RandomNumber" style="display:none;background-color:$($bgColorCode);">
"@
    
}
else {
    $Report = @"
<div class="section">
<div class="header">
    <a name="$($HeaderText)">$($HeaderText)</a>
</div>
<div class="content" style="background-color:$($bgColorCode);">
"@

}
    Return $Report
}

Function Get-HTMLContentClose
{
<#
    .SYNOPSIS
        Closes an HTML section
#>

    [CmdletBinding()]
    param()
    $Report = @"
    </div>
    </div>
"@

    Return $Report
}

Function Get-HTMLContentTable 
{
<#
    .SYNOPSIS
        Creates an HTML table from an array of objects
        .PARAMETER ArrayOfObjects
            An array of objects
        .PARAMETER Fixed
            fixes the html column width by the number of columns
        .PARAMETER GroupBy
            The column to group the data. make sure this is first in the array
        .PARAMETER Column Totals
            an Array of headers from that exist in the array of objects to be summed up
#>
    
param(
    [Array]$ArrayOfObjects, 
    [String]$GroupBy,
    [Array]$ColumnCounts,
    [Switch]$Fixed,
    [Array]$ColumnAverages,
    [Switch]$NoSortableHeader,
    [Array]$ColumnTotals

)

    $DTInstance = (-join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_})).tolower()

    if ($GroupBy -eq '') {
        $Report = $ArrayOfObjects | ConvertTo-Html -Fragment
        $Report = $Report -replace '<col/>', "" -replace '<colgroup>', "" -replace '</colgroup>', ""
        $Report = $Report -replace "<tr>(.*)<td>Green</td></tr>","<tr class=`"green`">`$+</tr>"
        $Report = $Report -replace "<tr>(.*)<td>Yellow</td></tr>","<tr class=`"yellow`">`$+</tr>"
        $Report = $Report -replace "<tr>(.*)<td>Red</td></tr>","<tr class=`"red`">`$+</tr>"
        $Report = $Report -replace "<tr>(.*)<td>Odd</td></tr>","<tr class=`"odd`">`$+</tr>"
        $Report = $Report -replace "<tr>(.*)<td>Even</td></tr>","<tr class=`"even`">`$+</tr>"
        $Report = $Report -replace "<tr>(.*)<td>None</td></tr>","<tr>`$+</tr>"
        $Report = $Report -replace '<th>RowColor</th>', ''

        if ($Fixed.IsPresent) 
        {    
            $Report = $Report -replace '<table>', '<table class="fixed">' 
        }
        else 
        {    
            if (!($NoSortableHeader)) {    $Report = $Report -replace '<table>', ('<table class="sortable" id="' + $DTInstance + '">') }
        }
    }
    else {
        $NumberOfColumns = ($ArrayOfObjects | Get-Member -MemberType NoteProperty | Select-Object Name).Count
        $Groupings = @()
        $ArrayOfObjects | Select-Object $GroupBy -Unique  | Sort-Object $GroupBy | ForEach-Object { $Groupings += [String]$_.$GroupBy}
        if ($Fixed.IsPresent) {    $Report = '<table class="fixed" id="' + $DTInstance + '">' }
        else { $Report = '<table id="' + $DTInstance + '">' }
        $GroupHeader = $ArrayOfObjects | ConvertTo-Html -Fragment 
        $GroupHeader = $GroupHeader -replace '<col/>', "" -replace '<colgroup>', "" -replace '</colgroup>', "" -replace '<table>', "" -replace '</table>', "" -replace "<td>.+?</td>" -replace "<tr></tr>", ""
        $GroupHeader = $GroupHeader -replace '<th>RowColor</th>', ''
        $Report += $GroupHeader
        foreach ($Group in $Groupings) {
            $Report += "<tr class=`"headercol`"><td colspan=`"$NumberOfColumns`" class=`"groupby`">$Group</td></tr>"
            $GroupBody = $ArrayOfObjects | Where-Object { [String]$($_.$GroupBy) -eq $Group } | Select-Object * -ExcludeProperty $GroupBy | ConvertTo-Html -Fragment
            $GroupBody = $GroupBody -replace '<col/>', "" -replace '<colgroup>', "" -replace '</colgroup>', "" -replace '<table>', "" -replace '</table>', "" -replace "<th>.+?</th>" -replace "<tr></tr>", "" -replace '<tr><td>', "<tr><td></td><td>"
            $GroupBody = $GroupBody -replace "<tr>(.*)<td>Green</td></tr>","<tr class=`"green`">`$+</tr>"
            $GroupBody = $GroupBody -replace "<tr>(.*)<td>Yellow</td></tr>","<tr class=`"yellow`">`$+</tr>"
            $GroupBody = $GroupBody -replace "<tr>(.*)<td>Red</td></tr>","<tr class=`"red`">`$+</tr>"
            $GroupBody = $GroupBody -replace "<tr>(.*)<td>Odd</td></tr>","<tr class=`"odd`">`$+</tr>"
            $GroupBody = $GroupBody -replace "<tr>(.*)<td>Even</td></tr>","<tr class=`"even`">`$+</tr>"
            $GroupBody = $GroupBody -replace "<tr>(.*)<td>None</td></tr>","<tr>`$+</tr>"
            $Report += $GroupBody
        }
    
    }
    $Report = $Report -replace 'URL01NEW', '<a target="_blank" href="'
    $Report = $Report -replace 'URL01', '<a href="'
    $Report = $Report -replace 'URL02', '">'
    $Report = $Report -replace 'URL03', '</a>'
    
    if ($Report -like "*<tr>*" -and $report -like "*odd*" -and $report -like "*even*") {
            $Report = $Report -replace "<tr>",'<tr class="header">'
    }
    
    if ($ColumnTotals.count -gt 0 -or $ColumnAverages.count -gt 0 -or $ColumnCounts.count -gt 0 ) {
        $Report = $Report -replace "</table>",""
        $TableFooter = $ArrayOfObjects | ConvertTo-Html -Fragment 
        $TableFooter = $TableFooter -replace '<col/>', "" -replace '<colgroup>', "" -replace '</colgroup>', "" -replace '<table>', "" -replace '</table>', "" -replace "<td>.+?</td>" -replace "<tr></tr>", ""
        $TableFooter = $TableFooter -replace '<th>RowColor</th>', ''
        #$ColumnTotal
        foreach ($ColumnTotal in $ColumnTotals) 
        {
            $TableFooter = $TableFooter -replace $ColumnTotal,("sum:" + ($arrayofobjects | measure $ColumnTotal -Sum ).sum)
        }
        #ColumnAverage
        foreach ($ColumnAverage in $ColumnAverages) 
        {
            $TableFooter = $TableFooter -replace $ColumnAverage,("avg:" +($arrayofobjects | measure $ColumnAverage -Average ).average)
        }
        #ColumnCount
        foreach ($ColumnCount in $ColumnCounts)
        {
            $TableFooter = $TableFooter -replace $ColumnCount,("count:"+ ($arrayofobjects | measure $ColumnCount).count)
        }
        #Cleanup
        foreach ($Column in ($ArrayOfObjects | Get-Member ))
        {
            $TableFooter = $TableFooter -replace ("<th>" + $Column.Name + "</th>"), '<td></td>'    
        }    
        
        $TableFooter = $TableFooter -replace '<th>', '<td class="totalrow">' -replace "</th>", '</td>'
        $TableFooter = $TableFooter -replace '<tr>', '<tr class="totalrow">' 
        $Report += "<tfoot>"
        $Report += $TableFooter
        $Report += "</tfoot>"
    }
        
    
    $Report += "</table>" 
    $Report += '<button style="margin-right: 10px; margin-top: 2px; position: sticky; left: 95%;" class="button" id="' + $DTInstance + '_button" tabletag="' + $DTInstance + '" tablename="' + $Global:CurrentHeaderName + '" onClick="exportTableF(this)">Export</button>'
<# $Report += @'
    <script>
    $('.headercol').click(function(){
        $(this).find('span').text(function(_, value){return value=='-'?'+':'-'});
         $(this).nextUntil('tr.headercol').slideToggle(100, function(){
         });
     });
     </script>
'@
#>

    return $Report
}

Function Get-HTMLContentTableAdvanced
{
<#
        .SYNOPSIS
            Code borrowed from https://www.powershellgallery.com/packages/EnhancedHTML2
             
 
#>

    param(
        [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
        [Array]$ArrayOfObjects
    )    
        
            $out = ''
            $out += "<table>"
        
          foreach ($object in $ArrayOfObjects) {
            $datarow = ''
            $headerrow = ''

            $properties = $object | Get-Member -MemberType Properties | Select -ExpandProperty Name
            
            foreach ($prop in $properties) {
            #$prop = $properties[0]
                $name = $null
                $value = $null
                
                if ($prop -is [string]) {
                    $name = $Prop
                    $value = $object.($prop)
                } else {
                    Write-Warning "Unhandled property $prop"
                }

               $headerrow += "<th>$name</th>"
               $datarow += "<td>$value</td>"
            }
            
            if (-not $wrote_first_line ) {
                $out += "<tr>$headerrow</tr><tbody>"
                $wrote_first_line = $true
            }
                $out += "<tr>$datarow</tr>"
            }
    
      $out += "</table>"
   
   
   return $out 
}

Function Get-HTMLContentDataTable 
{
<#
    .SYNOPSIS
        Creates an HTML 5 Data table from an array of objects
        .PARAMETER ArrayOfObjects
            An array of objects
        .PARAMETER Paging
        .PARAMETER PagingOptions
        .PARAMETER Ordering
        .PARAMETER Info
        .PARAMETER HideFooter
         
#>
    
param
(
    [Parameter(Mandatory=$True,ValueFromPipeline=$True)]
    [Array]$ArrayOfObjects,
    [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
    [switch]$DisablePaging,
    [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
    [string]$PagingOptions = '15,25, 50, 100,',
    [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
    [switch]$DisableOrdering,
    [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
    [switch]$DisableInfo,
    [Parameter(Mandatory=$false,ValueFromPipeline=$false)]
    [switch]$HideFooter

)
    if ($DisablePaging -eq $true)    {$Paging = 'false'}     else {$Paging = 'true'}  
    if ($DisableOrdering -eq $true) {$Ordering = 'false'}     else {$Ordering = 'true'}  
    if ($DisableInfo -eq $true)     {$Info = 'false'}         else {$Info = 'true'}  
    
    $DTInstance = (-join ((65..90) + (97..122) | Get-Random -Count 8 | % {[char]$_})).tolower()

    $TableHeader = @'
<script>
 $(document).ready(function() {
     $('#
'@


    $TableHeader += $DTInstance
    $TableHeader += @"
').DataTable({
        "paging": $($Paging),
        "pagingType": "full_numbers",
        "lengthMenu": [[$PagingOptions -1], [$PagingOptions "All"]],
        "ordering": $($Ordering),
        "info": $($Info),
         "columns": [
"@


    $ArraryHeader = $ArrayOfObjects | ConvertTo-Html -Fragment 
    $HeadersText =  ($ArraryHeader[2] -replace '<tr>',''  -replace '<th>','' -replace '</tr>','')
    $ColumnHeaders = ($HeadersText.substring(0,$HeadersText.Length-5))  -split '</th>'

    foreach ($ColumnHeader in $ColumnHeaders ) 
    {
       $TableHeader += '{ "data": "' + $ColumnHeader + '" },'
    }
    $TableHeader += @'
]
     });
 } );
</script>
'@

    $TableHeader = $TableHeader.Replace(',]',']')

    $NumberOfColumns = ($ArrayOfObjects | Get-Member -MemberType NoteProperty  | Select-Object Name).Count

    $Report = $ArrayOfObjects | ConvertTo-Html -Fragment 
    $Report = $Report -replace '<col/>', "" -replace '<colgroup>', "" -replace '</colgroup>', ""
    $Report = $Report -replace '<table>', ('<table id="' + $DTInstance + '" class="display compact"><thead onContextMenu="showTableFilter(this, event)" tabletag="' + $DTInstance + '">')
    $Report = $Report -replace '</th></tr>','</th></tr></thead><tbody>'
    $Report = $Report -replace "</table>","LoadFooterHere</tbody>"  
    if ($HideFooter -eq $true) 
    {
        $Report = $Report -replace "LoadFooterHere",""
    }
    else
    {
        $Footer = '<tfoot><tr>'
        foreach ($Header in $ColumnHeaders){
            $Footer += '<th>' + $Header + '</th>' 
        }
        $Footer += '</tr></tfoot>'
        $Report = $Report -replace "LoadFooterHere",$Footer
    }        
        
    $Report = $Report -replace 'URL01NEW', '<a target="_blank" href="'
    $Report = $Report -replace 'URL01', '<a href="'
    $Report = $Report -replace 'URL02', '">'
    $Report = $Report -replace 'URL03', '</a>'
    
    $Report += "</table>"
    $Report += '<button style="margin-right: 10px; margin-top: 10px; position: sticky; left: 95%;" class="button" id="' + $DTInstance + '_button" tabletag="' + $DTInstance + '" tablename="' + $Global:CurrentHeaderName + '" onClick="exportTableF(this)">Export Current View</button>'
    $Report += '<ul id="' + $DTInstance + '_menu" class="container__menu container__menu--hidden" tabletag="' + $DTInstance + '" data-menucreated="false"></ul>'
    $Report += @'
    <script>
    $('.headercol').click(function(){
        $(this).find('span').text(function(_, value){return value=='-'?'+':'-'});
         $(this).nextUntil('tr.headercol').slideToggle(100, function(){
         });
     });
     </script>
'@

    $Report += @"
    <script>
    function showTableFilter(clicked_object, e){
            const tt = clicked_object.getAttribute('tabletag');
            const menu = document.getElementById(tt+'_menu');
            const table = document.getElementById(tt);
            const headers = [].slice.call(table.querySelectorAll('th'));
            const cells = [].slice.call(table.querySelectorAll('th, td'));
            const numColumns = headers.length;
 
            const thead = table.querySelector('thead');
             
                e.preventDefault();
 
                const rect = thead.getBoundingClientRect();
                const x = e.clientX - rect.left;
                const y = rect.top;
 
                menu.style.top = `${y}px`;
                menu.style.left = `${x}px`;
                menu.classList.toggle('container__menu--hidden');
 
                 
 
            // Hide the menu when clicking outside of it
            const documentClickHandler = function (e) {
                const isClickedOutside = !menu.contains(e.target);
                if (isClickedOutside) {
                    menu.classList.add('container__menu--hidden');
                    document.removeEventListener('click', documentClickHandler);
                }
            };
                            document.addEventListener('click', documentClickHandler);
            const showColumn = function (index) {
                cells
                    .filter(function (cell) {
                        return cell.getAttribute('data-column-index') === `${index}`;
                    })
                    .forEach(function (cell) {
                        cell.style.display = '';
                        cell.setAttribute('data-shown', 'true');
                    });
 
                menu.querySelectorAll(`[type="checkbox"][disabled]`).forEach(function (checkbox) {
                    checkbox.removeAttribute('disabled');
                });
            };
 
            const hideColumn = function (index) {
                cells
                    .filter(function (cell) {
                        return cell.getAttribute('data-column-index') === `${index}`;
                    })
                    .forEach(function (cell) {
                        cell.style.display = 'none';
                        cell.setAttribute('data-shown', 'false');
                    });
                // How many columns are hidden
                const numHiddenCols = headers.filter(function (th) {
                    return th.getAttribute('data-shown') === 'false';
                }).length;
                if (numHiddenCols === numColumns - 1) {
                    // There's only one column which isn't hidden yet
                    // We don't allow user to hide it
                    const shownColumnIndex = thead
                        .querySelector('[data-shown="true"]')
                        .getAttribute('data-column-index');
 
                    const checkbox = menu.querySelector(
                        `[type="checkbox"][data-column-index="`${shownColumnIndex}"]`
                    );
                    checkbox.setAttribute('disabled', 'true');
                }
            };
 
            cells.forEach(function (cell, index) {
                cell.setAttribute('data-column-index', index % numColumns);
                cell.setAttribute('data-shown', 'true');
            });
            const mcreated = clicked_object.getAttribute('data-menucreated');
                            if(mcreated == "true"){
             
            }else{
            headers.forEach(function (th, index) {
                // Build the menu item
                const li = document.createElement('li');
                const label = document.createElement('label');
                const checkbox = document.createElement('input');
                checkbox.setAttribute('type', 'checkbox');
                checkbox.setAttribute('checked', 'true');
                checkbox.setAttribute('data-column-index', index);
                checkbox.style.marginRight = '.25rem';
 
                const text = document.createTextNode(th.textContent);
 
                label.appendChild(checkbox);
                label.appendChild(text);
                label.style.display = 'flex';
                label.style.alignItems = 'center';
                li.appendChild(label);
                menu.appendChild(li);
                                 
                // Handle the event
                checkbox.addEventListener('change', function (e) {
                    e.target.checked ? showColumn(index) : hideColumn(index);
                    menu.classList.add('container__menu--hidden');
                });
            })
            clicked_object.setAttribute("data-menucreated","true");
            };
        };
    </script>
"@

    return ($TableHeader + $Report)
}

Function Get-HTMLContentText
{
<#
    .SYNOPSIS
        Creates an HTML entry with heading and detail
        .PARAMETER Heading
            The type of logo
        .PARAMETER Detail
             Some additional pish
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$false)]
        [String]
        $Heading,
        [Parameter(Mandatory=$false)]
        [String]
        $Detail
    )

    $Report = @"
<table><tbody>
    <tr>
    <th class="content">$Heading</th>
    <td class="content">$($Detail)</td>
    </tr>
</tbody></table>
"@

    $Report = $Report -replace 'URL01NEW', '<a target="_blank" href="'
    $Report = $Report -replace 'URL01', '<a href="'
    $Report = $Report -replace 'URL02', '">'
    $Report = $Report -replace 'URL03', '</a>'
    Return $Report
}

Function Set-TableRowColor 
{
<#
    .SYNOPSIS
        adds a row colour field to the array of object for processing with htmltable
        .PARAMETER ArrayOfObjects
            The type of logo
        .PARAMETER Green
             Some additional pish
        .PARAMETER Yellow
             Some additional pish
        .PARAMETER Red
            use $this and an expression to measure the value
        .PARAMETER Alertnating
            a switch the will define Odd and Even Rows in the rowcolor column
#>

    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$false)]
        [Object[]]$ArrayOfObjects, 
        [Parameter(Mandatory=$false)]
        [string]$Green = '$this -eq $false', 
        [Parameter(Mandatory=$false)]
        [string]$Yellow = '$this -eq $false', 
        [Parameter(Mandatory=$false)]
        [string]$Red = '$this -eq $false',
        [Parameter(Mandatory=$false)]
        [switch]$Alternating
    )
    if ($Alternating) {
        $ColoredArray = $ArrayOfObjects | Add-Member -MemberType ScriptProperty -Name RowColor -Value {
        if ((([array]::indexOf($ArrayOfObjects,$this)) % 2) -eq 0) {'Odd'}
        if ((([array]::indexOf($ArrayOfObjects,$this)) % 2) -eq 1) {'Even'}
        } -PassThru -Force | Select-Object *
    } else {
        $ColoredArray = $ArrayOfObjects | Add-Member -MemberType ScriptProperty -Name RowColor -Value {
            if (Invoke-Expression $Green) {'Green'} 
            elseif (Invoke-Expression $Red) {'Red'} 
            elseif (Invoke-Expression $Yellow) {'Yellow'} 
            else {'None'}
            } -PassThru -Force | Select-Object *
    }
    
    return $ColoredArray
}

Function Get-HTMLColumn1of2
{
<#
    .SYNOPSIS
        adds a row colour field to the array of object for processing with htmltable
        .PARAMETER PieChartObject
            This is a custom object with Pie chart properties, Create-HTMLPieChartObject
        .PARAMETER PieChartData
            Required an array with the headings Name and Count. Using Powershell Group-object on an array
             
#>

    [CmdletBinding()]
    param()
    $report = '<div class="first column">'
    return $report
}

Function Get-HTMLColumn2of2
{
<#
    .SYNOPSIS
        adds a row colour field to the array of object for processing with htmltable
        .PARAMETER PieChartObject
            This is a custom object with Pie chart properties, Create-HTMLPieChartObject
        .PARAMETER PieChartData
            Required an array with the headings Name and Count. Using Powershell Group-object on an array
             
#>

    [CmdletBinding()]
    param()
    $report = '<div class="second column">'
    return $report
}

Function Get-HTMLColumnClose
{
<#
    .SYNOPSIS
        Closing Div Tag
#>

    [CmdletBinding()]
    param()
    $report = '</div>'
    return $report
}

Function Get-HTMLColumnOpen
{
<#
    .SYNOPSIS
        Dynamic Column Creation
        .PARAMETER NumberOf
            This is a current column number
        .PARAMETER ColumnTotal
            Total Number of columns
             
#>

    [CmdletBinding()]
    param
    (
        [Parameter(Mandatory=$true)]
        [int]$ColumnNumber,
        [Parameter(Mandatory=$true)]
        [int]$ColumnCount
    )
    
    $ColumnItem = [string]$ColumnNumber + "of" + [string]$ColumnCount
    Write-Verbose $ColumnItem 
    $ColumnItem = $ColumnItem.replace('1','one').replace('2','two').replace('3','three').replace('4','four').replace('5','five').replace('6','six')
    Write-Verbose $ColumnItem 
    $report = '<div class="' + $ColumnItem + ' column">'
    return $report
}

Function Get-HTMLAnchorLink 
{
<#
    .SYNOPSIS
        creates Hyperlink for an Anchor
        .PARAMETER AnchorName
            The Actual name of the Anchor (Hidden)
        .PARAMETER AnchorText
            The HyperLink text. Will default to $AnchorNname if not specified
#>

    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$false)]
        [String]
        $AnchorName,
        [Parameter(Mandatory=$true)]
        [String]
        $AnchorText
    )
    if ($AnchorText -eq $null -or $AnchorText -eq '') {$AnchorText=$AnchorName}
    $report = '<a class="alink" href="#' + $AnchorName + '">' +  $AnchorText +'</a>'

    Write-Output $report
}

Function Get-HTMLAnchor 
{
<#
    .SYNOPSIS
        creates an Anchor
        .PARAMETER AnchorName
            The Actual Anchor
#>

    [CmdletBinding()]
    Param
    (
        [Parameter(Mandatory=$true)]
        [String]
        $AnchorName
    )
    
    $Anchor = '<a name="' + $AnchorName + '"></a>'
    Write-Output $Anchor
}

Function Get-HTMLTabHeader 
{
    [CmdletBinding()]
    Param 
    (
        [Parameter(Mandatory=$true)]
        [Array]
        $TabNames
    )

    $TabHeader = @()
    $TabHeader += '<ul class="tab">'
    $FirstTab = $true
      Foreach ($TabName in $TabNames) {
        if ($FirstTab) 
        {
            $TabHeader += ' <li><a href="javascript:void(0)" class="tablinks" onclick="openTab(event, ''' + $TabName + ''')" id="defaultOpen">' + $TabName + '</a></li>'
            $FirstTab = $false
        }
        else
        {
            $TabHeader += ' <li><a href="javascript:void(0)" class="tablinks" onclick="openTab(event, ''' + $TabName + ''')">' + $TabName + '</a></li>'
        }
        
      }
    $TabHeader += '</ul>'
    Set-Variable -Scope global -Name TabHeaderCreated -Value $true
    Write-output $TabHeader 
}

Function Get-HTMLTabContentOpen 
{
    [CmdletBinding()]
    Param 
    (
        [Parameter(Mandatory=$true)]
        [String]
        $TabName,
        [Parameter(Mandatory=$true)]
        [String]
        $TabHeading
    )
    $TabContent  = @()
    $TabContent  += '<div id="' + $TabName +'" class="tabcontent">'

        $TabContent  += "<h7>$TabHeading</h7>"
     write-output $TabContent 
}

Function Get-HTMLTabContentClose
{
    $tabclose = @()
    $tabclose += "</p>"
    $tabclose += '</div>'
    $tabclose += @"
<script>
// Get the element with id="defaultOpen" and click on it
document.getElementById("defaultOpen").click();
</script>
"@

    write-output $tabclose 
}

Function Get-HTMLCodeBlock
{
    [CmdletBinding()]
    Param 
    (
        [Parameter(Mandatory=$true)]
        [String]
        $Code,
        [Parameter(Mandatory=$false)]
        [String]
        $Style = 'PowerShell'
    )
    $CodeBlock = @()
    switch ($Style) {
        'PowerShell' 
        {
            $CodeBlock += '<pre class="PowerShell">'
        }
        'othercodestyleneedsACSSStyle' 
        {
            $CodeBlock += '<pre class="PowerShell">'
        }
        default 
        {
            $CodeBlock += '<pre>'
        }
    }
    
    $CodeBlock  += $Code
    $CodeBlock  += '</pre>'
    [string]$CodeBlock = $CodeBlock
    Write-Output $CodeBlock
}

function Get-HTMLSpan 
{
    Param (
        $block, 
        $tokenColor
    )
#
# Original Author: Lee Holmes, http://www.leeholmes.com/blog/MorePowerShellSyntaxHighlighting.aspx
#
# Modified by: Helge Klein, http://blogs.sepago.de/helge/
#

    if (($tokenColor -eq 'NewLine') -or ($tokenColor -eq 'LineContinuation'))
    {
        if($tokenColor -eq 'LineContinuation')
        {
            $null = $codeBuilder.Append('`')
        }

        $null = $codeBuilder.Append("<br />`r`n")
    }
    else
    {
        $block = [System.Web.HttpUtility]::HtmlEncode($block)
        if (-not $block.Trim())
        {
            $block = $block.Replace(' ', '&nbsp;')
        }

        $htmlColor = $tokenColours[$tokenColor].ToString().Replace('#FF', '#')

        if($tokenColor -eq 'String')
        {
            $lines = $block -split "`r`n"
            $block = ""

            $multipleLines = $false
            foreach($line in $lines)
            {
                if($multipleLines)
                {
                    $block += "<BR />`r`n"
                }

                $newText = $line.TrimStart()
                $newText = "&nbsp;" * ($line.Length - $newText.Length) + $newText
                $block += $newText
                $multipleLines = $true
            }
        }

        $null = $codeBuilder.Append("<span style='color:$htmlColor'>$block</span>")
    }
}

Function Get-HTMLPowerShellSyntax 
{
    [CmdletBinding()]
    Param (
        $PowerShellFilePath
    )
#
# Original Author: Lee Holmes, http://www.leeholmes.com/blog/MorePowerShellSyntaxHighlighting.aspx
#
# Modified by: Helge Klein, http://blogs.sepago.de/helge/
#

#
# Syntax highlights a PowerShell script.
#
# Usage: Supply the script to syntax hightligh as first and only parameter
#
# Output: Copy of original script with extension ".html"
#
# Example: .\Highlight-Syntax.ps1 .\Get-AppVPackageDependencies.ps1
#
# Version history:
#
# 1.1:
#
# - Loading the required assembly System.Web now. This was missing earlier.
#
# 1.0: Initial version
#


$path = $PowerShellFilePath

# Load required assemblies
[void] [System.Reflection.Assembly]::Load("System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")

$tokenColours = @{
    'Attribute' = '#FFADD8E6'
    'Command' = '#FF0000FF'
    'CommandArgument' = '#FF8A2BE2'
    'CommandParameter' = '#FF000080'
    'Comment' = '#FF006400'
    'GroupEnd' = '#FF000000'
    'GroupStart' = '#FF000000'
    'Keyword' = '#FF00008B'
    'LineContinuation' = '#FF000000'
    'LoopLabel' = '#FF00008B'
    'Member' = '#FF000000'
    'NewLine' = '#FF000000'
    'Number' = '#FF800080'
    'Operator' = '#FFA9A9A9'
    'Position' = '#FF000000'
    'StatementSeparator' = '#FF000000'
    'String' = '#FF8B0000'
    'Type' = '#FF008080'
    'Unknown' = '#FF000000'
    'Variable' = '#FFFF4500'
}

# Generate an HTML span and append it to HTML string builder
$currentLine = 1

    $text = $null

    if($path)
    {
        $text = (Get-Content $path) -join "`r`n"
    }
    else
    {
        Write-Error 'Please supply the path to the PowerShell script to syntax highlight as first (and only) parameter.'
        return
    }

    trap { break }

    # Do syntax parsing.
    $errors = $null
    $tokens = [system.management.automation.psparser]::Tokenize($Text, [ref] $errors)

    # Initialize HTML builder.
    $codeBuilder = new-object system.text.stringbuilder

    # Iterate over the tokens and set the colors appropriately.
    $position = 0
    foreach ($token in $tokens)
    {
        if ($position -lt $token.Start)
        {
            $block = $text.Substring($position, ($token.Start - $position))
            $tokenColor = 'Unknown'
            Get-HtmlSpan $block $tokenColor
        }

        $block = $text.Substring($token.Start, $token.Length)
        $tokenColor = $token.Type.ToString()
        Get-HtmlSpan $block $tokenColor

        $position = $token.Start + $token.Length
    }

    # Build the entire syntax-highlighted script
    $code = $codeBuilder.ToString()
    
    # Replace tabs with three blanks
    $code    = $code -replace "\t"," "
    
    if ($WriteToPath) 
    {
        # Write the HTML to a file
        $code | set-content -path "$path.html"
    }
    else
    {
        write-output $code    
    }
}

Function Get-HTMLHeading 
{
    Param
    (
        [string]$headingText,
        [int]$headerSize
    )
    
    $headerString = "<h$headerSize>$headingText</h$headerSize>"
    return $headerString
}

#endregion

#Region Chart JS Functions

Function Get-HTMLBarChartObject
{
<#
    .SYNOPSIS
        create a Bar chart object for use with Get-HTMLBarChart
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        $ColorScheme
    )
    

    $ChartSize = New-Object PSObject -Property @{`
        Width = 500
        Height = 400
    }
    
    $DataDefinition = New-Object PSObject -Property @{`
        DataSetName = "Data"
        AxisXTitle = ""
        AxisYTitle = ""
        DataNameColumnName = "name"
        DataValueColumnName = "count"
        
    }
    
    if ($ColorScheme -eq "Generated") {$thisColorScheme = 'Generated' + [string](Get-Random -Minimum 1 -Maximum 8)}
    elseif ($ColorScheme -eq "Random") {$thisColorScheme = 'Random' }
    else {$thisColorScheme = 'ColorScheme1'}

    $ChartStyle = New-Object PSObject -Property @{`
        ChartType = "bar"
        ColorSchemeName = "$thisColorScheme"
        Showlabels= $true
        borderWidth = "1"
        responsive = 'false'
        legendPosition = 'bottom'
    
    }
    
    $ChartObject = New-Object PSObject -Property @{`
        ObjectName = -join ((65..90) + (97..122) | Get-Random -Count 12 | ForEach-Object {[char]$_})
        Title = ""
        Size = $ChartSize
        DataDefinition = $DataDefinition
        ChartStyle = $ChartStyle
    }
    
    return $ChartObject
}

Function Get-HTMLBarChart
{
<#
    .SYNOPSIS
     
#>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)]
        $ChartObject,
        [Parameter(Mandatory=$true)]
        [Array]
        $DataSet,
        [Parameter(Mandatory=$false)]
        $Options
    )

    $DataCount = $DataSet.Count
    Write-Verbose "Data Set counnt is $DataCount"
    if ($ChartObject.ChartStyle.ColorSchemeName -ne 'Random')
    {
        if ($Options -eq $null) {
            #Write-Verbose "Default Colour Schemes selected, selecting $($ChartObject.ChartStyle.ColorSchemeName)"
            #$ColorSchemes = Get-HTMLColorSchemes
            $ChartColorScheme = $GlobalColorSchemes.($ChartObject.ChartStyle.ColorSchemeName) | select -First $DataCount
        } else {
            Write-Verbose "Options Colour Schemes selected, selecting $($ChartObject.ChartStyle.ColorSchemeName)"
            $ChartColorScheme = $Options.ColorSchemes.($ChartObject.ChartStyle.ColorSchemeName) | select -First $DataCount
        }
        if ($ChartColorScheme.Count -lt $DataCount) {
            Write-Warning ("Colorscheme " +  $ChartObject.ChartStyle.ColorSchemeName + " only has " + $ChartColorScheme.Count + " schemes, you have $DataCount Records. Generating one for you" )
            $ChartColorScheme = GenerateRandomColorScheme -numberofschemes $DataCount
        }
    }
    else
    {
        $ChartColorScheme = GenerateRandomColorScheme -numberofschemes $DataCount
    }
        
    $ofs = ','
    $CJSHeader  = @()
    $CJSHeader += '<canvas id="' + $ChartObject.ObjectName + '" width="'+ $ChartObject.Size.Width + '" height="' + $ChartObject.Size.Height +'"></canvas>'
    $CJSHeader += '<script>'
    $CJSHeader += 'var ctx = document.getElementById("' + $ChartObject.ObjectName + '");'
    $CJSHeader += 'var ' + $ChartObject.ObjectName + ' = new Chart(ctx, {'
    $CJSHeader += " type: '$($ChartObject.ChartStyle.ChartType)',"
    
    
    $CJSData = @()
    $CJSData = " data: {"+ "`n"
    if ($ChartObject.ChartStyle.Showlabels) {
        $ofs ='","'
        $CJSData += ' labels: ["' +"$($DataSet.($ChartObject.DataDefinition.DataNameColumnName))" + '"],' + "`n"
    }
    
    $CJSData += " datasets: [{" + "`n"
    $CJSData += " label: '$($chartobject.DataDefinition.datasetname)'," + "`n"
    $ofs =","
    $CJSData += " data: [" + "$($DataSet | % {$_.($ChartObject.DataDefinition.DataValueColumnName)})" +"]," + "`n"
    $ofs ="','"
    $CJSData += " backgroundColor: ['" + "$($ChartColorScheme.Background)" + "']," + "`n"
    $CJSData += " borderColor: ['" + "$($ChartColorScheme.border)" + "']," + "`n"
    $CJSData += " hoverBackgroundColor: ['" + "$($ChartColorScheme.border)" + "']," + "`n"
    $CJSData += " borderWidth: $($ChartObject.ChartStyle.borderWidth)" + "`n"
    $CJSData += " }]"+ "`n"
    $CJSData += " },"
    $ofs =""
        
    $CJSOptions = @()
    $cjsOptions += ' options: {'
    #responsive
    $cjsOptions += " responsive: $($ChartObject.ChartStyle.responsive),"
    #legend
    $cjsOptions += " legend: {
                position: '$($ChartObject.ChartStyle.legendposition)',
            },"

    #title
    if ($ChartObject.Title -ne '') {
        $cjsOptions += " title: {
                display: true,
                text: '$($ChartObject.Title)'
            },"

    }
    #scale & Labels
    $XAxisLabel = $ChartObject.DataDefinition.AxisXTitle
    if ([string]::IsNullOrEmpty($XAxisLabel))
    {
        $displayXAxisLabel = 'false'
    }
    else 
    {
        $displayXAxisLabel = 'true'
    }

    $YAxisLabel = $ChartObject.DataDefinition.AxisYTitle
    if ([string]::IsNullOrEmpty($YAxisLabel))
    {
        $displayYAxisLabel = 'false'
    }
    else 
    {
        $displayYAxisLabel = 'true'
    }

    $CJSOptions += "scales: {
                        xAxes: [{
                            display: $displayXAxisLabel,
                            scaleLabel: {
                                display: $displayXAxisLabel,
                                labelString: '$XAxisLabel'
                            }
                        }],
                        yAxes: [{
                            display: $displayYAxisLabel,
                            scaleLabel: {
                                display: $displayYAxisLabel,
                                labelString: '$YAxisLabel'
                            },
                            ticks: {
                                beginAtZero:true
                            }
                        }]
                    },
     
    "


    $cjsOptions += " }" +"`n"
    $CJSOptions += "}); "
        
    $CJSFooter = " </script>"
    


    $CJS  = @()
    $CJS += $CJSHeader
    $CJS += $CJSData
    $CJS += $CJSOptions 
    $CJS += $CJSFooter

    write-output $CJS
}

Function Get-HTMLPieChartObject
{
<#
    .SYNOPSIS
        create a Bar chart object for use with Get-HTMLBarChart
#>

    [CmdletBinding()]
    param(
        [ValidateSet("pie","doughnut")]
        [String]
        $ChartType = 'pie',
        [Parameter(Mandatory=$false)]
        $ColorScheme
    )

    $ChartSize = New-Object PSObject -Property @{`
        Width = 500
        Height = 400
    }
    
    $DataDefinition = New-Object PSObject -Property @{`
        DataSetName = "Data"
        DataNameColumnName = "name"
        DataValueColumnName = "count"
    }
    
    if ($ColorScheme -eq "Generated") {$thisColorScheme = 'Generated' + [string](Get-Random -Minimum 1 -Maximum 8)}
    elseif ($ColorScheme -eq "Random") {$thisColorScheme = 'Random' }
    else {$thisColorScheme = 'ColorScheme2'}

    $ChartStyle = New-Object PSObject -Property @{`
        ChartType = $ChartType
        ColorSchemeName = "$thisColorScheme"
        Showlabels= $true
        borderWidth = "1"
        responsive = 'false'
        animateScale = 'true'
        animateRotate = 'true'
        legendPosition = 'bottom'
    }
    
    $ChartObject = New-Object PSObject -Property @{`
        ObjectName = -join ((65..90) + (97..122) | Get-Random -Count 12 | ForEach-Object {[char]$_})
        Title = ""
        Size = $ChartSize
        DataDefinition = $DataDefinition
        ChartStyle = $ChartStyle
    }
    
    return $ChartObject
}

Function Get-HTMLPieChart
{
<#
    .SYNOPSIS
     
#>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)]
        $ChartObject,
        [Parameter(Mandatory=$true)]
        [Array]
        $DataSet,
        [Parameter(Mandatory=$false)]
        $Options
    )

    $DataCount = $DataSet.Count
    Write-Verbose "Data Set counnt is $DataCount"

    if ($ChartObject.ChartStyle.ColorSchemeName -ne 'Random')
    {
        if ($Options -eq $null) {
            #Write-Verbose "Default Colour Schemes selected, selecting $($ChartObject.ChartStyle.ColorSchemeName)"
            #$ColorSchemes = Get-HTMLColorSchemes
            $ChartColorScheme = $GlobalColorSchemes.($ChartObject.ChartStyle.ColorSchemeName) | select -First $DataCount
        } else {
            Write-Verbose "Options Colour Schemes selected, selecting $($ChartObject.ChartStyle.ColorSchemeName)"
            $ChartColorScheme = $Options.ColorSchemes.($ChartObject.ChartStyle.ColorSchemeName) | select -First $DataCount
        }
        if ($ChartColorScheme.Count -lt $DataCount) {
            Write-Warning ("Colorscheme " +  $ChartObject.ChartStyle.ColorSchemeName + " only has " + $ChartColorScheme.Count + " schemes, you have $DataCount Records. Generating one for you" )            
            $ChartColorScheme = GenerateRandomColorScheme -numberofschemes $DataCount
        }
    }
    else
    {
        $ChartColorScheme = GenerateRandomColorScheme -numberofschemes $DataCount
    }
        
    $ofs = ','
    $CJSHeader  = @()
    $CJSHeader += '<canvas id="' + $ChartObject.ObjectName + '" width="'+ $ChartObject.Size.Width + '" height="' + $ChartObject.Size.Height +'"></canvas>'
    $CJSHeader += '<script>'
    $CJSHeader += 'var ctx = document.getElementById("' + $ChartObject.ObjectName + '");'
    $CJSHeader += 'var ' + $ChartObject.ObjectName + ' = new Chart(ctx, {'
    $CJSHeader += " type: '$($ChartObject.ChartStyle.ChartType)',"
    
    
    $CJSData = @()
    $CJSData = " data: {"+ "`n"
    if ($ChartObject.ChartStyle.Showlabels) {
        $ofs ='","'
        $CJSData += ' labels: ["' +"$($DataSet.($ChartObject.DataDefinition.DataNameColumnName))" + '"],' + "`n"
    }
    
    $CJSData += " datasets: [{" + "`n"
    $CJSData += " label: '$($chartobject.DataDefinition.datasetname)'," + "`n"
    $ofs =","
    $CJSData += " data: [" + "$($DataSet | % {$_.($ChartObject.DataDefinition.DataValueColumnName)})" +"]," + "`n"
    $ofs ="','"
    $CJSData += " backgroundColor: ['" + "$($ChartColorScheme.Background)" + "']," + "`n"
    $CJSData += " hoverBackgroundColor: ['" + "$($ChartColorScheme.border)" + "']," + "`n"
    $CJSData += " borderWidth: $($ChartObject.ChartStyle.borderWidth)" + "`n"
    $CJSData += " }]"+ "`n"
    $CJSData += " },"    
    $ofs =""
    
    
    $CJSOptions = @()
    $cjsOptions += ' options: {'
    #responsive
    $cjsOptions += " responsive: $($ChartObject.ChartStyle.responsive),"
    #legend
    $cjsOptions += " legend: {
                position: '$($ChartObject.ChartStyle.legendposition)',
            },"

    #Title
    if ($ChartObject.Title -ne '') {
        $cjsOptions += " title: {
                display: true,
                text: '$($ChartObject.Title)'
            },"

    }
    $cjsOptions += " },"
    #animation
    $cjsOptions += " animation: {
                animateScale: $($ChartObject.ChartStyle.animateScale),
                animateRotate: $($ChartObject.ChartStyle.animateRotate)
            }"

    $CJSOptions += "}); "
    
    
    
    $CJSFooter = " </script>"
    


    $CJS  = @()
    $CJS += $CJSHeader
    $CJS += $CJSData
    $CJS += $CJSOptions 
    $CJS += $CJSFooter

    write-output $CJS
}

Function Get-HTMLStackedChartObject
{
<#
    .SYNOPSIS
        create a Stacked chart object for use with Get-HTMLStackedChart
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory=$false)]
        $ColorScheme,
        #[Parameter(Mandatory=$true)]
        [String]
        $DataSetArrayXLabels='Date',
        #[Parameter(Mandatory=$true)]
        [String]
        $DataSetArrayName='OwnerSolution',
        #[Parameter(Mandatory=$true)]
        [String]
        $DataSetArrayData='usagedata',
        #[Parameter(Mandatory=$true)]
        [String]
        $DataSetArrayDataColumn='cost'
)

    $ChartSize = New-Object PSObject -Property @{`
        Width = 1000
        Height = 400
    }
    
    $DataDefinition = New-Object PSObject -Property @{`
        DataSetArrayData = $DataSetArrayData
        DataSetArrayName = $DataSetArrayName
        DataSetArrayXLabels = $DataSetArrayXLabels
        DataSetArrayDataColumn = $DataSetArrayDataColumn
    }
    
    if ($ColorScheme -eq "Generated") {$thisColorScheme = 'Generated' + [string](Get-Random -Minimum 1 -Maximum 8)}
    elseif ($ColorScheme -eq "Random") {$thisColorScheme = 'Random' }
    else {$thisColorScheme = 'ColorScheme2'}

    $ChartStyle = New-Object PSObject -Property @{`
        ChartType = 'line'
        ColorSchemeName = "$thisColorScheme"
        Showlabels= $true
        yAxesStacked= 'true'
        borderWidth = "1"
        responsive = 'false'
        animateScale = 'true'
        animateRotate = 'true'
        legendPosition = 'bottom'
        tooltips = New-Object PSObject -Property @{`
            mode = 'dataset'
            intersect = 'true'
        }
        hover  = New-Object PSObject -Property @{`
            mode = 'point'
            intersect = 'true'
        }

    }
    
    $ChartObject = New-Object PSObject -Property @{`
        ObjectName = -join ((65..90) + (97..122) | Get-Random -Count 12 | ForEach-Object {[char]$_})
        Title = ""
        Size = $ChartSize
        DataDefinition = $DataDefinition
        ChartStyle = $ChartStyle
    }
    
    return $ChartObject
}


#$ChartObject = Get-HTMLStackedChartObject
Function Get-HTMLStackedChart
{
<#
    .SYNOPSIS
     
#>

    [CmdletBinding()]
    Param (
        [Parameter(Mandatory=$true)]
        $ChartObject,
        [Parameter(Mandatory=$true)]
        [Array]
        $DataSet,        
        [Parameter(Mandatory=$false)]
        $Options
    )


    $DataCount = $DataSet.Count
    Write-Verbose "Data Set count is $DataCount"

    if ($ChartObject.ChartStyle.ColorSchemeName -ne 'Random')
    {
        if ($Options -eq $null) {
            #Write-Verbose "Default Colour Schemes selected, selecting $($ChartObject.ChartStyle.ColorSchemeName)"
            #$ColorSchemes = Get-HTMLColorSchemes
            $ChartColorScheme = $GlobalColorSchemes.($ChartObject.ChartStyle.ColorSchemeName) | select -First $DataCount
        } else {
            Write-Verbose "Options Colour Schemes selected, selecting $($ChartObject.ChartStyle.ColorSchemeName)"
            $ChartColorScheme = $Options.ColorSchemes.($ChartObject.ChartStyle.ColorSchemeName) | select -First $DataCount
        }
        if ($ChartColorScheme.Count -lt $DataCount) {
            Write-Warning ("Colorscheme " +  $ChartObject.ChartStyle.ColorSchemeName + " only has " + $ChartColorScheme.Count + " schemes, you have $DataCount Records. Generating one for you" )            
            $ChartColorScheme = GenerateRandomColorScheme -numberofschemes $DataCount -ColorSwing (($DataCount/2)+8)
        }
    }
    else
    {
        $ChartColorScheme = GenerateRandomColorScheme -numberofschemes $DataCount -ColorSwing (($DataCount/2)+8)
    }
        
    $ofs = ','
    $CJSHeader  = @()
    $CJSHeader += '<canvas id="' + $ChartObject.ObjectName + '" width="'+ $ChartObject.Size.Width + '" height="' + $ChartObject.Size.Height +'"></canvas>'
    $CJSHeader += '<script>'
    $CJSHeader += 'var ctx = document.getElementById("' + $ChartObject.ObjectName + '");'
    $CJSHeader += 'var ' + $ChartObject.ObjectName + ' = new Chart(ctx, {'
    $CJSHeader += " type: '$($ChartObject.ChartStyle.ChartType)',"
    
    
    $CJSData = @()
    $CJSData = " data: {"+ "`n"
    if ($ChartObject.ChartStyle.Showlabels) {
        $ofs ='","'
        $CJSData += ' labels: ["' +"$([string]($DataSet.($ChartObject.DataDefinition.DataSetArrayData).($ChartObject.DataDefinition.DataSetArrayXLabels) | select -Unique))" + '"],' + "`n"
    }
    

    $rowCount = 0
    $CJSData += " datasets: ["
    #$Set = $DataSet[4]
    Foreach ($Set in $DataSet)
    {
        $CJSData += " {" + "`n"
        $CJSData += " label: '$($Set.($ChartObject.DataDefinition.DataSetArrayName))'," + "`n"
        $ofs =","
        $CJSData += " fill: true," + "`n"
        $CJSData += " data: [" + "$([string]($Set.($ChartObject.DataDefinition.DataSetArrayData).($chartObject.DataDefinition.DataSetArrayDataColumn)))" +"]," + "`n"
        $ofs ="','"
        $CJSData += " borderCapStyle: 'butt'," + "`n"        
        $CJSData += " backgroundColor: '$($ChartColorScheme[$rowcount].Background)'," + "`n"
        $CJSData += " pointBackgroundColor: '$($ChartColorScheme[$rowcount].Border)'," + "`n"
        $CJSData += " pointHighlightStroke: '$($ChartColorScheme[$rowcount].Border)'," + "`n"
        $CJSData += " borderColor: '$($ChartColorScheme[$rowcount].Border)'," + "`n"
        
        if ($rowCount -ne ($DataSet.Count -1)) 
        {
            $CJSData += " },"
        }
        else
        {
            $CJSData += " }"
        }
        $rowCount++
    }

        $CJSData += " ]"+ "`n"
        $CJSData += " },"    
        $ofs =""
       

    
    
    $CJSOptions = @()
    $cjsOptions += ' options: {'
    #responsive
    $cjsOptions += " responsive: $($ChartObject.ChartStyle.responsive),"
    #legend
    $cjsOptions += " legend: {
                position: '$($ChartObject.ChartStyle.legendposition)',
            },"

    #Title
    if ($ChartObject.Title -ne '') {
        $cjsOptions += " title: {
                display: true,
                text: '$($ChartObject.Title)'
            },"

    }
    #Scales
    $cjsOptions += "scales: {
               yAxes: [{
               stacked: $($ChartObject.ChartStyle.yAxesStacked),
                }]
        },"

    #Tooltips
        $cjsOptions += "tooltips: {
               mode: '$($ChartObject.ChartStyle.tooltips.mode)',
               intersect: $($ChartObject.ChartStyle.tooltips.intersect),
        },"


    #Hover
        $cjsOptions += "hover: {
                 mode: '$($ChartObject.ChartStyle.hover.mode)',
               intersect: $($ChartObject.ChartStyle.hover.intersect),
        },"

    #animation
    $cjsOptions += " animation: {
                animateScale: $($ChartObject.ChartStyle.animateScale),
                animateRotate: $($ChartObject.ChartStyle.animateRotate),
                duration: 750,
            },"

    $cjsOptions += "}"
    $CJSOptions += "}); "
    
    
    $CJSFooter = " </script>"
    


    $CJS  = @()
    $CJS += $CJSHeader
    $CJS += $CJSData
    $CJS += $CJSOptions 
    $CJS += $CJSFooter

    write-output $CJS
}




#Endregion

#Region Output Functions

Function Save-HTMLReport 
{
<#
    .SYNOPSIS
        generation of report and invokes the file to open
    .PARAMETER ReportName
        with generate a random file name if noone is specified
    .PARAMETER ReportPath
        specifiy test directory, will use %TEMP% by default
    .PARAMETER ReportContent
        This should be the complete HTML code
#>

    [CmdletBinding()]
    Param 
    (
        [Parameter(Mandatory=$false)]
        [string]$ReportName,
        [Parameter(Mandatory=$false)]
        [string]$ReportPath,
        [Parameter(Mandatory=$true)]
        [Array]$ReportContent,
        [Parameter(Mandatory=$false)]
        [switch]$ShowReport
    )
   
    if ([string]::IsNullOrEmpty($ReportPath)) 
    {
        Write-Warning "ReportPath parameter $ReportPath is empty,using Temp"
        $ReportPath = $env:temp
    }
    else {
        if ((Test-Path $ReportPath) -eq $false )
        {
            Write-Warning "ReportPath parameter $ReportPath is not valid or can't be accessed,using Temp"
            $ReportPath = $env:temp
        }
    }
    
    
    $ReportName = $ReportName.replace('.html','')
    if ($ReportName -eq $null -or $ReportName -eq ""){
        $ReportName = -join ((65..90) + (97..122) | Get-Random -Count 12 | ForEach-Object {[char]$_})
    }
    $rptFile = join-path $ReportPath ($ReportName.replace(" ","") + ".html")
    Write-Verbose "Generating Report File at $rptFile"
    
       
    $ReportContent | Set-Content -Path $rptFile -Force
    Write-Verbose $rptFile
    if ($ShowReport) {
        Start-Sleep -Seconds 1
        Invoke-Item $rptFile
    }
    Write-Output $rptFile
}

Function Save-HTMLToBlobStorage  
{
<#
    .SYNOPSIS
        generation of report and invokes the file to open
#>

     [CmdletBinding()]
     Param
     (
        [Parameter(Mandatory=$true)]
        [Array]
        $ReportContent,
        [Parameter(Mandatory=$true)]
        [string]
        $resourceGroupName = "",
        [Parameter(Mandatory=$true)]
        [string]
        $storageAccountName = "",
        [Parameter(Mandatory=$true)]
        [string]
        $storageContainerName = "",
        [Parameter(Mandatory=$false)]
        [string]
        $ReportPrefix = "HTMLReport"
    )

    $localFileName ="{0}\report.html" -f $env:TEMP
    $ReportContent | Set-Content -Path $localFileName
    $blobFileName = $ReportPrefix + "-{0}" -f [guid]::NewGuid() + ".html"

    Write-Output ("Saving the report to storage")
    Write-Output ("Resource Group: {0}" -f $resourceGroupName)
    Write-Output ("Storage Account: {0}" -f $storageAccountName)
    Write-Output ("Storage Container: {0}" -f $storageContainerName)
    Write-Output ("Blob: {0}" -f $blobFileName)

    Set-AzureRmCurrentStorageAccount   -ResourceGroupName $resourceGroupName  -Name $storageAccountName | Out-Null

    $storageAccount = Get-AzureRmStorageAccount `
        -ResourceGroupName $resourceGroupName `
        -Name $storageAccountName

    $storageAccountContainer = Get-AzureStorageContainer `
        -Name $storageContainerName

    $blob = Set-AzureStorageBlobContent `
        -Container $storageContainerName `
        -Blob $blobFileName `
        -File $localFileName
        
    Write-Output ("Click the link below to view the report")
    $url = "https://{0}.blob.core.windows.net/{1}/{2}" -f $storageAccountName, $storageContainerName, $blob.Name
    $hash = @{
        type = "hyperlink";
        name = "Report: {0}" -f $blob.Name;
        value = $url
    }
    Write-Output($hash)
}

function Send-HTMLReport 
{
    <#
    .SYNOPSIS
        rudimentary send report via email function. Suggest finding more comprehensive function it must already exist :)
    .PARAMETER To
    .PARAMETER From
    .PARAMETER SMTPServer
    .PARAMETER SMTPPort
#>

    [CmdletBinding()]
    Param (
        [string]$ReportName,
        [string]$To,
        [string]$From,
        [string]$SMTPServer = "smtp.gmail.com",
        [string]$SMTPPort = "587",
        [string]$Body = 'HTML Report Attached',
        $Rptfile,
        [System.Management.Automation.PSCredential]
        $Credentials,
        [hashtable]
        $StoredReport
    )
    
    Write-Warning "...this is in development, mainly as a placeholder. Expect Breaking changes."
    sleep 3
    Send-MailMessage -From $From -to $To -Subject $ReportName `
        -Body $Body -SmtpServer $SMTPServer -port $SMTPPort -UseSsl -Credential $Credentials -Attachments $Rptfile

}

#Endregion

#region Alias's
New-Alias -name Get-HTMLPageClose -value Get-HTMLClosePage -Force
New-Alias -name Get-HTMLPageOpen -value Get-HTMLOpenPage -force
#endregion