public/Invoke-VPASMetricsPlatforms.ps1

<#
.Synopsis
   RUN VARIOUS PLATFORM METRICS FROM CYBERARK
   CREATED BY: Vadim Melamed, EMAIL: vmelamed5@gmail.com
.DESCRIPTION
   USE THIS FUNCTION TO GENERATE VARIOUS PLATFORM RELATED METRICS FROM CYBERARK
.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: AccountsAssignedToPlatforms, AutomaticVsManualRotation, AutomaticVsManualVerification
.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
.EXAMPLE
   $GenerateReport = Invoke-VPASMetricsPlatforms -TargetMetric AccountsAssignedToPlatforms -OutputDirectory "C:\temp\VPASMetrics" -MetricFormat ALL -HTMLChart ALL
.OUTPUTS
   HashTable object if successful
   $false if failed
#>

function Invoke-VPASMetricsPlatforms{
    [OutputType([bool])]
    [CmdletBinding()]
    Param(

        [Parameter(Mandatory=$true,ValueFromPipelineByPropertyName=$true,HelpMessage="Enter TargetMetric to be generated (AccountsAssignedToPlatforms, AutomaticVsManualRotation, AutomaticVsManualVerification)",Position=0)]
        [ValidateSet('AccountsAssignedToPlatforms','AutomaticVsManualRotation','AutomaticVsManualVerification')]
        [String]$TargetMetric,

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

        [Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,Position=2)]
        [String]$OutputDirectory,

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

        [Parameter(Mandatory=$false,ValueFromPipelineByPropertyName=$true,Position=4)]
        [switch]$HideRawData,

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

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

        Write-Verbose "SUCCESSFULLY PARSED PVWA VALUE"
        Write-Verbose "SUCCESSFULLY PARSED TOKEN VALUE"
        Write-Verbose "SUCCESSFULLY PARSED TARGET METRIC VALUE: $TargetMetric"
        Write-Verbose "SUCCESSFULLY PARSED METRIC OUTPUT VALUE: $MetricFormat"

        try{
            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 "AccountsAssignedToPlatforms"){
                $tagout = "accounts"
                #INITIALIZE HASH
                $OutputHash = @{}

                $AllAccounts = Get-VPASAllAccounts
                if(!$AllAccounts){
                    Write-Verbose "FAILED TO PULL ALL ACCOUNTS"
                    Write-VPASOutput -str "FAILED TO PULL ALL ACCOUNTS" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                foreach($acct in $AllAccounts.value){
                    $targetPlatformID = $acct.platformId
                    if([String]::IsNullOrEmpty($targetPlatformID)){ $targetPlatformID = "BLANK_PLATFORM" }

                    if($OutputHash.$targetPlatformID){
                        $OutputHash.$targetPlatformID.counter += 1
                        $OutputHash.$targetPlatformID.RawData += $acct
                    }
                    else{
                        $OutputHash += @{
                            $targetPlatformID = @{
                                counter = 1
                                RawData = @($acct)
                            }
                        }
                    }
                }

                $AllPlatforms = Get-VPASAllPlatforms
                foreach($plat in $AllPlatforms.Platforms){
                    $targetplatID = $plat.general.id
                    if([String]::IsNullOrEmpty($targetplatID)){ $targetplatID = "BLANK_PLATFORM" }
                    if($targetplatID -ne "BLANK_PLATFORM"){
                        $curActive = $plat.general.active
                        if($curActive){
                            if(!$OutputHash.$targetplatID){
                                $OutputHash += @{
                                    $targetplatID = @{
                                        counter = 0
                                        RawData = @()
                                    }
                                }
                            }
                        }
                    }
                    else{
                        if(!$OutputHash.$targetplatID){
                            $OutputHash += @{
                                $targetplatID = @{
                                    counter = 0
                                    RawData = @()
                                }
                            }
                        }
                    }
                }


                if($MetricFormat -eq "JSON" -or $MetricFormat -eq "ALL"){
                    $outputfile = "$OutputDirectory/AccountsAssignedToPlatforms.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/AccountsAssignedToPlatforms.html"
                    $titlesplit = "Amount of Accounts Assigned to Platforms"
                    $metricTag = "Platform Metrics"
                    $recommendation1 = "A platform is a set of configurations that defines how and when the system manages credentials and accesses for a particular type of system or application. Platforms are critical for ensuring secure and efficient means of management for privileged accounts."
                    $recommendation2 = "Frequent password rotation policies are a quick win for bolstering an organization's security posture. Avoid using platforms that do not support password rotation, or password storing type platforms, unless a plugin or integration is unavailable."
                    $recommendation3 = "Platforms without any associated accounts can be disabled or deleted to reduce clutter and streamline the environment."
                    $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 accounts assigned to which platforms. This metric will include disabled/inactive platforms if they contain accounts, but will ignore disabled/inactive platforms if they do not contain any accounts"

                    $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 "AutomaticVsManualRotation"){
                $tagout = "accounts"
                #INITIALIZE HASH
                $OutputHash = @{
                    Manual = @{
                        counter = 0
                    }
                    Automatic = @{
                        counter = 0
                    }
                }

                $AllAccounts = Get-VPASAllAccounts
                if(!$AllAccounts){
                    Write-Verbose "FAILED TO PULL ALL ACCOUNTS"
                    Write-VPASOutput -str "FAILED TO PULL ALL ACCOUNTS" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                foreach($acct in $AllAccounts.value){
                    $targetPlatformID = $acct.platformId
                    if([String]::IsNullOrEmpty($targetPlatformID)){ $targetPlatformID = "BLANK_PLATFORM" }

                    if($targetPlatformID -eq "BLANK_PLATFORM"){
                        if($OutputHash.Manual.$targetPlatformID){
                            $OutputHash.Manual.counter += 1
                            $OutputHash.Manual.$targetPlatformID.RawData += $acct
                        }
                        else{
                            $OutputHash.Manual += @{
                                $targetPlatformID = @{
                                    RawData = @($acct)
                                }
                            }
                            $OutputHash.Manual.counter += 1
                        }
                    }
                    else{
                        if($OutputHash.Manual.$targetPlatformID){
                            $OutputHash.Manual.counter += 1
                            $OutputHash.Manual.$targetPlatformID.RawData += $acct
                        }
                        elseif($OutputHash.Automatic.$targetPlatformID){
                            $OutputHash.Automatic.counter += 1
                            $OutputHash.Automatic.$targetPlatformID.RawData += $acct
                        }
                        else{
                            #GET PLATFORM DETAILS IN TERMS OF ROTATION
                            $AllPlatformDetails = Get-VPASPlatformDetails -platformID $targetPlatformID
                            $ChangeStyle = $AllPlatformDetails.Details.PerformPeriodicChange

                            if($ChangeStyle -eq "No"){
                                if($OutputHash.Manual.$targetPlatformID){
                                    $OutputHash.Manual.counter += 1
                                    $OutputHash.Manual.$targetPlatformID.RawData += $acct
                                }
                                else{
                                    $OutputHash.Manual += @{
                                        $targetPlatformID = @{
                                            RawData = @($acct)
                                        }
                                    }
                                    $OutputHash.Manual.counter += 1
                                }
                            }
                            elseif($ChangeStyle -eq "Yes"){
                                if($OutputHash.Automatic.$targetPlatformID){
                                    $OutputHash.Automatic.counter += 1
                                    $OutputHash.Automatic.$targetPlatformID.RawData += $acct
                                }
                                else{
                                    $OutputHash.Automatic += @{
                                        $targetPlatformID = @{
                                            RawData = @($acct)
                                        }
                                    }
                                    $OutputHash.Automatic.counter += 1
                                }
                            }
                        }
                    }
                }

                if($MetricFormat -eq "JSON" -or $MetricFormat -eq "ALL"){
                    $outputfile = "$OutputDirectory/AutomaticVsManualRotation.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/AutomaticVsManualRotation.html"
                    $titlesplit = "Amount of Accounts With Automatic vs Manual Password Rotation Flows"
                    $metricTag = "Platform Metrics"
                    $recommendation1 = "A platform is a set of configurations that defines how and when the system manages credentials and accesses for a particular type of system or application. Platforms are critical for ensuring secure and efficient means of management for privileged accounts."
                    $recommendation2 = "Frequent password rotation policies are a quick win for bolstering an organization's security posture. Avoid using platforms that do not support password rotation, or password storing type platforms, unless a plugin or integration is unavailable."
                    $recommendation3 = "If a platform without password rotation is required for a specific use case, consider using the automatic verification flow to ensure that the credentials in CyberArk match those on the target system."
                    $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 accounts that are configured with automatic password rotation flows verse accounts configured with only a manual password rotation flow. This configuration is based on the platform the accounts are associated with."

                    $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 "AutomaticVsManualVerification"){
                $tagout = "accounts"
                #INITIALIZE HASH
                $OutputHash = @{
                    Manual = @{
                        counter = 0
                    }
                    Automatic = @{
                        counter = 0
                    }
                }

                $AllAccounts = Get-VPASAllAccounts
                if(!$AllAccounts){
                    Write-Verbose "FAILED TO PULL ALL ACCOUNTS"
                    Write-VPASOutput -str "FAILED TO PULL ALL ACCOUNTS" -type E
                    Write-VPASOutput -str $_ -type E
                    return $false
                }
                foreach($acct in $AllAccounts.value){
                    $targetPlatformID = $acct.platformId
                    if([String]::IsNullOrEmpty($targetPlatformID)){ $targetPlatformID = "BLANK_PLATFORM" }

                    if($targetPlatformID -eq "BLANK_PLATFORM"){
                        if($OutputHash.Manual.$targetPlatformID){
                            $OutputHash.Manual.counter += 1
                            $OutputHash.Manual.$targetPlatformID.RawData += $acct
                        }
                        else{
                            $OutputHash.Manual += @{
                                $targetPlatformID = @{
                                    RawData = @($acct)
                                }
                            }
                            $OutputHash.Manual.counter += 1
                        }
                    }
                    else{
                        if($OutputHash.Manual.$targetPlatformID){
                            $OutputHash.Manual.counter += 1
                            $OutputHash.Manual.$targetPlatformID.RawData += $acct
                        }
                        elseif($OutputHash.Automatic.$targetPlatformID){
                            $OutputHash.Automatic.counter += 1
                            $OutputHash.Automatic.$targetPlatformID.RawData += $acct
                        }
                        else{
                            #GET PLATFORM DETAILS IN TERMS OF ROTATION
                            $AllPlatformDetails = Get-VPASPlatformDetails -platformID $targetPlatformID
                            $VerifyStyle = $AllPlatformDetails.Details.VFPerformPeriodicVerification

                            if($VerifyStyle -eq "No"){
                                if($OutputHash.Manual.$targetPlatformID){
                                    $OutputHash.Manual.counter += 1
                                    $OutputHash.Manual.$targetPlatformID.RawData += $acct
                                }
                                else{
                                    $OutputHash.Manual += @{
                                        $targetPlatformID = @{
                                            RawData = @($acct)
                                        }
                                    }
                                    $OutputHash.Manual.counter += 1
                                }
                            }
                            elseif($VerifyStyle -eq "Yes"){
                                if($OutputHash.Automatic.$targetPlatformID){
                                    $OutputHash.Automatic.counter += 1
                                    $OutputHash.Automatic.$targetPlatformID.RawData += $acct
                                }
                                else{
                                    $OutputHash.Automatic += @{
                                        $targetPlatformID = @{
                                            RawData = @($acct)
                                        }
                                    }
                                    $OutputHash.Automatic.counter += 1
                                }
                            }
                        }
                    }
                }

                if($MetricFormat -eq "JSON" -or $MetricFormat -eq "ALL"){
                    $outputfile = "$OutputDirectory/AutomaticVsManualVerification.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/AutomaticVsManualVerification.html"
                    $titlesplit = "Amount of Accounts With Automatic vs Manual Password Verification Flows"
                    $metricTag = "Platform Metrics"
                    $recommendation1 = "A platform is a set of configurations that defines how and when the system manages credentials and accesses for a particular type of system or application. Platforms are critical for ensuring secure and efficient means of management for privileged accounts."
                    $recommendation2 = "Verification is a process that ensures the credentials stored in CyberArk match those on the target system. This process is crucial for maintaining the integrity and accuracy of the target credential."
                    $recommendation3 = "If a platform without password rotation is required for a specific use case, consider using the automatic verification flow to ensure that the credentials in CyberArk match those on the target system."
                    $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 accounts that are configured with automatic password verification flows verse accounts configured with only a manual password verification flow. This configuration is based on the platform the accounts are associated with."

                    $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>
        </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>
"
 | Set-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
    }
}