Private/Get-TBSnapshotResourceProperties.ps1
|
function Get-TBSnapshotResourceProperties { <# .SYNOPSIS Downloads snapshot content and extracts resource type properties. .DESCRIPTION Fetches the snapshot content from its ResourceLocation URL and returns a hashtable mapping lowercase resource type names to their properties objects. Handles multiple API response shapes defensively: flat array, value-wrapped, and resources-wrapped. .PARAMETER Snapshot A snapshot object (must have Status and ResourceLocation). .OUTPUTS [hashtable] Keys are lowercase resource type names, values are property objects. #> [CmdletBinding()] [OutputType([hashtable])] param( [Parameter(Mandatory = $true)] [object]$Snapshot ) $result = @{} if ($Snapshot.Status -ne 'succeeded' -and $Snapshot.Status -ne 'partiallySuccessful') { throw ('Snapshot status is "{0}". Only succeeded or partiallySuccessful snapshots can provide resource properties.' -f $Snapshot.Status) } if (-not $Snapshot.ResourceLocation) { throw 'Snapshot has no ResourceLocation URL. Cannot download content.' } Write-TBLog -Message ('Downloading snapshot content from: {0}' -f $Snapshot.ResourceLocation) $content = Invoke-TBGraphRequest -Uri $Snapshot.ResourceLocation -Method 'GET' if (-not $content) { Write-TBLog -Message 'Snapshot content is empty.' -Level 'Warning' return $result } # Normalize response to an array of resource items. # The API may return: # 1. A flat array of resource objects # 2. An object with a "value" array # 3. An object with a "resources" array # 4. A single resource object (array unwrapped by PowerShell) $items = $null if ($content -is [System.Collections.IEnumerable] -and $content -isnot [hashtable] -and $content -isnot [string]) { $items = @($content) } elseif ($content -is [hashtable]) { if ($content.ContainsKey('value')) { $items = @($content['value']) } elseif ($content.ContainsKey('resources')) { $items = @($content['resources']) } elseif ($content.ContainsKey('resourceType')) { # Single resource object (array unwrapped) $items = @($content) } } else { if ($content.PSObject.Properties['value']) { $items = @($content.value) } elseif ($content.PSObject.Properties['resources']) { $items = @($content.resources) } elseif ($content.PSObject.Properties['resourceType']) { # Single resource object (array unwrapped) $items = @($content) } } if (-not $items) { Write-TBLog -Message 'Snapshot content contains no recognizable resource items.' -Level 'Warning' return $result } foreach ($item in $items) { $rtName = $null $props = $null if ($item -is [hashtable]) { if ($item.ContainsKey('resourceType')) { $rtName = $item['resourceType'] } if ($item.ContainsKey('properties')) { $props = $item['properties'] } } else { if ($item.PSObject.Properties['resourceType']) { $rtName = $item.resourceType } if ($item.PSObject.Properties['properties']) { $props = $item.properties } } if (-not $rtName) { Write-TBLog -Message 'Skipping snapshot item with no resourceType field.' -Level 'Warning' continue } if (-not $props) { Write-TBLog -Message ('Skipping snapshot item "{0}" with no properties field.' -f $rtName) -Level 'Warning' continue } # Check if properties is effectively empty $isEmpty = $false if ($props -is [hashtable]) { $isEmpty = $props.Count -eq 0 } elseif ($props.PSObject.Properties) { $isEmpty = @($props.PSObject.Properties).Count -eq 0 } if ($isEmpty) { Write-TBLog -Message ('Snapshot item "{0}" has empty properties -- skipping.' -f $rtName) -Level 'Warning' continue } $key = $rtName.ToLower() if (-not $result.ContainsKey($key)) { $result[$key] = $props } } Write-TBLog -Message ('Extracted properties for {0} resource type(s) from snapshot.' -f $result.Count) return $result } |