Private/Get-FilterableProperties.ps1
|
#Requires -Version 5.1 <# .SYNOPSIS Inspects Get-EvergreenApp output and returns metadata for each property that can be used as a filter control in the UI. .DESCRIPTION Given an array of PSObjects returned by Get-EvergreenApp, this function: 1. Enumerates the property names from the first object 2. Excludes properties that are display-only (Version, URI, Date, etc.) 3. For each remaining property, collects unique values and determines the appropriate WPF control type based on cardinality: 2–6 unique values → CheckBoxStrip (horizontal checkbox row) 7–20 unique values → MultiListBox (scrollable multi-select listbox) 21+ unique values → TextBox (free-text contains-match) Also performs URI-based Type derivation: if the result set has no Type property but all rows have a URI, a synthetic 'Type (derived)' property is created by extracting the file extension from each URI. .PARAMETER AppResults The PSObject array returned by Get-EvergreenApp. Must contain at least one object. Version and URI are always required on each object. .OUTPUTS PSCustomObject[] - one object per filterable property with: Name : string - property name as returned by Evergreen DisplayName : string - friendly label for the UI UniqueValues : string[] - sorted distinct values Count : int - number of unique values ControlType : string - 'CheckBoxStrip' | 'MultiListBox' | 'TextBox' IsSynthetic : bool - true if derived from URI rather than a real property .EXAMPLE $results = Get-EvergreenApp -Name 'MicrosoftEdge' $props = Get-FilterableProperties -AppResults $results # Returns objects for Architecture, Channel, Release, Type #> function Get-FilterableProperties { [CmdletBinding()] [OutputType([PSCustomObject[]])] param( [Parameter(Mandatory)] [AllowEmptyCollection()] [PSObject[]]$AppResults ) $appResultsArray = @($AppResults) if ($appResultsArray.Count -eq 0) { return @() } # Guard against double-wrapped data: if element 0 is itself an array (e.g. Object[]{ Object[]{...} }), # flatten one level so the actual PSCustomObjects are used instead of the Array's own properties. if ($appResultsArray[0] -is [System.Array]) { $appResultsArray = @($appResultsArray[0]) if ($appResultsArray.Count -eq 0) { return @() } } # Properties that are never filterable - display in the grid only [string[]]$displayOnly = @( 'Version', 'URI', 'Date', 'Expiry', 'Sha', 'Sha1', 'Sha256', 'Hash', 'Checksum', 'Size', 'JavaVersion' ) # Friendly display names for well-known properties $friendlyNames = @{ Architecture = 'Architecture' Type = 'File type' Channel = 'Channel' Ring = 'Ring / Channel' Release = 'Release' Language = 'Language' Platform = 'Platform' Track = 'Track' Product = 'Product variant' } $filterableProps = $appResultsArray[0].PSObject.Properties.Name | Where-Object { $_ -notin $displayOnly -and $_ -notlike '*Date*' } $output = foreach ($propName in $filterableProps) { $allValues = @( $appResultsArray.$propName | Where-Object { $null -ne $_ } | ForEach-Object { [string]$_ } | Sort-Object -Unique ) $controlType = if ($allValues.Count -le 6) { 'CheckBoxStrip' } elseif ($allValues.Count -le 20) { 'MultiListBox' } else { 'TextBox' } [PSCustomObject]@{ Name = $propName DisplayName = if ($friendlyNames.ContainsKey($propName)) { $friendlyNames[$propName] } else { $propName } UniqueValues = [string[]]$allValues Count = $allValues.Count ControlType = $controlType IsSynthetic = $false } } # URI-based Type derivation - add synthetic 'File type' if Type is absent $hasTypeProperty = ($appResultsArray[0].PSObject.Properties.Name) -contains 'Type' $hasUriProperty = ($appResultsArray[0].PSObject.Properties.Name) -contains 'URI' if (-not $hasTypeProperty -and $hasUriProperty) { $derivedTypes = @( $appResultsArray.URI | Where-Object { $null -ne $_ } | ForEach-Object { [System.IO.Path]::GetExtension($_).TrimStart('.').ToLower() } | Where-Object { $_ -ne '' } | Sort-Object -Unique ) if ($derivedTypes.Count -gt 0) { $output = @($output) + [PSCustomObject]@{ Name = '_DerivedType' DisplayName = 'File type (derived)' UniqueValues = [string[]]$derivedTypes Count = $derivedTypes.Count ControlType = if ($derivedTypes.Count -le 6) { 'CheckBoxStrip' } else { 'MultiListBox' } IsSynthetic = $true } } } return @($output) } |