Private/Get-DeepestActiveStep.ps1

function Get-DeepestActiveStep {
    <#
    .SYNOPSIS
        Recursively walks the update run step hierarchy to find the deepest InProgress or Failed step object.
    .DESCRIPTION
        Companion to Get-CurrentStepPath. Returns the leaf step object itself (not just its name path)
        so callers can pull fields like startTimeUtc, endTimeUtc, errorMessage off the deepest
        actively-executing or most-recently-failed step. Used by Format-AzLocalUpdateRun in v0.7.96
        to surface per-step elapsed (so a 16-node cluster's legitimate 8h overall run does not flag
        as stuck when its current Start/Stop/Apply step has actually been ticking along normally).
    #>

    [CmdletBinding()]
    [OutputType([object])]
    param(
        [Parameter(Mandatory = $false)]
        [array]$Steps,

        [Parameter(Mandatory = $false)]
        [int]$MaxDepth = 20
    )

    if (-not $Steps -or $Steps.Count -eq 0 -or $MaxDepth -le 0) { return $null }

    foreach ($step in $Steps) {
        # v0.9.18: guard status/steps under Set-StrictMode -Version Latest. A leaf step in
        # a failed run can omit the `steps` (and even `status`) property; a bare read THROWS
        # "The property 'steps' cannot be found on this object" (observed live: Tacoma failed
        # run bae9704e - four top-level LEAF steps with no `steps` child).
        $stepStatus = if ($step.PSObject.Properties['status']) { $step.status } else { $null }
        if ($stepStatus -in @("InProgress", "Error", "Failed")) {
            $childSteps = if ($step.PSObject.Properties['steps']) { $step.steps } else { $null }
            if ($childSteps -and @($childSteps).Count -gt 0) {
                $deeper = Get-DeepestActiveStep -Steps $childSteps -MaxDepth ($MaxDepth - 1)
                if ($deeper) { return $deeper }
            }
            return $step
        }
    }
    return $null
}