core/modules/monkeyhtml/private/Card/New-FindingCard.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-FindingCard{
    <#
        .SYNOPSIS
 
        .DESCRIPTION
 
        .INPUTS
 
        .OUTPUTS
 
        .EXAMPLE
 
        .NOTES
            Author : Juan Garrido
            Twitter : @tr1ana
            File Name : New-FindingCard
            Version : 1.0
 
        .LINK
            https://github.com/silverhack/monkey365
    #>


    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseShouldProcessForStateChangingFunctions", "", Scope="Function")]
    [CmdletBinding()]
    Param (
        [parameter(Mandatory= $True, ValueFromPipeline = $True, HelpMessage= "Template")]
        [Object]$FindingObject,

        [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{
        Try{
            Foreach($findingObj in @($PSBoundParameters['FindingObject'])){
                Write-Verbose ($Script:messages.NewCardMessage -f $findingObj.title)
                If($findingObj.statusCode.ToLower() -eq "manual" -or $findingObj.statusCode.ToLower() -eq "pass"){
                    $bodyObject = [xml] '<div class="row monkey-finding-row"></div>'
                }
                Else{
                    $bodyObject = [xml] '<div class="row"></div>'
                }
                #Import node
                $bodyObject = $TemplateObject.ImportNode($bodyObject.DocumentElement,$true);
                #set Array
                $sections = [System.Collections.Generic.List[System.Management.Automation.PsObject]]::new()
                #Create new card
                $p = @{
                    ClassName = "monkey-finding-card","shadow-sm";
                    Header = $findingObj.displayName;
                    HeaderClass = "monkey-finding-header";
                    Id = ("FindingCard{0}" -f [System.Guid]::NewGuid().Guid.ToString().Replace('-',''))
                    Collapsible = $True;
                    Template = $TemplateObject;
                }
                $findingCard = New-HtmlCard @p
                #Get card header, body and footer
                $cardHeader = $findingCard.SelectSingleNode('//div[contains(@class,"card-header")]')
                $cardBody = $findingCard.SelectSingleNode('//div[contains(@class,"card-body")]')
                #Get icon
                $class = $findingObj.level | Get-IconFromLevel
                #Get I object
                $iProperties = @{
                    Name = "i";
                    ClassName = $class;
                    Empty = $True;
                    Template = $TemplateObject;
                }
                #Create element
                $iconHeader = New-HtmlTag @iProperties
                [void]$cardHeader.PrependChild($iconHeader);
                #Get finding card info
                $findingCardInfo = $findingObj | Get-HTMLFindingCardInfo -Template $TemplateObject
                If($findingCardInfo){
                    #Add to array
                    $sectionObj = [PsCustomObject]@{
                        name = "Info";
                        xml = $findingCardInfo;
                    }
                    [void]$sections.Add($sectionObj);
                }
                If($null -ne $findingObj.psobject.properties.Item('description') -and $null -ne $findingObj.description -and $findingObj.description.Length -gt 0){
                    $p = @{
                        Name = "Description";
                        Content = $findingObj.description;
                        Template = $TemplateObject;
                    }
                    $output = Get-HTMLCardContent @p
                }
                Else{
                    $p = @{
                        Name = "Description";
                        Content = 'No description available.';
                        Template = $TemplateObject;
                    }
                    $output = Get-HTMLCardContent @p
                }
                #Add to array
                $sectionObj = [PsCustomObject]@{
                    name = "Description";
                    xml = $output;
                }
                [void]$sections.Add($sectionObj);
                #Get rationale
                If($null -ne $findingObj.psobject.properties.Item('rationale') -and $null -ne $findingObj.rationale -and $findingObj.rationale.Length -gt 0){
                    $p = @{
                        Name = "Rationale";
                        Content = $findingObj.rationale;
                        Template = $TemplateObject;
                    }
                    $output = Get-HTMLCardContent @p
                    #Add to array
                    $sectionObj = [PsCustomObject]@{
                        name = "Rationale";
                        xml = $output;
                    }
                    [void]$sections.Add($sectionObj);
                }
                #Get impact
                If($null -ne $findingObj.psobject.properties.Item('impact') -and $null -ne $findingObj.impact -and $findingObj.impact.Length -gt 0){
                    $p = @{
                        Name = "Impact";
                        Content = $findingObj.impact;
                        Template = $TemplateObject;
                    }
                    $output = Get-HTMLCardContent @p
                    #Add to array
                    $sectionObj = [PsCustomObject]@{
                        name = "Impact";
                        xml = $output;
                    }
                    [void]$sections.Add($sectionObj);
                }
                #Get remediation
                Try{
                    If($null -ne $findingObj.remediation.text -and $findingObj.remediation.text.Length -gt 0){
                        $p = @{
                            Name = "Remediation";
                            Content = $findingObj.remediation.text;
                            Template = $TemplateObject;
                        }
                        $output = Get-HTMLCardContent @p
                        #Add to array
                        $sectionObj = [PsCustomObject]@{
                            name = "Remediation";
                            xml = $output;
                        }
                        [void]$sections.Add($sectionObj);
                    }
                }
                Catch{
                    Write-Warning ($Script:messages.UnableToGetProperty -f $findingObj.title)
                    Write-Error $_.Exception
                }
                #Get references
                If($null -ne $findingObj.psobject.properties.Item('references') -and $null -ne $findingObj.references -and @($findingObj.references).Count -gt 0){
                    $p = @{
                        Name = "References";
                        Content = $findingObj.references;
                        Template = $TemplateObject;
                    }
                    $output = Get-HTMLCardReference @p
                    #Add to array
                    $sectionObj = [PsCustomObject]@{
                        name = "References";
                        xml = $output;
                    }
                    [void]$sections.Add($sectionObj);
                }
                <#
                #Get compliance
                If($null -ne $findingObj.psobject.properties.Item('compliance') -and $null -ne $findingObj.compliance){
                    $p = @{
                        Name = "Compliance";
                        Content = $findingObj.compliance;
                        Template = $TemplateObject;
                    }
                    $output = Get-HTMLCardCompliance @p
                    #Add to array
                    $sectionObj = [PsCustomObject]@{
                        name = "Compliance";
                        xml = $output;
                    }
                    [void]$sections.Add($sectionObj);
                }
                #>

                #Fill card
                foreach($section in $sections){
                    Write-Verbose ($Script:messages.AppendElementMessageInfo -f $section.name, $findingObj.displayName);
                    [void]$bodyObject.AppendChild($section.xml);
                }
                #Add body object to card body
                If($findingObj.statusCode.ToLower() -in @('pass','manual')){
                    #Add to body
                    [void]$cardBody.AppendChild($bodyObject);
                }
                Else{
                    #Get Tab
                    $p = @{
                        Id = $findingObj.idSuffix;
                        Default = $True;
                        Template = $TemplateObject;
                    }
                    $tab = New-HTMLTab @p
                    #Get active tab pane
                    $_div = $tab.SelectSingleNode('//div[contains(@class,"show active")]')
                    If($null -ne $_div){
                        [void]$_div.AppendChild($bodyObject);
                    }
                    #Get tab pane
                    $_div = $tab.SelectSingleNode('//div[@class="tab-pane"]')
                    If($null -ne $_div){
                        $outData = $findingObj.output.html.out;
                        If($null -ne $outData){
                            $TableOption = $findingObj.output.html.table;
                            $extraFormat = $findingObj.output.html.decorate;
                            $extendedData = $findingObj.output.html.extendedData;
                            $emphasis = $findingObj.output.html.emphasis;
                            #Get showmodal and showgoto button
                            Try{
                                $out = $null;
                                [void][bool]::TryParse($findingObj.output.html.actions.showModalButton,[ref]$out);
                                $showModalButton = $out
                                $out = $null;
                                [void][bool]::TryParse($findingObj.output.html.actions.showGoToButton,[ref]$null)
                                $showGoToButton = $out
                            }
                            Catch{
                                $showModalButton = $false
                                $showGoToButton = $false
                            }
                            $p = @{
                                Data = $findingObj.output.html.out;
                                Template = $TemplateObject;
                                ShowModalButton = $showModalButton;
                                ShowGoToButton = $showGoToButton;
                            }
                            If($null -ne $TableOption -and $TableOption -ne "Normal"){
                                [void]$p.Add('AsList',$True);
                            }
                            If($null -ne $extraFormat -and @($extraFormat).Count -gt 0){
                                [void]$p.Add('Decorate',@($extraFormat))
                            }
                            If($null -ne $extendedData -and @($extendedData).Count -gt 0){
                                [void]$p.Add('ExtendedData',$extendedData);
                            }
                            If($null -ne $emphasis -and @($emphasis).Count -gt 0){
                                [void]$p.Add('Emphasis',$emphasis);
                            }
                            #Table goes here
                            $myTable = New-HtmlTableFromObject @p
                            [void]$_div.AppendChild($myTable);
                        }
                        Else{
                            Write-Warning ($Scripts:messages.EmptySectionMessage -f "data",$findingObj.title);
                        }
                    }
                    #Add to body
                    [void]$cardBody.AppendChild($tab);
                }
                $findingCard
            }
        }
        Catch{
            Write-Warning ($Script:messages.CardErrorMessage -f "Finding card", $findingObj.title);
            Write-Error $_.Exception
        }
    }
    End{
        #Nothing to do here
    }
}