core/modules/monkeyruleset/private/New-MonkeyFindingObject.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-MonkeyFindingObject {
<#
        .SYNOPSIS
        Create a new finding object
 
        .DESCRIPTION
        Create a new finding object
 
        .INPUTS
 
        .OUTPUTS
 
        .EXAMPLE
 
        .NOTES
            Author : Juan Garrido
            Twitter : @tr1ana
            File Name : New-MonkeyFindingObject
            Version : 1.0
 
        .LINK
            https://github.com/silverhack/monkey365
    #>


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

        [parameter(Mandatory= $false, HelpMessage="affected objects")]
        [AllowNull()]
        [AllowEmptyString()]
        [Object]$AffectedObjects,

        [parameter(Mandatory= $false, HelpMessage="objects to check")]
        [AllowNull()]
        [AllowEmptyString()]
        [Object]$Resources,

        [Parameter(Mandatory=$false, HelpMessage="Set the output timestamp format as unix timestamps instead of iso format")]
        [Switch]$UnixTimestamp
    )
    Process{
        try{
            #Check level
            if($null -eq $InputObject.PsObject.Properties.Item('level')){
                $InputObject | Add-Member -Type NoteProperty -name level -value $null -Force
            }
            #Add metadata
            $Metadata = $InputObject | Get-ObjectFromDataset -Metadata
            If($null -eq $Metadata){
                $Metadata = New-EmptyMetadataObject
            }
            $InputObject | Add-Member -Type NoteProperty -name metadata -value $Metadata -Force
            $InputObject | Add-Member -Type NoteProperty -name affectedResources -value $AffectedObjects -Force
            $InputObject | Add-Member -Type NoteProperty -name resources -value $Resources -Force
            #Format html and text output if exists
            If($PSBoundParameters.ContainsKey('AffectedObjects') -and $PSBoundParameters['AffectedObjects']){
                #Format HTML if exists
                Try{
                    $p = @{
                        Expressions = $InputObject.output.html.data.properties;
                        ExpandObject = $InputObject.output.html.data.expandObject ;
                    }
                    $dataOut = $PSBoundParameters['AffectedObjects'] | Format-DataFromExpression @p -RuleName $InputObject.displayName
                    #Add to object
                    $InputObject.output.html | Add-Member -Type NoteProperty -name out -value $dataOut -Force
                }
                Catch{
                    Write-Warning -Message ($Script:messages.UnableToFormatErrorMessage -f "HTML")
                    $InputObject.output.html | Add-Member -Type NoteProperty -name out -value $null -Force
                }
                #Format text if exists
                Try{
                    $p = @{
                        Expressions = $InputObject.output.text.data.properties;
                        ExpandObject = $InputObject.output.text.data.expandObject ;
                    }
                    $dataOut = $PSBoundParameters['AffectedObjects'] | Format-DataFromExpression @p
                    #Add to object
                    $InputObject.output.text | Add-Member -Type NoteProperty -name out -value $dataOut -Force
                }
                Catch{
                    Write-Warning -Message ($Script:messages.UnableToFormatErrorMessage -f "text")
                    $InputObject.output.text | Add-Member -Type NoteProperty -name out -value $null -Force
                }
                #Format extended data if exists
                Try{
                    $extendedData = [System.Collections.Generic.List[System.Object]]::new();
                    [int]$intMinValue = [int32]::MinValue;
                    [bool]$limit = [int]::TryParse($InputObject.output.html.actions.objectData.limit, [ref]$intMinValue);
                    $expressions = $InputObject.output.html.actions.objectData.properties;
                    $expandObject = $InputObject.output.html.actions.objectData.expandObject;
                    $p = @{
                        Expressions = $expressions;
                        ExpandObject = $expandObject;
                    }
                    If($limit){
                        [void]$p.Add('Limit',$InputObject.output.html.actions.objectData.limit)
                    }
                    $dataOut = $PSBoundParameters['AffectedObjects'] | Format-DataFromExpression @p
                    Foreach($obj in @($dataOut)){
                        $id = ("MonkeyRawObject_{0}" -f [System.Guid]::NewGuid().Guid.Replace('-','').ToString())
                        $newObj = [psobject]@{
                            rawData = $obj;
                            format = "json";
                            id = $id;
                        }
                        #Add to array
                        [void]$extendedData.Add($newObj);
                    }
                    #Append psObject
                    $InputObject.output.html | Add-Member -type NoteProperty -name extendedData -value $extendedData -Force
                }
                Catch{
                    Write-Warning -Message ($Script:messages.UnableToFormatErrorMessage -f "extended data")
                    $InputObject.output.html | Add-Member -Type NoteProperty -name extendedData -value $null -Force
                }
            }
            Else{
                Set-StrictMode -Off
                $InputObject.output.html | Add-Member -Type NoteProperty -name out -value $null -Force
                $InputObject.output.text | Add-Member -Type NoteProperty -name out -value $null -Force
                $InputObject.output.html | Add-Member -Type NoteProperty -name extendedData -value $null -Force
            }
            #Add timestamp
            if($PSBoundParameters.ContainsKey('UnixTimestamp') -and $PSBoundParameters['UnixTimestamp'].IsPresent){
                $timestamp = ([System.DateTime]::UtcNow).ToString("yyyy-MM-ddTHH:mm:ssK")
            }
            Else{
                $timestamp = ([System.DateTime]::Now.ToString('o'))
            }
            $InputObject | Add-Member -Type NoteProperty -name timestamp -value $timestamp -Force
            #Add StatusCode
            $InputObject | Add-Member -Type NoteProperty -name statusCode -value $null -Force
            #Add method to count resources
            $InputObject | Add-Member -Type ScriptMethod -Name affectedResourcesCount -Value {
                If($null -ne $this.affectedResources){
                    return @($this.affectedResources).Count
                }
                Else{
                    return 0
                }
            } -Force
            #Add method to count resources
            $InputObject | Add-Member -Type ScriptMethod -Name resourcesCount -Value {
                If($null -ne $this.resources){
                    return @($this.resources).Count
                }
                Else{
                    return 0
                }
            } -Force
            #Add method to generate id suffix numbers
            $InputObject | Add-Member -Type ScriptMethod -Name getNewIdSuffix -Value {
                If($null -ne $this.idSuffix.Replace(' ','_')){
                    $guid = [System.Guid]::NewGuid().ToString('N')
                    return ("{0}_{1}" -f $this.idSuffix, $guid)
                }
            } -Force
            return $InputObject
        }
        catch{
            Write-Verbose $_.Exception.Message
        }
    }
}