src/_Get-CciBlobModuleIndexResult.ps1

function _Get-CciBlobModuleIndexResult {
<#
.SYNOPSIS
    Reads <blobPrefix>/index.json from the tenant distribution store, and says
    why when it cannot.
.DESCRIPTION
    Replaces _Get-CciBlobModuleIndex, which returned $null for EVERY failure.
    Callers turned that single $null into "the store has nothing to offer", so
    a store that had rejected our identity was reported as an empty store: a
    technician was told 'the cciit distribution store has no module index yet'
    while the index sat there, healthy, with all three modules in it. The name
    changed deliberately - a caller left on the old $null contract would have
    gone on believing an auth failure was an empty store, and a rename makes
    that a load-time error instead of a quiet lie.
 
    ALWAYS returns a result object, never $null. The object is always truthy,
    so callers MUST branch on Status:
 
      Status 'ok' - Index holds the parsed index
                  'absent' - the store answered, and there is no index yet
                  'auth' - the store rejected our identity (401 / 403)
                  'unreachable' - anything else: network, malformed index, ...
      Index the parsed index on 'ok', otherwise $null
      HttpStatus the HTTP status behind a failure, 0 when there was not one
      Message the underlying error text, empty on success
 
    Classification reads the HTTP status back out of the message
    _Invoke-CciBlobRequest throws, which is formatted '(HTTP <status>)'. That
    format is a contract between the two functions and is covered by a test.
#>

    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]$Feed,
        [Parameter(Mandatory)]$Context
    )
    $tmp = Join-Path ([IO.Path]::GetTempPath()) "cciget-index-$([guid]::NewGuid().ToString('n')).json"
    try {
        $null = _Invoke-CciBlobRequest -Context $Context -Operation Download `
            -Container $Feed.blobContainer -Blob "$($Feed.blobPrefix)/index.json" -Path $tmp
        $index = (Get-Content $tmp -Raw | ConvertFrom-Json)
        return [pscustomobject]@{
            Status     = 'ok'
            Index      = $index
            HttpStatus = 0
            Message    = ''
        }
    } catch {
        $message = "$_"
        $status = 0
        if ($message -match '\(HTTP (\d{3})\)') { $status = [int]$Matches[1] }
        $state =
            if ($status -eq 401 -or $status -eq 403) { 'auth' }
            elseif ($status -eq 404)                 { 'absent' }
            else                                     { 'unreachable' }
        Write-Verbose "cciget: module index unavailable ($state): $message"
        return [pscustomobject]@{
            Status     = $state
            Index      = $null
            HttpStatus = $status
            Message    = $message
        }
    } finally {
        Remove-Item $tmp -Force -ErrorAction SilentlyContinue
    }
}