public/Invoke-VPASMetricsProviders.ps1

<#
.Synopsis
   RUN VARIOUS PROVIDER METRICS FROM CYBERARK
   CREATED BY: Vadim Melamed, EMAIL: vpasmodule@gmail.com
.DESCRIPTION
   USE THIS FUNCTION TO GENERATE VARIOUS PROVIDER RELATED METRICS FROM CYBERARK
.LINK
   https://vpasmodule.com/commands/Invoke-VPASMetricsProviders
.PARAMETER token
   HashTable of data containing various pieces of login information (PVWA, LoginToken, HeaderType, etc).
   If -token is not passed, function will use last known hashtable generated by New-VPASToken
.PARAMETER TargetMetric
   Specify which report will be run
   Possible values: ApplicationIDsOnSafes, AccountsPulledViaApplicationID
.PARAMETER MetricFormat
   Specify the report output format
   NONE will return the generated hashtable of data that can be assigned to a variable
   Possible values: JSON, HTML, ALL, NONE
.PARAMETER OutputDirectory
   Specify where the location for report output to be saved
.PARAMETER HTMLChart
   Specify the HTML report type
   Possible values: BarGraph, LineGraph, PieChart, ALL
.PARAMETER HideRawData
   Removes the RawData visual from the exported output
   Helpful when exporting to a PDF or document to remove extra not needed information
.PARAMETER IgnoreSafes
   Wildcard value that will cause a record to be ignored from the metrics if the target record SafeName matches
.PARAMETER IgnorePlatforms
   Wildcard value that will cause a record to be ignored from the metrics if the target record PlatformID matches
.PARAMETER IgnoreUsernames
   Wildcard value that will cause a record to be ignored from the metrics if the target record Username matches
.PARAMETER SafeSearchQuery
   Wildcard value that will limit the metrics to only target records that match the searchquery via safe name
.PARAMETER PlatformSearchQuery
   Wildcard value that will limit the metrics to only target records that match the searchquery via platformID
.PARAMETER UsernameSearchQuery
   Wildcard value that will limit the metrics to only target records that match the searchquery via account username
.PARAMETER InputParameters
   HashTable of values containing the parameters required to make the API call
.EXAMPLE
   $GenerateReport = Invoke-VPASMetricsProviders -TargetMetric AccountsPulledViaApplicationID -MetricFormat ALL -OutputDirectory C:\Temp\Metrics\ProviderMetrics -HTMLChart ALL
.EXAMPLE
   $GenerateReport = Invoke-VPASMetricsProviders -TargetMetric ApplicationIDsOnSafes -MetricFormat ALL -OutputDirectory C:\Temp\Metrics\ProviderMetrics -HTMLChart ALL
.EXAMPLE
   $InputParameters = @{
        TargetMetric = "ApplicationIDsOnSafes"|"AccountsPulledViaApplicationID"
        MetricFormat = "JSON"|"HTML"|"ALL"|"NONE"
        OutputDirectory = "C:\temp\ReportOutputs"
        HTMLChart = "BarGraph"|"LineGraph"|"PieChart"|"ALL"
        HideRawData = $true|$false
        IgnoreSafes = @("VaultInternal","System")
        IgnorePlatforms = @("WinDomain","WinLocal")
        IgnoreUsernames = @("IgnoreUsername1")
        SafeSearchQuery = @("vman-","vpas-")
        PlatformSearchQuery = @("norotate","store")
        UsernameSearchQuery = @("TargetUser1","TargetUser3")
   }
   $GenerateReport = Invoke-VPASMetricsProviders -InputParameters $InputParameters
.OUTPUTS
   HashTable object if successful
   ---
   $false if failed
#>

function Invoke-VPASMetricsProviders{
    [OutputType([bool])]
    [CmdletBinding(DefaultParameterSetName='Set1')]
    Param(

        [Parameter(Mandatory=$true,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true,HelpMessage="Enter TargetMetric to be generated (ApplicationIDsOnSafes, AccountsPulledViaApplicationID)")]
        [ValidateSet('ApplicationIDsOnSafes','AccountsPulledViaApplicationID')]
        [String]$TargetMetric,

        [Parameter(Mandatory=$true,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true,HelpMessage="Enter ReportOutput type (JSON, HTML, ALL, NONE)")]
        [ValidateSet('JSON','HTML','ALL','NONE')]
        [String]$MetricFormat,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [String]$OutputDirectory,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [ValidateSet('BarGraph','LineGraph','PieChart','ALL')]
        [String]$HTMLChart,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [switch]$HideRawData,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [String[]]$IgnoreSafes,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [String[]]$IgnorePlatforms,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [String[]]$IgnoreUsernames,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [String[]]$SafeSearchQuery,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [String[]]$PlatformSearchQuery,

        [Parameter(Mandatory=$false,ParameterSetName='Set1',ValueFromPipelineByPropertyName=$true)]
        [String[]]$UsernameSearchQuery,

        [Parameter(Mandatory=$true,ParameterSetName='InputParameters',ValueFromPipelineByPropertyName=$true,HelpMessage="Hashtable of parameters required to make API call, refer to get-help -examples for valid inputs")]
        [hashtable]$InputParameters,

        [Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true)]
        [hashtable]$token
    )

    Begin{
        $tokenval,$sessionval,$PVWA,$Header,$ISPSS,$IdentityURL,$EnableTextRecorder,$AuditTimeStamp,$NoSSL,$VaultVersion,$HideWarnings,$AuthenticatedAs,$SubDomain,$EnableTroubleshooting = Get-VPASSession -token $token
        $CommandName = $MyInvocation.MyCommand.Name
        $log = Write-VPASTextRecorder -inputval $CommandName -token $token -LogType COMMAND
    }
    Process{

        try{
            if($PSCmdlet.ParameterSetName -eq "InputParameters"){
                $KeyHash = @{
                    set1 = @{
                        AcceptableKeys = @("TargetMetric","MetricFormat","OutputDirectory","HTMLChart","HideRawData","IgnoreSafes","IgnorePlatforms","IgnoreUsernames","SafeSearchQuery","PlatformSearchQuery","UsernameSearchQuery")
                        MandatoryKeys = @("TargetMetric","MetricFormat")
                    }
                }
                $CheckSet = Test-VPASHashtableKeysHelper -InputHash $InputParameters -KeyHash $KeyHash

                if(!$CheckSet){
                    $log = Write-VPASTextRecorder -inputval "FAILED TO FIND TARGET PARAMETER SET" -token $token -LogType MISC
                    Write-Verbose "FAILED TO FIND TARGET PARAMETER SET"
                    Write-VPASOutput -str "FAILED TO FIND TARGET PARAMETER SET...VIEW EXAMPLES BELOW:" -type E
                    $examples = Write-VPASExampleHelper -CommandName $CommandName
                    return $false
                }
                else{
                    foreach($key in $InputParameters.Keys){
                        Set-Variable -Name $key -Value $InputParameters.$key
                    }
                }
            }
        }catch{
            $log = Write-VPASTextRecorder -inputval $_ -token $token -LogType ERROR
            $log = Write-VPASTextRecorder -inputval "REST API COMMAND RETURNED: FALSE" -token $token -LogType MISC
            Write-Verbose "FAILED TO INVOKE METRIC"
            Write-VPASOutput -str $_ -type E
            return $false
        }

        try{
            $SkipPlatformsSTR = ""
            foreach($rec in $IgnorePlatforms){
                $SkipPlatformsSTR += "*" + $rec + "*; "
            }
            $SkipUsernameSTR = ""
            foreach($rec in $IgnoreUsernames){
                $SkipUsernameSTR += "*" + $rec + "*; "
            }
            $SkipSafeSTR = ""
            foreach($rec in $IgnoreSafes){
                $SkipSafeSTR += "*" + $rec + "*; "
            }
            $TargetSafeSTR = ""
            foreach($rec in $SafeSearchQuery){
                $TargetSafeSTR += "*" + $rec + "*; "
            }
            $TargetPlatformSTR = ""
            foreach($rec in $PlatformSearchQuery){
                $TargetPlatformSTR += "*" + $rec + "*; "
            }
            $TargetUsernameSTR = ""
            foreach($rec in $UsernameSearchQuery){
                $TargetUsernameSTR += "*" + $rec + "*; "
            }

            if($MetricFormat -ne "NONE"){
                if([String]::IsNullOrEmpty($OutputDirectory)){
                    $curUser = $env:UserName
                    $OutputDirectory = "C:\Users\$curUser\AppData\Local\VPASModuleOutputs\Metrics"
                    Write-Verbose "NO OUTPUT DIRECTORY SUPPLIED, USING DEFAULT LOCATION: $OutputDirectory"

                    if(Test-Path -Path $OutputDirectory){
                        #DO NOTHING
                    }
                    else{
                        write-verbose "$OutputDirectory DOES NOT EXIST, CREATING DIRECTORY"
                        $MakeDirectory = New-Item -Path $OutputDirectory -Type Directory
                    }
                }
                else{
                    if(Test-Path -Path $OutputDirectory){
                        #DO NOTHING
                    }
                    else{
                        $curUser = $env:UserName
                        $OutputDirectory = "C:\Users\$curUser\AppData\Local\VPASModuleOutputs\Metrics"
                        write-verbose "$OutputDirectory DOES NOT EXIST, USING DEFAULT LOCATION: $OutputDirectory"
                        if(Test-Path -Path $OutputDirectory){
                            #DO NOTHING
                        }
                        else{
                            $MakeDirectory = New-Item -Path $OutputDirectory -Type Directory
                        }
                    }
                }
            }

            if([String]::IsNullOrEmpty($HTMLChart)){
                $HTMLChart = "BarGraph"
            }

            if($TargetMetric -eq "ApplicationIDsOnSafes"){
                $tagout = "safes"
                #INITIALIZE HASH
                $OutputHash = @{}

                $AllAppIDs = Get-VPASAllApplications
                if(!$AllAppIDs){
                    Write-Verbose "FAILED TO PULL ALL APPLICATION IDS"
                    Write-VPASOutput -str "FAILED TO PULL ALL APPLICATION IDS" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                else{
                    $AllAppIDsArr = @()
                    foreach($appID in $AllAppIDs.AppID){
                        $targetAppID = $appID
                        $OutputHash += @{
                            $targetAppID = @{
                                Safes = @()
                                RawData = @()
                                counter = 0
                            }
                        }
                        $AllAppIDsArr += $targetAppID
                    }
                }

                $AllEPVGroups = Get-VPASAllEPVGroups -IncludeMembers
                if(!$AllEPVGroups){
                    Write-Verbose "FAILED TO PULL ALL EPV GROUPS"
                    Write-VPASOutput -str "FAILED TO PULL ALL EPV GROUPS" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                else{
                    $EPVGroupMatrix = @{}
                    foreach($group in $AllEPVGroups.value){
                        $GroupName = $group.groupName
                        $GroupMembers = $group.members
                        foreach($mem in $GroupMembers.username){
                            if($AllAppIDsArr.Contains($mem)){
                                if($EPVGroupMatrix.$GroupName){
                                    $EPVGroupMatrix.$GroupName.Members += $mem
                                }
                                else{
                                    $EPVGroupMatrix += @{
                                        $GroupName = @{
                                            Members = @($mem)
                                        }
                                    }
                                }
                            }
                        }
                    }
                }


                if($SafeSearchQuery.count -gt 0){
                    $SafeMatrix = @()
                    $AllSafes = @{
                        value = @()
                        count = 0
                    }
                    foreach($query in $SafeSearchQuery){
                        $smallquery = Get-VPASSafes -searchQuery $query
                        foreach($rec in $smallquery.value){
                            $recSafeName = $rec.safename
                            if(!$SafeMatrix.Contains($recSafeName)){
                                $AllSafes.value += $rec
                                $AllSafes.Count += 1
                                $SafeMatrix += $recSafeName
                            }
                        }
                    }
                }
                else{
                    $AllSafes = Get-VPASAllSafes
                }
                if(!$AllSafes){
                    Write-Verbose "FAILED TO RETRIEVE SAFES"
                    Write-VPASOutput -str "FAILED TO RETRIEVE SAFES" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                else{
                    foreach($safe in $AllSafes.value){
                        $targetSafeName = $safe.safeName
                        $skipval = $false

                        if(!$skipval){
                            foreach($ignoreval in $IgnoreSafes){
                                if($targetSafeName -match $ignoreval){
                                    Write-Verbose "SKIPPING $targetSafeName : SKIP VALUE $ignoreval FOUND IN SAFE $targetSafeName"
                                    $skipval = $true
                                }
                            }
                        }

                        if(!$skipval){
                            $AllSafeMembers = Get-VPASSafeMembers -safe $targetSafeName -IncludePredefinedMembers
                            if($AllSafeMembers){
                                foreach($mem in $AllSafeMembers.value){
                                    $targetMember = $mem.memberName
                                    if($AllAppIDsArr.Contains($targetMember)){
                                        $OutputHash.$targetMember.counter += 1
                                        $OutputHash.$targetMember.Safes += $targetSafeName
                                        $OutputHash.$targetMember.RawData += $safe
                                    }
                                    elseif($EPVGroupMatrix.$targetMember){
                                        $CheckArr = $EPVGroupMatrix.$targetMember.Members
                                        foreach($ArrCheck in $CheckArr){
                                            $OutputHash.$ArrCheck.counter += 1
                                            $OutputHash.$ArrCheck.Safes += $targetSafeName
                                            $OutputHash.$ArrCheck.RawData += $safe
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if($MetricFormat -eq "JSON" -or $MetricFormat -eq "ALL"){
                    $outputfile = "$OutputDirectory/ApplicationIDsOnSafes.json"
                    $OutputDataJSON = $OutputHash | ConvertTo-Json -Depth 100
                    Write-Output $OutputDataJSON | Set-Content $outputfile
                }
                if($MetricFormat -eq "NONE"){
                    $htmlData += @{
                        datahash = $OutputHash
                    }
                }
                if($MetricFormat -eq "HTML" -or $MetricFormat -eq "ALL"){
                    $outputfile = "$OutputDirectory/ApplicationIDsOnSafes.html"
                    $titlesplit = "ApplicationIDs on Safes"
                    $metricTag = "Provider Metrics"
                    $recommendation1 = "An ApplicationID is a critical component of CyberArk's Application Access Manager (AAM), enabling secure and controlled access to sensitive credentials without hardcoding them into applications or scripts"
                    $recommendation2 = "By using AAM, organizations can avoid hardcoding credentials in application code, configuration files, or scripts, which significantly reduces the risk of credential exposure, and decreases the amount of dependencies needed to update if the credential changes"
                    $recommendation3 = "AAM allows the creation of detailed policies that control which applications can access specific credentials, ensuring that only authorized applications have access based on predefined criteria"
                    $OutputDataJSON = $OutputHash | ConvertTo-Json -Depth 100
                    $curTime = get-date -Format "MM/dd/yyyy HH:mm:ss"
                    if($HTMLChart -eq "ALL"){
                        $tablestr = "Bar Graph, Line Graph, Pie Chart"
                    }
                    else{
                        $tablestr = $HTMLChart
                    }
                    $metricexplanation = "This metric tracks the number of safes that contain individual ApplicationIDs as safe members. This metric will count a safe twice if multiple ApplicationIDs are found as safe members"

                    $tempstr = ""
                    $tempstr2 = ""
                    $tempstr3 = ""
                    $tempstr4 = ""
                    $AllKeys = $OutputHash.Keys
                    $GetMinMax = @()

                    foreach($key in $AllKeys){
                        $curCount = $OutputHash.$key.counter
                        $GetMinMax += $curCount
                        $textColor =  '#{0:X6}' -f (Get-Random -Maximum 0x1000000)

                        $tempstr += "`"$key`","
                        $tempstr2 += "$curCount,"
                        $tempstr3 += "`"green`","
                        $tempstr4 += "`"$textColor`","
                    }

                    if($GetMinMax.count -ne 0){
                        $GetMinMax = $GetMinMax | Sort-Object
                        $mintick = 0
                        $maxtick = $GetMinMax[$GetMinMax.Count - 1]
                    }
                    else{
                        $mintick = 0
                        $maxtick = 0
                    }

                    if(![String]::IsNullOrEmpty($tempstr)){
                        $tempstr = $tempstr.Substring(0,$tempstr.Length-1)
                    }
                    if(![String]::IsNullOrEmpty($tempstr2)){
                        $tempstr2 = $tempstr2.Substring(0,$tempstr2.Length-1)
                    }
                    if(![String]::IsNullOrEmpty($tempstr3)){
                        $tempstr3 = $tempstr3.Substring(0,$tempstr3.Length-1)
                    }
                    if(![String]::IsNullOrEmpty($tempstr4)){
                        $tempstr4 = $tempstr4.Substring(0,$tempstr4.Length-1)
                    }

                    $htmlData += @{
                        Recommendation1 = $recommendation1
                        Recommendation2 = $recommendation2
                        Recommendation3 = $recommendation3
                        titlesplit = $titlesplit
                        outputfile = $outputfile
                        metricTag = $metricTag
                        OutputDataJSON = $OutputDataJSON
                        curTime = $curTime
                        tablestr = $tablestr
                        metricexplanation = $metricexplanation
                        HTMLChart = $HTMLChart
                        tempstr = $tempstr
                        tempstr2 = $tempstr2
                        tempstr3 = $tempstr3
                        tempstr4 = $tempstr4
                        datahash = $OutputHash
                        maxtick = $maxtick
                        mintick = $mintick
                    }
                }
            }
            if($TargetMetric -eq "AccountsPulledViaApplicationID"){
                $tagout = "accounts"
                #INITIALIZE HASH
                $OutputHash = @{}

                $AllAppIDs = Get-VPASAllApplications
                if(!$AllAppIDs){
                    Write-Verbose "FAILED TO PULL ALL APPLICATION IDS"
                    Write-VPASOutput -str "FAILED TO PULL ALL APPLICATION IDS" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                else{
                    $AllAppIDsArr = @()
                    foreach($appID in $AllAppIDs.AppID){
                        $targetAppID = $appID
                        $OutputHash += @{
                            $targetAppID = @{
                                Accounts = @()
                                RawData = @()
                                counter = 0
                            }
                        }
                        $AllAppIDsArr += $targetAppID
                    }
                }

                $AllEPVGroups = Get-VPASAllEPVGroups -IncludeMembers
                if(!$AllEPVGroups){
                    Write-Verbose "FAILED TO PULL ALL EPV GROUPS"
                    Write-VPASOutput -str "FAILED TO PULL ALL EPV GROUPS" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                else{
                    $EPVGroupMatrix = @{}
                    foreach($group in $AllEPVGroups.value){
                        $GroupName = $group.groupName
                        $GroupMembers = $group.members
                        foreach($mem in $GroupMembers.username){
                            if($AllAppIDsArr.Contains($mem)){
                                if($EPVGroupMatrix.$GroupName){
                                    $EPVGroupMatrix.$GroupName.Members += $mem
                                }
                                else{
                                    $EPVGroupMatrix += @{
                                        $GroupName = @{
                                            Members = @($mem)
                                        }
                                    }
                                }
                            }
                        }
                    }
                }


                if($SafeSearchQuery.count -gt 0){
                    $SafeMatrix = @()
                    $AllSafes = @{
                        value = @()
                        count = 0
                    }
                    foreach($query in $SafeSearchQuery){
                        $smallquery = Get-VPASSafes -searchQuery $query
                        foreach($rec in $smallquery.value){
                            $recSafeName = $rec.safename
                            if(!$SafeMatrix.Contains($recSafeName)){
                                $AllSafes.value += $rec
                                $AllSafes.Count += 1
                                $SafeMatrix += $recSafeName
                            }
                        }
                    }
                }
                else{
                    $AllSafes = Get-VPASAllSafes
                }
                if(!$AllSafes){
                    Write-Verbose "FAILED TO RETRIEVE SAFES"
                    Write-VPASOutput -str "FAILED TO RETRIEVE SAFES" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                else{
                    foreach($safe in $AllSafes.value){
                        $targetSafeName = $safe.safeName
                        $skipval = $false

                        if(!$skipval){
                            foreach($ignoreval in $IgnoreSafes){
                                if($targetSafeName -match $ignoreval){
                                    Write-Verbose "SKIPPING $targetSafeName : SKIP VALUE $ignoreval FOUND IN SAFE $targetSafeName"
                                    $skipval = $true
                                }
                            }
                        }

                        if(!$skipval){
                            $AllSafeMembers = Get-VPASSafeMembers -safe $targetSafeName -IncludePredefinedMembers
                            if($AllSafeMembers){
                                foreach($mem in $AllSafeMembers.value){
                                    $targetMember = $mem.memberName
                                    if($AllAppIDsArr.Contains($targetMember)){
                                        #GET ALL ACCOUNTS HERE
                                        $AllAccts = Get-VPASAccountDetails -safe $targetSafeName -ExactMatch
                                        foreach($recacct in $AllAccts.value){
                                            $validtargetplatform = $false
                                            $validtargetsafe = $false
                                            $validtargetusername = $false
                                            $targetPlat = $recacct.platformID
                                            $targetSafe = $recacct.safeName
                                            $targetUsername = $recacct.userName
                                            $targetAccountName = $recacct.name
                                            $skipval = $false

                                            if($PlatformSearchQuery.Count -eq 0){
                                                $validtargetplatform = $true
                                            }
                                            else{
                                                foreach($query in $PlatformSearchQuery){
                                                    if($targetPlat -match $query){
                                                        $validtargetplatform = $true
                                                    }
                                                }
                                            }

                                            if($UsernameSearchQuery.Count -eq 0){
                                                $validtargetusername = $true
                                            }
                                            else{
                                                foreach($query in $UsernameSearchQuery){
                                                    if($targetUsername -match $query){
                                                        $validtargetusername = $true
                                                    }
                                                }
                                            }

                                            if($SafeSearchQuery.Count -eq 0){
                                                $validtargetsafe = $true
                                            }
                                            else{
                                                foreach($query in $SafeSearchQuery){
                                                    if($targetSafe -match $query){
                                                        $validtargetsafe = $true
                                                    }
                                                }
                                            }

                                            if(!$validtargetplatform -or !$validtargetsafe -or !$validtargetusername){
                                                $skipval = $true
                                            }

                                            if(!$skipval){
                                                foreach($ignoreval in $IgnoreSafes){
                                                    if($targetSafe -match $ignoreval){
                                                        Write-Verbose "SKIPPING $targetAccountName : SKIP VALUE $ignoreval FOUND IN SAFE $targetSafe"
                                                        $skipval = $true
                                                    }
                                                }
                                            }

                                            if(!$skipval){
                                                foreach($ignoreval in $IgnorePlatforms){
                                                    if($targetPlat -match $ignoreval){
                                                        Write-Verbose "SKIPPING $targetAccountName : SKIP VALUE $ignoreval FOUND IN PLATFORM $targetPlat"
                                                        $skipval = $true
                                                    }
                                                }
                                            }

                                            if(!$skipval){
                                                foreach($ignoreval in $IgnoreUsernames){
                                                    if($targetUsername -match $ignoreval){
                                                        Write-Verbose "SKIPPING $targetAccountName : SKIP VALUE $ignoreval FOUND IN USERNAME $targetUsername"
                                                        $skipval = $true
                                                    }
                                                }
                                            }

                                            if(!$skipval){
                                                $AcctID = $recacct.id
                                                $OutputHash.$targetMember.counter += 1
                                                $OutputHash.$targetMember.Accounts += $AcctID
                                                $OutputHash.$targetMember.RawData += $recacct
                                            }
                                        }
                                    }
                                    elseif($EPVGroupMatrix.$targetMember){
                                        $CheckArr = $EPVGroupMatrix.$targetMember.Members
                                        foreach($ArrCheck in $CheckArr){
                                            #GET ALL ACCOUNTS HERE
                                            $AllAccts = Get-VPASAccountDetails -safe $targetSafeName -ExactMatch
                                            foreach($recacct in $AllAccts.value){
                                                $validtargetplatform = $false
                                                $validtargetsafe = $false
                                                $validtargetusername = $false
                                                $targetPlat = $recacct.platformID
                                                $targetSafe = $recacct.safeName
                                                $targetUsername = $recacct.userName
                                                $targetAccountName = $recacct.name
                                                $skipval = $false

                                                if($PlatformSearchQuery.Count -eq 0){
                                                    $validtargetplatform = $true
                                                }
                                                else{
                                                    foreach($query in $PlatformSearchQuery){
                                                        if($targetPlat -match $query){
                                                            $validtargetplatform = $true
                                                        }
                                                    }
                                                }

                                                if($UsernameSearchQuery.Count -eq 0){
                                                    $validtargetusername = $true
                                                }
                                                else{
                                                    foreach($query in $UsernameSearchQuery){
                                                        if($targetUsername -match $query){
                                                            $validtargetusername = $true
                                                        }
                                                    }
                                                }

                                                if($SafeSearchQuery.Count -eq 0){
                                                    $validtargetsafe = $true
                                                }
                                                else{
                                                    foreach($query in $SafeSearchQuery){
                                                        if($targetSafe -match $query){
                                                            $validtargetsafe = $true
                                                        }
                                                    }
                                                }

                                                if(!$validtargetplatform -or !$validtargetsafe -or !$validtargetusername){
                                                    $skipval = $true
                                                }

                                                if(!$skipval){
                                                    foreach($ignoreval in $IgnoreSafes){
                                                        if($targetSafe -match $ignoreval){
                                                            Write-Verbose "SKIPPING $targetAccountName : SKIP VALUE $ignoreval FOUND IN SAFE $targetSafe"
                                                            $skipval = $true
                                                        }
                                                    }
                                                }

                                                if(!$skipval){
                                                    foreach($ignoreval in $IgnorePlatforms){
                                                        if($targetPlat -match $ignoreval){
                                                            Write-Verbose "SKIPPING $targetAccountName : SKIP VALUE $ignoreval FOUND IN PLATFORM $targetPlat"
                                                            $skipval = $true
                                                        }
                                                    }
                                                }

                                                if(!$skipval){
                                                    foreach($ignoreval in $IgnoreUsernames){
                                                        if($targetUsername -match $ignoreval){
                                                            Write-Verbose "SKIPPING $targetAccountName : SKIP VALUE $ignoreval FOUND IN USERNAME $targetUsername"
                                                            $skipval = $true
                                                        }
                                                    }
                                                }

                                                if(!$skipval){
                                                    $AcctID = $recacct.id
                                                    $OutputHash.$targetMember.counter += 1
                                                    $OutputHash.$targetMember.Accounts += $AcctID
                                                    $OutputHash.$targetMember.RawData += $recacct
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                if($MetricFormat -eq "JSON" -or $MetricFormat -eq "ALL"){
                    $outputfile = "$OutputDirectory/AccountsPulledViaApplicationID.json"
                    $OutputDataJSON = $OutputHash | ConvertTo-Json -Depth 100
                    Write-Output $OutputDataJSON | Set-Content $outputfile
                }
                if($MetricFormat -eq "NONE"){
                    $htmlData += @{
                        datahash = $OutputHash
                    }
                }
                if($MetricFormat -eq "HTML" -or $MetricFormat -eq "ALL"){
                    $outputfile = "$OutputDirectory/AccountsPulledViaApplicationID.html"
                    $titlesplit = "Accounts Pulled via ApplicationIDs"
                    $metricTag = "Provider Metrics"
                    $recommendation1 = "An ApplicationID is a critical component of CyberArk's Application Access Manager (AAM), enabling secure and controlled access to sensitive credentials without hardcoding them into applications or scripts"
                    $recommendation2 = "By using AAM, organizations can avoid hardcoding credentials in application code, configuration files, or scripts, which significantly reduces the risk of credential exposure, and decreases the amount of dependencies needed to update if the credential changes"
                    $recommendation3 = "AAM allows the creation of detailed policies that control which applications can access specific credentials, ensuring that only authorized applications have access based on predefined criteria"
                    $OutputDataJSON = $OutputHash | ConvertTo-Json -Depth 100
                    $curTime = get-date -Format "MM/dd/yyyy HH:mm:ss"
                    if($HTMLChart -eq "ALL"){
                        $tablestr = "Bar Graph, Line Graph, Pie Chart"
                    }
                    else{
                        $tablestr = $HTMLChart
                    }
                    $metricexplanation = "This metric tracks the number of accounts that can be pulled via specific ApplicationIDs. This metric will count an account twice if multiple ApplicationIDs are found as safe members"

                    $tempstr = ""
                    $tempstr2 = ""
                    $tempstr3 = ""
                    $tempstr4 = ""
                    $AllKeys = $OutputHash.Keys
                    $GetMinMax = @()

                    foreach($key in $AllKeys){
                        $curCount = $OutputHash.$key.counter
                        $GetMinMax += $curCount
                        $textColor =  '#{0:X6}' -f (Get-Random -Maximum 0x1000000)

                        $tempstr += "`"$key`","
                        $tempstr2 += "$curCount,"
                        $tempstr3 += "`"green`","
                        $tempstr4 += "`"$textColor`","
                    }

                    if($GetMinMax.count -ne 0){
                        $GetMinMax = $GetMinMax | Sort-Object
                        $mintick = 0
                        $maxtick = $GetMinMax[$GetMinMax.Count - 1]
                    }
                    else{
                        $mintick = 0
                        $maxtick = 0
                    }

                    if(![String]::IsNullOrEmpty($tempstr)){
                        $tempstr = $tempstr.Substring(0,$tempstr.Length-1)
                    }
                    if(![String]::IsNullOrEmpty($tempstr2)){
                        $tempstr2 = $tempstr2.Substring(0,$tempstr2.Length-1)
                    }
                    if(![String]::IsNullOrEmpty($tempstr3)){
                        $tempstr3 = $tempstr3.Substring(0,$tempstr3.Length-1)
                    }
                    if(![String]::IsNullOrEmpty($tempstr4)){
                        $tempstr4 = $tempstr4.Substring(0,$tempstr4.Length-1)
                    }

                    $htmlData += @{
                        Recommendation1 = $recommendation1
                        Recommendation2 = $recommendation2
                        Recommendation3 = $recommendation3
                        titlesplit = $titlesplit
                        outputfile = $outputfile
                        metricTag = $metricTag
                        OutputDataJSON = $OutputDataJSON
                        curTime = $curTime
                        tablestr = $tablestr
                        metricexplanation = $metricexplanation
                        HTMLChart = $HTMLChart
                        tempstr = $tempstr
                        tempstr2 = $tempstr2
                        tempstr3 = $tempstr3
                        tempstr4 = $tempstr4
                        datahash = $OutputHash
                        maxtick = $maxtick
                        mintick = $mintick
                    }
                }
            }

            $datahash = $htmlData.datahash
            if($MetricFormat -eq "HTML" -or $MetricFormat -eq "ALL"){

                #OUTPUT DATA IN A PRETTY HTML
write-output "
<!DOCTYPE html>
<html>
<head>
<title>$TargetMetric</title>
<style>
    body {
        font-family: Arial, sans-serif;
        background-color: #c0c0c0;
        margin: 0;
        padding: 20px;
    }
    .metrics-container3 {
        background-color: #333;
        border-radius: 16px;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        padding: 20px;
        margin: 0;
        color: white;
        font-size: 24px;
        font-weight: bold;
        Text-align: center;
    }
    .metrics-container2 {
        background-color: #333;
        border-radius: 16px;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        padding: 20px;
        margin: 0;
        color: white;
    }
    .metrics-container {
        background-color: #fff;
        border-radius: 16px;
        box-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
        padding: 20px;
        margin: 0;
    }
    .metric {
        margin-bottom: 10px;
    }
    .metric-label {
        font-weight: bold;
    }
</style>
</head>
<script src=`"https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.9.4/Chart.js`"></script>
<body>
<div style=`"max-width: 1200px; width: 100%; margin: 0 auto;`">
    <div style=`"width: 95%; margin-right: 1%; margin-left: 1%`" class=`"metrics-container3`">
        $titlesplit <small><small>(Powered By Vpas)</small></small>
    </div>
    <br>
    <div style=`"display: flex; width: 99%;`">
        <div style=`"width:48%; margin-left: 1%; margin-right: 1%;`" class=`"metrics-container`">
            <div class=`"metric`">
                <span class=`"metric-label`">Generated By:</span> $AuthenticatedAs
            </div>
            <div class=`"metric`">
                <span class=`"metric-label`">Generated Date:</span> $curTime
            </div>
            <div class=`"metric`">
                <span class=`"metric-label`">Metric Category:</span> $metricTag
            </div>
            <div class=`"metric`">
                <span class=`"metric-label`">Output Table(s):</span> $tablestr
            </div>
"
 | Set-content $outputfile
                if(![String]::IsNullOrEmpty($TargetSafeSTR)){
write-output "
            <div class=`"metric`">
                <span class=`"metric-label`">Target Safe(s):</span> $TargetSafeSTR
            </div>
"
 | Add-content $outputfile
                }
                if(![String]::IsNullOrEmpty($TargetPlatformSTR)){
write-output "
            <div class=`"metric`">
                <span class=`"metric-label`">Target Platform(s):</span> $TargetPlatformSTR
            </div>
"
 | Add-content $outputfile
                }
                if(![String]::IsNullOrEmpty($TargetUsernameSTR)){
write-output "
            <div class=`"metric`">
                <span class=`"metric-label`">Target Username(s):</span> $TargetUsernameSTR
            </div>
"
 | Add-content $outputfile
                }
                if(![String]::IsNullOrEmpty($SkipPlatformsSTR)){
write-output "
            <div class=`"metric`">
                <span class=`"metric-label`">Ignore Platform(s):</span> $SkipPlatformsSTR
            </div>
"
 | Add-content $outputfile
                }
                if(![String]::IsNullOrEmpty($SkipUsernameSTR)){
write-output "
            <div class=`"metric`">
                <span class=`"metric-label`">Ignore Username(s):</span> $SkipUsernameSTR
            </div>
"
 | Add-content $outputfile
                }
                if(![String]::IsNullOrEmpty($SkipSafeSTR)){
write-output "
            <div class=`"metric`">
                <span class=`"metric-label`">Ignore Safe(s):</span> $SkipSafeSTR
            </div>
"
 | Add-content $outputfile
                }

write-output "
        </div>
 
        <div style=`"width:48%; margin-left: 1%; margin-right: 1;%`" class=`"metrics-container`">
            <div class=`"metric`">
                <span class=`"metric-label`">Metric Type:</span><small> $titlesplit</small>
            </div>
            <div class=`"metric`">
                <span class=`"metric-label`">Explanation:</span> <small>$metricexplanation</small>
            </div>
        </div>
    </div>
    <br>
"
 | Add-content $outputfile

                if($HTMLChart -eq "BarGraph" -or $HTMLChart -eq "ALL"){
                    write-output "<div style=`"max-width:95%; margin-right: 1%; margin-left: 1%`"class=`"metrics-container`"><canvas height=`"500%`" id=`"myChartBAR`" style=`"width:100%;`"></canvas></div>`n<br><br>`n" | Add-Content $outputfile
                }
                if($HTMLChart -eq "LineGraph" -or $HTMLChart -eq "ALL"){
                    write-output "<div style=`"max-width:95%; margin-right: 1%; margin-left: 1%`"class=`"metrics-container`"><canvas height=`"500%`" id=`"myChartLINE`" style=`"width:100%;`"></canvas></div>`n<br><br>`n"| Add-Content $outputfile
                }
                if($HTMLChart -eq "PieChart" -or $HTMLChart -eq "ALL"){
                    write-output "<div style=`"max-width:95%; margin-right: 1%; margin-left: 1%`"class=`"metrics-container`"><canvas height=`"500%`" id=`"myChartPIE`" style=`"width:100%;`"></canvas></div>`n<br><br>`n"| Add-Content $outputfile
                }

Write-Output "
    <div style=`"display: flex;`">
        <div style=`"width:33%; margin-right: 1%; margin-left: 1%`" class=`"metrics-container`">
            <div class=`"metric`">
                <span class=`"metric-label`">Totals:</span>
            </div>
"
 | Add-Content $outputfile

                if($TargetMetric -eq "AccountsOnboardedXDays"){
                    $countkeys = $datahash.Keys.Count
                    $i = 1
                    while($i -le $countkeys){
                        $Max = $datahash."Set$i".Max
                        $Min = $datahash."Set$i".Min
                        $curCount = $datahash."Set$i".Count
Write-Output "
            <div class=`"metric`">
                <span class=`"metric-label`"><small>&emsp;Set$i) $Max-$Min`:</small></span><small> $curCount $tagout</small>
            </div>
"
 | Add-Content $outputfile
                        $i += 1
                    }
                }
                else{
                    foreach($key in $datahash.Keys){
                        $curCount = $datahash."$key".counter

Write-Output "
            <div class=`"metric`">
                <span class=`"metric-label`"><small>&emsp;$key`:</small></span><small> $curCount $tagout</small>
            </div>
"
 | Add-Content $outputfile
                    }
                }

Write-Output "
        </div>
        <div style=`"max-width:58%; width: 68%; margin-right: 1%; margin-left: 1%`" class=`"metrics-container`">
            <div class=`"metric`">
                <span class=`"metric-label`">Recommendations:</span>
            </div>
            <div class=`"metric`">
                <span class=`"metric-label`"><small>&emsp;1)</small></span> <small>$recommendation1</small>
            </div>
            <div class=`"metric`">
                <span class=`"metric-label`"><small>&emsp;2)</small></span> <small>$recommendation2</small>
            </div>
            <div class=`"metric`">
                <span class=`"metric-label`"><small>&emsp;3)</small></span> <small>$recommendation3</small>
            </div>
        </div>
    </div>
    <br>
"
 | Add-Content $outputfile
if(!$HideRawData){
Write-Output "
    <div style=`"max-width:95%; width: 95%; margin-right: 1%; margin-left: 1%`" class=`"metrics-container`">
        <div class=`"metric`">
            <span class=`"metric-label`">Raw Data:</span>
            <div><button onclick=`"copyText()`">Copy JSON</button></div>
            <br>
            <div style=`"max-width:95%; width: 95%; margin-right: 1%; margin-left: 1%`" class=`"metrics-container2`">
            <span id=`"CopyText`" ><small>$OutputDataJSON</small></span>
            </div>
        </div>
    </div>
"
 | Add-Content $outputfile
}

Write-Output "
</div>
<script>
"
 | Add-Content $outputfile
                if($HTMLChart -eq "BarGraph" -or $HTMLChart -eq "ALL"){
                    write-output "const xValuesBAR = [$tempstr];" | Add-Content $outputfile
                    write-output "const yValuesBAR = [$tempstr2];" | Add-Content $outputfile
                    write-output "const barColorsBAR = [$tempstr3];" | Add-Content $outputfile
                }
                if($HTMLChart -eq "LineGraph" -or $HTMLChart -eq "ALL"){
                    write-output "const xValuesLINE = [$tempstr];" | Add-Content $outputfile
                    write-output "const yValuesLINE = [$tempstr2];" | Add-Content $outputfile
                }
                if($HTMLChart -eq "PieChart" -or $HTMLChart -eq "ALL"){
                    write-output "const xValuesPIE = [$tempstr];" | Add-Content $outputfile
                    write-output "const yValuesPIE = [$tempstr2];" | Add-Content $outputfile
                    write-output "const barColorsPIE = [$tempstr4];" | Add-Content $outputfile
                }

if($HTMLChart -eq "BarGraph" -or $HTMLChart -eq "ALL"){
#BAR
Write-Output "
new Chart(`"myChartBAR`", {
    type: `"bar`",
    data: {
        labels: xValuesBAR,
        datasets: [{
            backgroundColor: barColorsBAR,
            data: yValuesBAR
        }]
    },
    options: {
        scales: {
            yAxes: [{
                ticks: {
                    beginAtZero: true
                }
            }]
        },
        legend: {display: false},
        title: {
            display: true,
            text: `"$titlesplit`"
        }
    }
});
"
 | Add-Content $outputfile
}
if($HTMLChart -eq "LineGraph" -or $HTMLChart -eq "ALL"){
#LINE
Write-Output "
new Chart(`"myChartLINE`", {
    type: `"line`",
    data: {
        labels: xValuesLINE,
        datasets: [{
            label: `"$titlesplit`",
            fill: false,
            lineTension: 0,
            backgroundColor: `"rgba(0,0,255,1.0)`",
            borderColor: `"rgba(0,0,255,0.1)`",
            data: yValuesLINE
        }]
    },
    options: {
        legend: {display: true},
        scales: {
            yAxes: [{ticks: {min: $mintick, max:$maxtick}}],
        }
    }
});
"
 | Add-Content $outputfile
}
if($HTMLChart -eq "PieChart" -or $HTMLChart -eq "ALL"){
#PIE
write-output "
new Chart(`"myChartPIE`", {
    type: `"pie`",
    data: {
        labels: xValuesPIE,
        datasets: [{
            backgroundColor: barColorsPIE,
            data: yValuesPIE
        }]
    },
    options: {
        title: {
            display: true,
            text: `"$titlesplit`"
        }
    }
});
function copyText() {
        var copyText = document.getElementById(`"CopyText`");
        var textArea = document.createElement(`"textarea`");
        textArea.value = copyText.textContent;
        document.body.appendChild(textArea);
        textArea.select();
        document.execCommand(`"Copy`");
        textArea.remove();
        alert(`"JSON copied to clipboard`");
    }
"
 | Add-Content $outputfile
}


                write-output "</script>`n</body>`n</html>" | Add-Content $outputfile
            }
            return $datahash

        }catch{
            Write-Verbose "UNABLE TO RUN REPORT...RETURNING FALSE"
            Write-VPASOutput -str "UNABLE TO RUN REPORT...RETURNING FALSE" -type E
            Write-VPASOutput -str $_ -type E
            return $false
        }
    }
    End{
        $log = Write-VPASTextRecorder -inputval $CommandName -token $token -LogType DIVIDER
    }
}