Private/Measure-Percentile.ps1

function Measure-Percentile {
    <#
    .SYNOPSIS
        Computes a percentile from a numeric array using linear interpolation.

    .DESCRIPTION
        Platform metrics in Azure Monitor expose only Average/Min/Max/Count/Total --
        there is no server-side percentile aggregation. This function computes
        percentiles client-side from the raw per-interval datapoints we pull back.

        Uses the same linear-interpolation-between-closest-ranks method as Kusto's
        percentile() (type C / "linear"), so values line up with VMPerformance().

    .PARAMETER Value
        The numeric samples. Nulls are ignored. Order does not matter (sorted internally).

    .PARAMETER Percentile
        The percentile to compute, 0-100 (e.g. 95 for P95).

    .OUTPUTS
        [double] the interpolated percentile, or $null when no samples are supplied.

    .EXAMPLE
        Measure-Percentile -Value 1,2,3,4,5,6,7,8,9,10 -Percentile 95
    #>

    [CmdletBinding()]
    [OutputType([double])]
    param(
        [Parameter(Mandatory)]
        [AllowEmptyCollection()]
        [AllowNull()]
        [double[]] $Value,

        [Parameter(Mandatory)]
        [ValidateRange(0, 100)]
        [double] $Percentile
    )

    $samples = @($Value | Where-Object { $null -ne $_ } | Sort-Object)
    $n = $samples.Count
    if ($n -eq 0) { return $null }
    if ($n -eq 1) { return [double] $samples[0] }

    # Rank position on a 0-based index scale (linear interpolation, Kusto-compatible).
    $rank = ($Percentile / 100.0) * ($n - 1)
    $lower = [math]::Floor($rank)
    $upper = [math]::Ceiling($rank)
    if ($lower -eq $upper) {
        return [double] $samples[[int]$lower]
    }

    $weight = $rank - $lower
    return [double] ($samples[[int]$lower] * (1 - $weight) + $samples[[int]$upper] * $weight)
}