Private/Write-AACAdvisorRecommendationHtml.ps1
|
function Write-AACAdvisorRecommendationHtml { <# .SYNOPSIS Writes Get-AACAdvisorRecommendation's -HtmlPath report: tiles for recommendations, impact, resources and savings; charts by category, impact, subscription and recommendation; and every recommendation in one interactive table, grouped by recommendation. #> [CmdletBinding()] [OutputType([System.IO.FileInfo])] param( [Parameter(Mandatory)] [AllowEmptyCollection()] [object[]] $Recommendation, [Parameter(Mandatory)] [string] $Path, [string] $Title = 'Azure Advisor recommendations', [System.Collections.IDictionary] $Detail ) $count = { param($Items, [scriptblock] $Where) @($Items | Where-Object $Where).Count } $top = { param($Items, [string] $Property, [int] $First = 10) @($Items | Group-Object -Property $Property | Sort-Object -Property @{ Expression = 'Count'; Descending = $true }, Name | Select-Object -First $First | ForEach-Object { @{ Label = $(if ($_.Name) { $_.Name } else { '(none)' }); Value = $_.Count; Filter = $(if ($_.Name) { $_.Name } else { '(none)' }) } }) } $categoryTone = @{ Cost = 'good'; Security = 'bad'; Reliability = 'info'; OperationalExcellence = 'violet'; Performance = 'warn' } $resources = @($Recommendation | Where-Object ResourceId | ForEach-Object { $_.ResourceId.ToLowerInvariant() } | Select-Object -Unique).Count $tiles = [System.Collections.Generic.List[object]]::new() $tiles.Add(@{ Value = '{0:N0}' -f $Recommendation.Count; Label = 'recommendations'; Tone = 'info'; Table = 'recommendations' }) $tiles.Add(@{ Value = '{0:N0}' -f (& $count $Recommendation { $_.Impact -eq 'High' }); Label = 'high impact'; Tone = 'bad'; Table = 'recommendations'; Filters = @{ Impact = 'High' } }) $tiles.Add(@{ Value = '{0:N0}' -f (& $count $Recommendation { $_.Impact -eq 'Medium' }); Label = 'medium impact'; Tone = 'warn'; Table = 'recommendations'; Filters = @{ Impact = 'Medium' } }) $tiles.Add(@{ Value = '{0:N0}' -f (& $count $Recommendation { $_.Impact -eq 'Low' }); Label = 'low impact'; Tone = 'neutral'; Table = 'recommendations'; Filters = @{ Impact = 'Low' } }) $tiles.Add(@{ Value = '{0:N0}' -f $resources; Label = 'resources affected'; Tone = 'violet' }) # Savings per currency, never converted. foreach ($currency in @($Recommendation | Where-Object { $_.MonthlySavings } | Group-Object SavingsCurrency | Sort-Object Count -Descending | Select-Object -First 2)) { $total = 0.0 foreach ($item in $currency.Group) { $total += [double]$item.MonthlySavings } $tiles.Add(@{ Value = ('{0} {1:N0}' -f $currency.Name, $total).Trim(); Label = 'est. savings / month'; Tone = 'good'; Table = 'recommendations'; Filters = @{ Category = 'Cost' } }) } $retiring = & $count $Recommendation { $_.RetirementDate } if ($retiring) { $tiles.Add(@{ Value = '{0:N0}' -f $retiring; Label = 'affected by retirements'; Tone = 'warn' }) } $byCategory = @(& $top $Recommendation 'Category' 10 | ForEach-Object { $_.Tone = $categoryTone[$_.Label]; $_ }) $byImpact = @(foreach ($impact in 'High', 'Medium', 'Low') { $n = & $count $Recommendation { $_.Impact -eq $impact } if ($n) { @{ Label = $impact; Value = $n; Tone = @{ High = 'bad'; Medium = 'warn'; Low = 'neutral' }[$impact] } } }) $charts = @( @{ Title = 'By category'; Items = $byCategory; Table = 'recommendations'; Column = 'Category' } @{ Title = 'By impact'; Items = $byImpact; Table = 'recommendations'; Column = 'Impact' } @{ Title = 'By subscription'; Items = @(& $top $Recommendation 'SubscriptionName' 10); Table = 'recommendations'; Column = 'SubscriptionName'; Tone = 'violet' } @{ Title = 'Most common recommendations'; Items = @(& $top $Recommendation 'Problem' 10); Table = 'recommendations'; Column = 'Problem'; Wide = $true } ) $table = @{ Id = 'recommendations' Title = 'Recommendations' Note = 'One row per recommendation per resource. Savings are Advisor''s estimates, per currency.' Noun = 'recommendations' File = 'AdvisorRecommendations' Rows = $Recommendation Group = 'Problem' GroupBy = @('Problem', 'Category', 'Impact', 'SubscriptionName', 'ResourceGroup', 'ResourceType') Columns = @( @{ Key = 'Category'; Label = 'Category'; Type = 'badge'; Facet = $true; Tones = $categoryTone } @{ Key = 'Impact'; Label = 'Impact'; Type = 'badge'; Facet = $true; Tones = @{ High = 'bad'; Medium = 'warn'; Low = 'neutral' } } @{ Key = 'Problem'; Label = 'Recommendation'; Type = 'wide' } @{ Key = 'ResourceName'; Label = 'Resource'; Type = 'resource' } @{ Key = 'ResourceType'; Label = 'Type'; Facet = $true; Nowrap = $true } @{ Key = 'ResourceGroup'; Label = 'Resource group'; Facet = $true; Nowrap = $true } @{ Key = 'SubscriptionName'; Label = 'Subscription'; Facet = $true; Nowrap = $true } @{ Key = 'MonthlySavings'; Label = 'Savings / month'; Type = 'money'; Sum = $true; CurrencyKey = 'SavingsCurrency'; Tone = 'good' } @{ Key = 'RetirementDate'; Label = 'Retirement'; Type = 'date'; Soon = $true } @{ Key = 'Solution'; Label = 'Solution'; Type = 'wide' } @{ Key = 'Status'; Label = 'Status'; Type = 'badge'; Facet = $true; Tones = @{ Active = 'info'; Postponed = 'warn'; Dismissed = 'neutral' } } @{ Key = 'LearnMoreLink'; Label = 'Docs'; Type = 'link'; Text = 'Learn more' } @{ Key = 'SubscriptionId'; Label = 'Subscription ID'; Hidden = $true } @{ Key = 'AnnualSavings'; Label = 'Savings / year'; Type = 'money'; Hidden = $true } @{ Key = 'SavingsCurrency'; Label = 'Currency'; Hidden = $true } @{ Key = 'RetiringFeature'; Label = 'Retiring feature'; Hidden = $true } @{ Key = 'PotentialBenefits'; Label = 'Potential benefits'; Hidden = $true } @{ Key = 'LastUpdated'; Label = 'Last updated'; Type = 'date'; Hidden = $true } @{ Key = 'ResourceId'; Label = 'Resource ID'; Hidden = $true } ) } Write-AACHtmlReport -Path $Path -Title $Title -Subtitle "$('{0:N0}' -f $Recommendation.Count) recommendations for $('{0:N0}' -f $resources) resources" -Fact $Detail -Tile $tiles.ToArray() -Chart $charts -Table @($table) } |