Public/cloud-host.ps1

function Get-CloudHost {
    <#
    .SYNOPSIS
        Gets hosts from the Cloud Server.
     
    .DESCRIPTION
        Retrieves a list of hosts. Automatically handles token refresh.
     
    .PARAMETER Name
        Optional. Filter by host name.
     
    .PARAMETER ID
        Optional. Filter by host ID
     
    .EXAMPLE
        # Get all hosts
        Get-CloudHost
         
    .EXAMPLE
        # Get a host by specifying an ID
        Get-CloudHost -ID 5
         
    .EXAMPLE
        # Get hosts that match the specified name string
        Get-CloudHost -Name si-overlapped-2
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [int]$ID
    )
    
    # Build the URI
    #$uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/metal/host"
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/host"
    
    # Filter by ID if specified
    if ($ID) {
        #$hosturi = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/host/${ID}"
        $hosturi = "$uri/${ID}"
        $response = Invoke-CloudApiRequest -Uri $hosturi -Method Get
        
        # Extract host from the response
        $host = $response.host  # Likely singular when querying by ID
        return $host
    }
    else {
        # Use the helper function which handles token refresh automatically
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        
        # Extract hosts from the response
        $hosts = $response.hosts
        
        # Filter by name if specified
        if ($Name) {
            $hosts = $hosts | Where-Object { $_.name -like "*$Name*" }
        }
        
        return $hosts
    }
}

function Get-CloudCluster {
    <#
    .SYNOPSIS
        Gets Clusters from the Cloud Server.
     
    .DESCRIPTION
        Retrieves a list of Clusters. Automatically handles token refresh.
     
    .PARAMETER Name
        Optional. Filter by Cluster name.
     
    .PARAMETER ID
        Optional. Filter by Cluster ID
     
    .EXAMPLE
        # Get all clusters
        Get-CloudCluster
         
    .EXAMPLE
        # Get a specific cluster by ID
        Get-CloudCluster -ID 5
         
    .EXAMPLE
        # Get clusters that match the specified name string
        Get-CloudCluster -Name "default"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [int]$ID
    )
    
    # Build the URI
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/cluster"
    
    # Filter by ID if specified
    if ($ID) {
        $Clusteruri = "$uri/${ID}"
        $response = Invoke-CloudApiRequest -Uri $Clusteruri -Method Get
        
        # Extract Cluster from the response
        $Cluster = $response.Cluster  # Likely singular when querying by ID
        return $Cluster
    }
    else {
        # Use the helper function which handles token refresh automatically
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        
        # Extract Clusters from the response
        $Clusters = $response.Cluster
        
        # Filter by name if specified
        if ($Name) {
            $Clusters = $Clusters | Where-Object { $_.name -like "*$Name*" }
        }
        
        return $Clusters
    }
}

function Get-CloudDatacenter {
    <#
    .SYNOPSIS
        Gets Datacenters from the Cloud Server.
     
    .DESCRIPTION
        Retrieves a list of Datacenters. Automatically handles token refresh.
     
    .PARAMETER Name
        Optional. Filter by Datacenter name.
     
    .PARAMETER ID
        Optional. Filter by Datacenter ID
     
    .EXAMPLE
        # Get all datacenters
        Get-CloudDatacenter
         
    .EXAMPLE
        # Get a specific datacenter by ID
        Get-CloudDatacenter -ID 5
         
    .EXAMPLE
        # Get datacenters that match the specified name string
        Get-CloudDatacenter -Name "default"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [int]$ID
    )
    
    # Build the URI
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/datacenter"
    
    # Filter by ID if specified
    if ($ID) {
        $Datacenteruri = "$uri/${ID}"
        $response = Invoke-CloudApiRequest -Uri $Datacenteruri -Method Get
        
        # Extract Datacenter from the response
        $Datacenter = $response.Datacenter  # Likely singular when querying by ID
        return $Datacenter
    }
    else {
        # Use the helper function which handles token refresh automatically
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        
        # Extract Datacenters from the response
        $Datacenters = $response.Datacenters
        
        # Filter by name if specified
        if ($Name) {
            $Datacenters = $Datacenters | Where-Object { $_.name -like "*$Name*" }
        }
        
        return $Datacenters
    }
}

function Get-CloudCompute {
    <#
    .SYNOPSIS
        Gets compute-only from the Cloud Server. Try Get-CloudHost to return all hosts
     
    .DESCRIPTION
        Retrieves a list of computes. Automatically handles token refresh.
     
    .PARAMETER Name
        Optional. Filter by compute name.
     
    .PARAMETER ID
        Optional. Filter by compute ID
     
    .EXAMPLE
        # Get all compute hosts
        Get-CloudCompute
         
    .EXAMPLE
        # Get a specific compute host by ID
        Get-CloudCompute -ID 5
         
    .EXAMPLE
        # Get compute hosts that match the specified name string
        Get-CloudCompute -Name "si-overlapped-2"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [string]$Name,
        
        [Parameter(Mandatory = $false)]
        [int]$ID
    )
    
    # Build the URI
    #$uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/metal/compute"
    $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/compute"
    
    # Filter by ID if specified
    if ($ID) {
        #$computeuri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/compute/${ID}"
        $computeuri = "$uri/${ID}"
        $response = Invoke-CloudApiRequest -Uri $computeuri -Method Get
        
        # Extract compute from the response
        $compute = $response#.compute # Likely singular when querying by ID
        return $compute
    }
    else {
        # Use the helper function which handles token refresh automatically
        $response = Invoke-CloudApiRequest -Uri $uri -Method Get
        
        # Extract computes from the response
        $computes = $response#.computes
        
        # Filter by name if specified
        if ($Name) {
            $computes = $computes | Where-Object { $_.name -like "*$Name*" }
        }
        
        return $computes
    }
}

function Get-CloudHostPerformance {
    <#
    .SYNOPSIS
        Gets and displays host performance metrics from the Cloud Server.
     
    .DESCRIPTION
        Retrieves host performance metrics with optional graphical display.
        Shows CPU and memory utilization with visual percentage graphs.
        Automatically handles token refresh.
     
    .PARAMETER Graph
        Optional. Display metrics with visual percentage graphs
     
    .PARAMETER Seconds
        Optional. Value in seconds to collect metrics - i.e. 60 will pull stats for the past minute
     
    .PARAMETER ID
        Optional. Filter by host ID
     
    .PARAMETER GroupByHost
        Optional. When using -Graph, group results by host ID and show average utilization
     
    .PARAMETER GB
        Display memory in Gigabytes (default)
     
    .PARAMETER TB
        Display memory in Terabytes
            
    .EXAMPLE
        # Get host performance
        Get-CloudHostPerformance
         
    .EXAMPLE
        # Get host performance displayed graphically
        Get-CloudHostPerformance -Graph
         
    .EXAMPLE
        # Get host performance displayed graphically for a specific host
        Get-CloudHostPerformance -Graph -ID 5
         
    .EXAMPLE
        # Get host performance displayed graphically for the a specified time period only
        Get-CloudHostPerformance -Seconds 90 -Graph
         
    .EXAMPLE
        # Get host performance displayed graphically and average the per-host values out over the time period
        Get-CloudHostPerformance -Seconds 60 -Graph -GroupByHost
         
    .EXAMPLE
        # Get host performance displayed graphically and change the display units
        Get-CloudHostPerformance -Graph -TB
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [switch]$Graph,
        
        [Parameter(Mandatory = $false)]
        [int]$Seconds,
        
        [Parameter(Mandatory = $false)]
        [int]$ID,
        
        [Parameter(Mandatory = $false)]
        [switch]$GroupByHost,
        
        [Parameter(Mandatory = $false)]
        [switch]$GB,
        
        [Parameter(Mandatory = $false)]
        [switch]$TB
    )
    
    # Get monitoring data using the existing function
    $monitoringParams = @{}
    if ($PSBoundParameters.ContainsKey('Seconds')) {
        $monitoringParams['Seconds'] = $Seconds
    }
    if ($PSBoundParameters.ContainsKey('ID')) {
        $monitoringParams['ID'] = $ID
    }
    
    $monitoring = Get-CloudHostMonitoring @monitoringParams
    
    if (-not $monitoring) {
        Write-Warning "No monitoring data returned"
        return
    }
    
    # Determine target unit and conversion factor
    $targetUnit = "GB"  # Default to GB
    $conversionFactors = @{
        'GB' = @{ fromKB = 1/1048576; label = 'GB'; decimals = 2; format = 'N2' }
        'TB' = @{ fromKB = 1/1073741824; label = 'TB'; decimals = 4; format = 'N4' }
    }
    
    if ($TB) { $targetUnit = 'TB' }
    
    $unitConfig = $conversionFactors[$targetUnit]
    
    if ($Graph) {
        Write-Host ("=" * 70)
        
        if ($GroupByHost) {
            # Group by host and calculate averages
            $grouped = $monitoring | Group-Object -Property id
            
            foreach ($group in $grouped | Sort-Object Name) {
                $hostId = $group.Name
                $samples = $group.Group
                
                # Calculate averages
                $avgUsedCpu = ($samples.capacity.used_cpu | Measure-Object -Average).Average
                $avgFreeCpu = ($samples.capacity.free_cpu | Measure-Object -Average).Average
                $avgUsedMemory = ($samples.capacity.used_memory | Measure-Object -Average).Average
                $avgFreeMemory = ($samples.capacity.free_memory | Measure-Object -Average).Average
                
                $totalCpu = $avgUsedCpu + $avgFreeCpu
                $totalMemory = $avgUsedMemory + $avgFreeMemory
                
                # Calculate percentages
                $cpuPercent = if ($totalCpu -gt 0) { 
                    [math]::Round(($avgUsedCpu / $totalCpu) * 100) 
                } else { 0 }
                
                $memPercent = if ($totalMemory -gt 0) { 
                    [math]::Round(($avgUsedMemory / $totalMemory) * 100) 
                } else { 0 }
                
                # Convert memory values
                $usedMemConverted = [math]::Round($avgUsedMemory * $unitConfig.fromKB, $unitConfig.decimals)
                $totalMemConverted = [math]::Round($totalMemory * $unitConfig.fromKB, $unitConfig.decimals)
                
                Write-Host "`nHost ID: $hostId (averaged over $($samples.Count) sample$(if($samples.Count -ne 1){'s'}))" -ForegroundColor Cyan
                
                # CPU Graph
                Write-Host " cpu " -NoNewline
                Show-PercentageGraph -percent $cpuPercent
                $cpuDisplay = " - {0,8:N0} / {1,8:N0} threads" -f $avgUsedCpu, $totalCpu
                Write-Host $cpuDisplay
                
                # Memory Graph
                Write-Host " memory " -NoNewline
                Show-PercentageGraph -percent $memPercent
                $memDisplay = " - {0} / {1} {2}" -f 
                    ("{0:$($unitConfig.format)}" -f $usedMemConverted), 
                    ("{0:$($unitConfig.format)}" -f $totalMemConverted),
                    $unitConfig.label
                Write-Host $memDisplay
            }
        }
        else {
            # Show individual snapshots
            foreach ($sample in $monitoring) {
                # Convert Unix timestamp to DateTime (PowerShell 5.1 compatible)
                $timestamp = if ($sample.timestamp) {
                    $origin = New-Object DateTime(1970, 1, 1, 0, 0, 0, [DateTimeKind]::Utc)
                    $origin.AddSeconds($sample.timestamp).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")
                } else {
                    "Unknown"
                }
                
                $totalCpu = $sample.capacity.used_cpu + $sample.capacity.free_cpu
                $totalMemory = $sample.capacity.used_memory + $sample.capacity.free_memory
                
                # Calculate percentages
                $cpuPercent = if ($totalCpu -gt 0) { 
                    [math]::Round(($sample.capacity.used_cpu / $totalCpu) * 100) 
                } else { 0 }
                
                $memPercent = if ($totalMemory -gt 0) { 
                    [math]::Round(($sample.capacity.used_memory / $totalMemory) * 100) 
                } else { 0 }
                
                # Convert memory values
                $usedMemConverted = [math]::Round($sample.capacity.used_memory * $unitConfig.fromKB, $unitConfig.decimals)
                $totalMemConverted = [math]::Round($totalMemory * $unitConfig.fromKB, $unitConfig.decimals)
                
                Write-Host "`nHost ID: $($sample.id) | Time: $timestamp" -ForegroundColor Cyan
                
                # CPU Graph
                Write-Host " cpu " -NoNewline
                Show-PercentageGraph -percent $cpuPercent
                $cpuDisplay = " - {0,8:N0} / {1,8:N0} threads" -f $sample.capacity.used_cpu, $totalCpu
                Write-Host $cpuDisplay
                
                # Memory Graph
                Write-Host " memory " -NoNewline
                Show-PercentageGraph -percent $memPercent
                $memDisplay = " - {0} / {1} {2}" -f 
                    ("{0:$($unitConfig.format)}" -f $usedMemConverted), 
                    ("{0:$($unitConfig.format)}" -f $totalMemConverted),
                    $unitConfig.label
                Write-Host $memDisplay
            }
        }
        
        Write-Host ""
    }
    else {
        # Return normal object output
        return $monitoring
    }
}

function Get-CloudHostMonitoring {
    <#
    .SYNOPSIS
        Gets host metrics from the Cloud Server.
     
    .DESCRIPTION
        Retrieves host metrics. Automatically handles token refresh.
     
    .PARAMETER Seconds
        Optional. Value in seconds to collect metrics - i.e. 60 will pull stats for the past minute
     
    .PARAMETER ID
        Optional. Filter by host ID
     
    .PARAMETER Graph
        Optional. Display metrics with visual percentage graphs
     
    .PARAMETER GroupByHost
        Optional. When using -Graph, group results by host ID and show average utilization
     
    .PARAMETER ExportCSV
        Optional. Path to export the monitoring data as a CSV file. Data will be flattened for CSV format.
     
    .PARAMETER GB
        Display memory in Gigabytes (default)
     
    .PARAMETER TB
        Display memory in Terabytes
            
    .EXAMPLE
        # Get host metrics for all hosts
        Get-CloudHostMonitoring
         
    .EXAMPLE
        # Get host metrics for a specific host
        Get-CloudHostMonitoring -ID 5
         
    .EXAMPLE
        # Get host metrics for a specific period of time
        Get-CloudHostMonitoring -Seconds 90
         
    .EXAMPLE
        # Get host metrics for all hosts for a specific period of time and graph them
        Get-CloudHostMonitoring -Seconds 90 -Graph
         
    .EXAMPLE
        # Get host metrics for all hosts for a specific period of time, average the metrics out per-host, and graph them
        Get-CloudHostMonitoring -Seconds 300 -Graph -GroupByHost
         
    .EXAMPLE
        # Get host metrics for a specific host for a specific period of time and graph them
        Get-CloudHostMonitoring -Seconds 60 -ID 5 -Graph
         
    .EXAMPLE
        # Get all most metrics for the past 5 minutes and export them to CSV
        Get-CloudHostMonitoring -Seconds 300 -ExportCSV "C:\Temp\host-monitoring.csv"
         
    .EXAMPLE
        # Get most metrics for a certain host, for the past hour and export them to CSV
        Get-CloudHostMonitoring -Seconds 3600 -ID 2 -ExportCSV "C:\Temp\host2-monitoring.csv"
    #>

    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory = $false)]
        [int]$Seconds,
        
        [Parameter(Mandatory = $false)]
        [int]$ID,
        
        [Parameter(Mandatory = $false)]
        [switch]$Graph,
        
        [Parameter(Mandatory = $false)]
        [switch]$GroupByHost,
        
        [Parameter(Mandatory = $false)]
        [string]$ExportCSV,
        
        [Parameter(Mandatory = $false)]
        [switch]$GB,
        
        [Parameter(Mandatory = $false)]
        [switch]$TB
    )
    
    # Build base URI based on parameters
    if ($PSBoundParameters.ContainsKey('Seconds')) {
        # If Seconds is specified, always use the monitoring endpoint with seconds param
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/host/monitoring?seconds=$Seconds"
    }
    elseif ($PSBoundParameters.ContainsKey('ID')) {
        # If only ID is specified (no Seconds), use the specific host monitoring endpoint
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/host/$ID/monitoring"
    }
    else {
        # No parameters - get all monitoring data
        $uri = "$($script:CloudConnection.BaseUri)/manifold-api/v2/cloud/host/monitoring"
    }
    
    Write-Verbose "Request URI: $uri"
    
    # Use the helper function which handles token refresh automatically
    $response = Invoke-CloudApiRequest -Uri $uri -Method Get
    
    # Extract monitoring data from the response
    $monitoring = $response.monitoring
    
    # If both Seconds and ID were specified, filter the results
    if ($PSBoundParameters.ContainsKey('Seconds') -and $PSBoundParameters.ContainsKey('ID')) {
        $monitoring = $monitoring | Where-Object { $_.id -eq $ID }
    }
    
    # Handle CSV export if requested
    if ($PSBoundParameters.ContainsKey('ExportCSV')) {
        # Flatten the nested objects for CSV export
        $flattenedData = $monitoring | ForEach-Object {
            # Convert Unix timestamp to readable format
            $readableTime = if ($_.timestamp) {
                $origin = New-Object DateTime(1970, 1, 1, 0, 0, 0, [DateTimeKind]::Utc)
                $origin.AddSeconds($_.timestamp).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")
            } else {
                "Unknown"
            }
            
            [PSCustomObject]@{
                Timestamp = $_.timestamp
                DateTime = $readableTime
                HostID = $_.id
                FreeCPU = $_.capacity.free_cpu
                UsedCPU = $_.capacity.used_cpu
                TotalCPU = $_.capacity.free_cpu + $_.capacity.used_cpu
                CPUUsagePercent = if (($_.capacity.free_cpu + $_.capacity.used_cpu) -gt 0) {
                    [math]::Round(($_.capacity.used_cpu / ($_.capacity.free_cpu + $_.capacity.used_cpu)) * 100, 2)
                } else { 0 }
                FreeMemoryKB = $_.capacity.free_memory
                UsedMemoryKB = $_.capacity.used_memory
                TotalMemoryKB = $_.capacity.free_memory + $_.capacity.used_memory
                MemoryUsagePercent = if (($_.capacity.free_memory + $_.capacity.used_memory) -gt 0) {
                    [math]::Round(($_.capacity.used_memory / ($_.capacity.free_memory + $_.capacity.used_memory)) * 100, 2)
                } else { 0 }
                NetworkRX = $_.system.netrx
                NetworkTX = $_.system.nettx
            }
        }
        
        # Export to CSV
        try {
            $flattenedData | Export-Csv -Path $ExportCSV -NoTypeInformation
            Write-Host "Successfully exported $($flattenedData.Count) record(s) to: $ExportCSV" -ForegroundColor Green
        }
        catch {
            Write-Error "Failed to export CSV: $_"
        }
        
        # Return nothing to avoid screen output
        return
    }
    
    # Handle graphing if requested
    if ($Graph) {
        # Determine target unit and conversion factor
        $targetUnit = "GB"  # Default to GB
        $conversionFactors = @{
            'GB' = @{ fromKB = 1/1048576; label = 'GB'; decimals = 2; format = 'N2' }
            'TB' = @{ fromKB = 1/1073741824; label = 'TB'; decimals = 4; format = 'N4' }
        }
        
        if ($TB) { $targetUnit = 'TB' }
        
        $unitConfig = $conversionFactors[$targetUnit]
        
        Write-Host ("=" * 70)
        
        if ($GroupByHost) {
            # Group by host and calculate averages
            $grouped = $monitoring | Group-Object -Property id
            
            foreach ($group in $grouped | Sort-Object Name) {
                $hostId = $group.Name
                $samples = $group.Group
                
                # Calculate averages
                $avgUsedCpu = ($samples.capacity.used_cpu | Measure-Object -Average).Average
                $avgFreeCpu = ($samples.capacity.free_cpu | Measure-Object -Average).Average
                $avgUsedMemory = ($samples.capacity.used_memory | Measure-Object -Average).Average
                $avgFreeMemory = ($samples.capacity.free_memory | Measure-Object -Average).Average
                
                $totalCpu = $avgUsedCpu + $avgFreeCpu
                $totalMemory = $avgUsedMemory + $avgFreeMemory
                
                # Calculate percentages
                $cpuPercent = if ($totalCpu -gt 0) { 
                    [math]::Round(($avgUsedCpu / $totalCpu) * 100) 
                } else { 0 }
                
                $memPercent = if ($totalMemory -gt 0) { 
                    [math]::Round(($avgUsedMemory / $totalMemory) * 100) 
                } else { 0 }
                
                # Convert memory values
                $usedMemConverted = [math]::Round($avgUsedMemory * $unitConfig.fromKB, $unitConfig.decimals)
                $totalMemConverted = [math]::Round($totalMemory * $unitConfig.fromKB, $unitConfig.decimals)
                
                Write-Host "`nHost ID: $hostId (averaged over $($samples.Count) sample$(if($samples.Count -ne 1){'s'}))" -ForegroundColor Cyan
                
                # CPU Graph
                Write-Host " cpu " -NoNewline
                Show-PercentageGraph -percent $cpuPercent
                $cpuDisplay = " - {0,8:N0} / {1,8:N0} threads" -f $avgUsedCpu, $totalCpu
                Write-Host $cpuDisplay
                
                # Memory Graph
                Write-Host " memory " -NoNewline
                Show-PercentageGraph -percent $memPercent
                $memDisplay = " - {0} / {1} {2}" -f 
                    ("{0:$($unitConfig.format)}" -f $usedMemConverted), 
                    ("{0:$($unitConfig.format)}" -f $totalMemConverted),
                    $unitConfig.label
                Write-Host $memDisplay
            }
        }
        else {
            # Show individual snapshots
            foreach ($sample in $monitoring) {
                # Convert Unix timestamp to DateTime (PowerShell 5.1 compatible)
                $timestamp = if ($sample.timestamp) {
                    $origin = New-Object DateTime(1970, 1, 1, 0, 0, 0, [DateTimeKind]::Utc)
                    $origin.AddSeconds($sample.timestamp).ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss")
                } else {
                    "Unknown"
                }
                
                $totalCpu = $sample.capacity.used_cpu + $sample.capacity.free_cpu
                $totalMemory = $sample.capacity.used_memory + $sample.capacity.free_memory
                
                # Calculate percentages
                $cpuPercent = if ($totalCpu -gt 0) { 
                    [math]::Round(($sample.capacity.used_cpu / $totalCpu) * 100) 
                } else { 0 }
                
                $memPercent = if ($totalMemory -gt 0) { 
                    [math]::Round(($sample.capacity.used_memory / $totalMemory) * 100) 
                } else { 0 }
                
                # Convert memory values
                $usedMemConverted = [math]::Round($sample.capacity.used_memory * $unitConfig.fromKB, $unitConfig.decimals)
                $totalMemConverted = [math]::Round($totalMemory * $unitConfig.fromKB, $unitConfig.decimals)
                
                Write-Host "`nHost ID: $($sample.id) | Time: $timestamp" -ForegroundColor Cyan
                
                # CPU Graph
                Write-Host " cpu " -NoNewline
                Show-PercentageGraph -percent $cpuPercent
                $cpuDisplay = " - {0,8:N0} / {1,8:N0} threads" -f $sample.capacity.used_cpu, $totalCpu
                Write-Host $cpuDisplay
                
                # Memory Graph
                Write-Host " memory " -NoNewline
                Show-PercentageGraph -percent $memPercent
                $memDisplay = " - {0} / {1} {2}" -f 
                    ("{0:$($unitConfig.format)}" -f $usedMemConverted), 
                    ("{0:$($unitConfig.format)}" -f $totalMemConverted),
                    $unitConfig.label
                Write-Host $memDisplay
            }
        }
        
        Write-Host ""
    }
    else {
        # Return normal object output
        return $monitoring
    }
}