core/modules/monkeyhtml/private/Tables/New-HtmlTableFromObject.ps1

# Monkey365 - the PowerShell Cloud Security Tool for Azure and Microsoft 365 (copyright 2022) by Juan Garrido
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Function New-HtmlTableFromObject{
    <#
        .SYNOPSIS
 
        .DESCRIPTION
 
        .INPUTS
 
        .OUTPUTS
 
        .EXAMPLE
 
        .NOTES
            Author : Juan Garrido
            Twitter : @tr1ana
            File Name : New-HtmlTableFromObject
            Version : 1.0
 
        .LINK
            https://github.com/silverhack/monkey365
    #>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "", Scope="Function")]
    [CmdletBinding()]
    [OutputType([System.Xml.XmlElement])]
    Param (
        [parameter(Mandatory= $True, HelpMessage= "Table data")]
        [Object]$Data,

        [parameter(Mandatory= $false, HelpMessage= "Table class name")]
        [String[]]$ClassName,

        [parameter(Mandatory= $false, HelpMessage= "ID table")]
        [String]$Id,

        [parameter(Mandatory= $false, HelpMessage= "AsList table")]
        [Switch]$AsList,

        [parameter(Mandatory= $false, HelpMessage= "ShowModal button")]
        [Switch]$ShowModalButton,

        [parameter(Mandatory= $false, HelpMessage= "ShowGoTo button")]
        [Switch]$ShowGoToButton,

        [parameter(Mandatory= $false, HelpMessage= "Extended data")]
        [Object]$ExtendedData,

        [parameter(Mandatory= $false, HelpMessage= "Decorate data")]
        [System.Array]$Decorate,

        [parameter(Mandatory= $false, HelpMessage= "Emphasis data")]
        [System.Array]$Emphasis,

        [parameter(Mandatory= $false, HelpMessage= "Emphasis class")]
        [String[]]$EmphasisClass = 'cell-highlight',

        [parameter(Mandatory= $false, HelpMessage= "Template")]
        [System.Xml.XmlDocument]$Template
    )
    Begin{
        If($PSBoundParameters.ContainsKey('Template') -and $PSBoundParameters['Template']){
            $TemplateObject = $PSBoundParameters['Template']
        }
        ElseIf($null -ne (Get-Variable -Name Template -Scope Script -ErrorAction Ignore)){
            $TemplateObject = $script:Template
        }
        Else{
            [xml]$TemplateObject = "<html></html>"
        }
    }
    Process{
        $formattedData = $Data | Format-PsObject
        If($null -ne $formattedData){
            #Check if AsList Table
            If($PSBoundParameters.ContainsKey('AsList') -and $PSBoundParameters['AsList'].IsPresent){
                #Convert to HTML table
                $outTable = $formattedData | Microsoft.PowerShell.Utility\ConvertTo-Html -As List -Fragment
                $outDataTable = $outTable -replace "<td><hr></td>", "<td><hr/></td><td><hr/></td>"
                $table = "<table><thead>`n{0}`n</thead>`n<tbody>`n{1}`n</tbody></table>" -f $outDataTable[1], ($outDataTable[2..($outDataTable.Count - 2)] -join "`n")
                #Decode table
                [xml]$xmlTable = [System.Net.WebUtility]::HtmlDecode($table)
                #Import table
                $newxmlTable = $TemplateObject.ImportNode($xmlTable.get_DocumentElement(), $True)
                #Set class
                [void]$newxmlTable.SetAttribute('class',"table monkey-table-vertical table-borderless no-footer");
                #Set Table mode
                [void]$newxmlTable.SetAttribute('type',"asList")
                #emphasis data
                If($PSBoundParameters.ContainsKey('Emphasis') -and $PSBoundParameters['Emphasis']){
                    Foreach($emphasisElement in $PSBoundParameters['Emphasis']){
                        #Find element
                        $element = $newxmlTable.SelectNodes(('tbody/tr[td="{0}:"]' -f $emphasisElement))
                        If($element){
                            ForEach($node in $element){
                                $node.LastChild.SetAttribute('class',$EmphasisClass)
                            }
                        }
                    }
                }
            }
            Else{
                $tmpTable = '<table>${formattedData}</table>'
                $outTable = $formattedData | Microsoft.PowerShell.Utility\ConvertTo-Html -As Table -Fragment
                $outDataTable = "<thead>`n{0}`n</thead>`n<tbody>`n{1}`n</tbody>" -f $outTable[2], ($outTable[3..($outTable.Count - 2)] -join "`n")
                $table = $tmpTable -replace '\${formattedData}', $outDataTable
                #Decode table
                [xml]$xmlTable = [System.Net.WebUtility]::HtmlDecode($table);
                #Import table
                $newxmlTable = $TemplateObject.ImportNode($xmlTable.get_DocumentElement(), $True)
                #Set class
                #[void]$newxmlTable.SetAttribute('class',"table monkey-table");
                [void]$newxmlTable.SetAttribute('class',"table monkey-table");
                #Set Table mode
                [void]$newxmlTable.SetAttribute('type',"Default")
                #Set Table style
                [void]$newxmlTable.SetAttribute('style',"width:100%;")
                #Check for disabled/enabled/notset elements
                $tds = $newxmlTable.SelectNodes("//td")
                foreach($td in @($tds)){
                    If($td.InnerText.ToLower() -eq 'disabled'){
                        #Create new A element
                        $spanProperties = @{
                            Name = "span";
                            Attributes = @{
                                class = "badge badge-warning badge-xl";
                            };
                            Text = $td.InnerText;
                            CreateTextNode = $True;
                            Template = $TemplateObject;
                        }
                        #Create span tag
                        $span = New-HtmlTag @spanProperties
                        If($span){
                            $td.InnerText = $null
                            [void]$td.AppendChild($span)
                        }
                    }
                    ElseIf($td.InnerText.ToLower() -eq 'enabled'){
                        #Create new A element
                        $spanProperties = @{
                            Name = "span";
                            Attributes = @{
                                class = "badge badge-success badge-xl";
                            };
                            Text = $td.InnerText;
                            CreateTextNode = $True;
                            Template = $TemplateObject;
                        }
                        #Create span tag
                        $span = New-HtmlTag @spanProperties
                        If($span){
                            $td.InnerText = $null
                            [void]$td.AppendChild($span)
                        }
                    }
                    ElseIf($td.InnerText.ToLower() -eq 'notset'){
                        #Create new A element
                        $spanProperties = @{
                            Name = "span";
                            Attributes = @{
                                class = "badge badge-disabled badge-xl";
                            };
                            Text = $td.InnerText;
                            CreateTextNode = $True;
                            Template = $TemplateObject;
                        }
                        #Create span tag
                        $span = New-HtmlTag @spanProperties
                        If($span){
                            $td.InnerText = $null
                            [void]$td.AppendChild($span)
                        }
                    }
                }
                #Decorate data
                If($PSBoundParameters.ContainsKey('Decorate') -and $PSBoundParameters['Decorate']){
                    Foreach($decorateOptions in $PSBoundParameters['Decorate']){
                        $itemName = $decorateOptions | Select-Object -ExpandProperty ItemName -ErrorAction Ignore
                        $itemValue = $decorateOptions | Select-Object -ExpandProperty ItemValue -ErrorAction Ignore
                        $itemClassName = $decorateOptions | Select-Object -ExpandProperty className -ErrorAction Ignore
                        #Find element
                        $element = $newxmlTable.SelectNodes(('//td[(count(//tr/th[.="{0}"]/preceding-sibling::*)+1)]' -f $itemName))
                        If($element){
                            ForEach($node in $element){
                                If($node.InnerText.ToString().ToLower() -eq $itemValue.ToString()){
                                    $node.LastChild.SetAttribute('class',$itemClassName)
                                }
                            }
                        }
                    }
                }
                #Add showmodal and goto buttons
                If($PSBoundParameters.ContainsKey('ExtendedData') -and $PSBoundParameters['ExtendedData'] -and (($PSBoundParameters.ContainsKey('ShowModalButton') -and $PSBoundParameters['ShowModalButton'].IsPresent) -or ($PSBoundParameters.ContainsKey('ShowGoToButton') -and $PSBoundParameters['ShowGoToButton'].IsPresent))){
                    Set-Variable -Name table -Value $newxmlTable -scope Global -Force
                    #Set actions column
                    $thead = $newxmlTable.SelectSingleNode("thead/tr")
                    #Add Actions column
                    $th = $TemplateObject.CreateElement("th")
                    $th.InnerText = "Actions"
                    [void]$thead.AppendChild($th)
                    #Iterate over body to add buttons
                    $tbody = $newxmlTable.SelectSingleNode("tbody")
                    For ($idx=0;$idx -lt $tbody.ChildNodes.Count; $idx++){
                        #Create Td object
                        $td = $TemplateObject.CreateElement("td")
                        Try{
                            If($idx -lt @($PSBoundParameters['ExtendedData']).Count){
                                $id = ("#{0}" -f $PSBoundParameters['ExtendedData'].Item($idx).id);
                            }
                            Else{
                                $id = $null;
                            }
                        }
                        Catch{
                            $id = $null
                        }
                        If($PSBoundParameters.ContainsKey('ShowModalButton') -and $PSBoundParameters['ShowModalButton'].IsPresent){
                            #Create I object
                            $iProperties = @{
                                Name = "i";
                                Attributes = @{
                                    class = "bi bi-eye";
                                };
                                Empty = $True;
                                Template = $TemplateObject;
                            }
                            #Create i tag
                            $i = New-HtmlTag @iProperties
                            #Create button
                            $buttonProperties = @{
                                Name = "button";
                                Attributes = @{
                                    class = 'btn btn-primary me-2';
                                    title = "showModal";
                                    type = 'button';
                                    "data-bs-target" = $Id;
                                    "data-bs-toggle" = "modal";
                                };
                                AppendObject = $i;
                                Template = $TemplateObject;
                            }
                            $showGotoObjButton = New-HtmlTag @buttonProperties
                            [void]$td.AppendChild($showGotoObjButton);
                        }
                        [void]$tbody.ChildNodes.Item($idx).LastChild.AppendChild($td)
                        #Close i tags
                        $i_tags = $tbody.ChildNodes.Item($idx).SelectNodes("//i")
                        $i_tags | ForEach-Object {$_.InnerText = [string]::Empty}
                    }
                }
            }
            #Check if Id
            If($PSBoundParameters.ContainsKey('Id') -and $PSBoundParameters['Id']){
                [void]$newxmlTable.SetAttribute('id',$PSBoundParameters['Id'])
            }
            Else{
                $tableId = ("MonkeyTable_{0}" -f [System.Guid]::NewGuid().Guid.Replace('-','').ToString());
                [void]$newxmlTable.SetAttribute('id',$tableId)
            }
            #Set Class name
            If($PSBoundParameters.ContainsKey('ClassName') -and $PSBoundParameters['ClassName']){
                $oldClass = $newxmlTable.table.class
                $_Class = [String]::Join(' ',$PSBoundParameters['ClassName']);
                $tableClass = ("{0} {1}" -f $oldClass,$_Class)
                [void]$newxmlTable.SetAttribute('class',$tableClass);
            }
            #Add table to main div
            #Create a root div element
            <#
            $divProperties = @{
                Name = "div";
                Attributes = @{
                    class = "monkey-datatable";
                };
                AppendObject = $newxmlTable;
                Template = $TemplateObject;
            }
            #Create div tag
            $rootDiv = New-HtmlTag @divProperties
            #>

            #return table
            $newxmlTable
        }
    }
    End{
    }
}