@@ -31,6 +31,60 @@ function Invoke-ExecUniversalSearchV2 {
3131 ' Applications' {
3232 $Results = Search-CIPPDbData - SearchTerms $SearchTerms - Types ' Apps' , ' ServicePrincipals' - Limit $Limit - Properties ' id' , ' appId' , ' displayName' , ' publisherName' , ' appOwnerOrganizationId' - TenantFilter $TenantFilter
3333 }
34+ ' Licenses' {
35+ # SKU lookup is universal — always search across all tenants regardless of caller scope.
36+ # No Properties filter so service plan names / friendly names embedded in the JSON
37+ # still pass the secondary verification pass.
38+ $Raw = Search-CIPPDbData - SearchTerms $SearchTerms - Types ' LicenseOverview' - TenantFilter ' allTenants'
39+
40+ $BySku = [ordered ]@ {}
41+ foreach ($Row in $Raw ) {
42+ $Data = $Row.Data
43+ if (-not $Data -or [string ]::IsNullOrWhiteSpace($Data.skuId )) { continue }
44+ $Key = ([string ]$Data.skuId ).ToLowerInvariant()
45+
46+ if (-not $BySku.Contains ($Key )) {
47+ $BySku [$Key ] = [PSCustomObject ]@ {
48+ skuId = [string ]$Data.skuId
49+ skuPartNumber = [string ]$Data.skuPartNumber
50+ displayName = [string ]$Data.License
51+ servicePlans = @ ($Data.ServicePlans )
52+ tenantCount = 0
53+ totalAssigned = 0
54+ totalAvailable = 0
55+ tenants = [System.Collections.Generic.List [object ]]::new()
56+ }
57+ }
58+
59+ $Entry = $BySku [$Key ]
60+ if ([string ]::IsNullOrWhiteSpace($Entry.skuPartNumber ) -and $Data.skuPartNumber ) { $Entry.skuPartNumber = [string ]$Data.skuPartNumber }
61+ if ([string ]::IsNullOrWhiteSpace($Entry.displayName ) -and $Data.License ) { $Entry.displayName = [string ]$Data.License }
62+ if ((-not $Entry.servicePlans -or $Entry.servicePlans.Count -eq 0 ) -and $Data.ServicePlans ) { $Entry.servicePlans = @ ($Data.ServicePlans ) }
63+
64+ $Entry.tenantCount ++
65+ $Used = 0 ; [int ]::TryParse([string ]$Data.CountUsed , [ref ]$Used ) | Out-Null
66+ $Total = 0 ; [int ]::TryParse([string ]$Data.TotalLicenses , [ref ]$Total ) | Out-Null
67+ $Entry.totalAssigned += $Used
68+ $Entry.totalAvailable += $Total
69+ $Entry.tenants.Add ([PSCustomObject ]@ {
70+ tenant = [string ]$Row.Tenant
71+ used = $Used
72+ total = $Total
73+ })
74+ }
75+
76+ $Aggregated = $BySku.Values | Sort-Object - Property tenantCount - Descending | Select-Object - First $Limit
77+
78+ # Shape into the same envelope as other types so the frontend can use match.Data
79+ $Results = foreach ($Item in $Aggregated ) {
80+ [PSCustomObject ]@ {
81+ Tenant = ' '
82+ Type = ' Licenses'
83+ RowKey = " Licenses-$ ( $Item.skuId ) "
84+ Data = $Item
85+ }
86+ }
87+ }
3488 default {
3589 $Results = Search-CIPPDbData - SearchTerms $SearchTerms - Types ' Users' - Limit $Limit - Properties ' id' , ' userPrincipalName' , ' displayName' - TenantFilter $TenantFilter
3690 }
0 commit comments