.claude/worktrees/agent-a7ad6c4ede1f0dedc/Modules/Private/Main/Get-AZTICollectedValue.ps1

<#
.Synopsis
Reads one named value from every element of a collection, safely under StrictMode.
 
.DESCRIPTION
PowerShell's member enumeration ($collection.Name) is unsafe under
Set-StrictMode -Version Latest: when the enumeration yields nothing at all, PowerShell
reports the property as missing and throws
 
    The property 'Name' cannot be found on this object. Verify that the property exists.
 
A $null value on every element is fine - enumeration still yields one $null per element.
An EMPTY COLLECTION on every element is not: those flatten away, the overall result is
empty, and the read throws even though every element carries the key.
 
That distinction matters because an empty collection is a perfectly normal Azure API
response. A subscription with no reservation recommendations returns { "value": [] }, so a
healthy tenant was crashing the inventory run (AB#5633).
 
This function reads each element explicitly instead, and emits nothing when there is
nothing to emit - so `$Resources += Get-AZSCCollectedValue ...` adds nothing rather than
throwing. It handles both dictionary elements (the API result hashtables) and objects.
 
.PARAMETER InputObject
The collection to read from. $null and empty collections are accepted and yield nothing.
 
.PARAMETER Name
The key or property name to read from each element.
 
.EXAMPLE
$Resources += Get-AZSCCollectedValue -InputObject $APIResults -Name 'ReservationRecomen'
 
.COMPONENT
This PowerShell Module is part of Azure Scout (AZSC).
#>

function Get-AZSCCollectedValue {
    [CmdletBinding()]
    Param(
        [Parameter(Position = 0)]
        [AllowNull()]
        $InputObject,

        [Parameter(Mandatory, Position = 1)]
        [ValidateNotNullOrEmpty()]
        [string]$Name
    )

    if ($null -eq $InputObject) { return }

    foreach ($Element in @($InputObject)) {
        if ($null -eq $Element) { continue }

        if ($Element -is [System.Collections.IDictionary]) {
            # .Contains rather than .ContainsKey: IDictionary guarantees the former.
            if ($Element.Contains($Name)) { $Element[$Name] }
            continue
        }

        # PSObject.Properties lookup never throws for an absent member, unlike $Element.$Name.
        $Property = $Element.PSObject.Properties[$Name]
        if ($Property) { $Property.Value }
    }
}