src/Private/Measure-WastedSpend.ps1
|
function Measure-WastedSpend { <# .SYNOPSIS Prices the reclaimable licenses and rolls them up into the wasted-spend totals. .DESCRIPTION Takes the raw candidate records from Join-AccountLicense, resolves each SKU to a friendly name and monthly list price, and returns: - PricedReclaimable : each candidate with a priced Skus array and a MonthlyWasteUsd subtotal - Summary : TotalMonthlyUsd, TotalAnnualUsd, account/license counts, and a BySku rollup The BySku rollup is what the FREE report shows; PricedReclaimable (the named list) is gated to FULL. .OUTPUTS PSCustomObject with PricedReclaimable and Summary members. #> [CmdletBinding()] param( [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]] $Reclaimable, [Parameter(Mandatory)] [hashtable] $PriceList ) $pricedReclaimable = New-Object System.Collections.Generic.List[object] $skuAccumulator = @{} # skuId -> rollup record $totalMonthly = 0.0 $licenseCount = 0 $unknownPriceCount = 0 foreach ($candidate in $Reclaimable) { $pricedSkus = New-Object System.Collections.Generic.List[object] $accountMonthly = 0.0 foreach ($skuId in $candidate.SkuIds) { $price = Resolve-SkuPrice -SkuId $skuId -PriceList $PriceList $monthly = [double]$price.MonthlyListUsd $accountMonthly += $monthly $totalMonthly += $monthly $licenseCount++ if ($price.PSObject.Properties.Name -contains 'PriceKnown' -and -not $price.PriceKnown) { $unknownPriceCount++ } $pricedSkus.Add([pscustomobject]@{ SkuId = $price.SkuId Name = $price.Name PartNumber = $price.PartNumber MonthlyListUsd = $monthly }) $key = $price.SkuId.ToLowerInvariant() if (-not $skuAccumulator.ContainsKey($key)) { $skuAccumulator[$key] = [pscustomobject]@{ SkuId = $price.SkuId Name = $price.Name PartNumber = $price.PartNumber Count = 0 MonthlyEachUsd = $monthly MonthlyTotalUsd = 0.0 } } $skuAccumulator[$key].Count++ $skuAccumulator[$key].MonthlyTotalUsd += $monthly } $clone = $candidate | Select-Object * -ExcludeProperty SkuIds $pricedReclaimable.Add(($clone | Add-Member -NotePropertyMembers @{ Skus = $pricedSkus.ToArray() MonthlyWasteUsd = [math]::Round($accountMonthly, 2) } -PassThru)) } $bySku = @($skuAccumulator.Values | Sort-Object -Property MonthlyTotalUsd -Descending) $summary = [pscustomobject]@{ TotalMonthlyUsd = [math]::Round($totalMonthly, 2) TotalAnnualUsd = [math]::Round($totalMonthly * 12, 2) ReclaimableAccountCount = $pricedReclaimable.Count ReclaimableLicenseCount = $licenseCount UnknownPriceSkuCount = $unknownPriceCount BySku = $bySku } [pscustomobject]@{ PricedReclaimable = $pricedReclaimable.ToArray() Summary = $summary } } |