-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
fc928f9
commit 682b644
Showing
51 changed files
with
7,332 additions
and
2 deletions.
There are no files selected for viewing
681 changes: 681 additions & 0 deletions
681
105-Well Architected/tools/Azure_Well_Architected_Review_Sample.csv
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
Category,Description | ||
Survey Level Group,Assess your Security Journey for Cloud Adoption. Receive actionable considerations to improve your security posture. | ||
Business Alignment,"Security transformation is necessary to keep up with the pace of change in cloud platforms, the threat environment, and the evolution of security technologies. Integration of security with business processes is a core component of the methodology focusing on three categories of risk insights, security integration, and operational resiliency." | ||
Access Control,"Organizations must embrace a zero trust approach to access control as they embrace remote work and use cloud technology to digitally transform their business model, customer engagement model, employee engagement, and empowerment model." | ||
Security Operations,Security operations reduce risk by limiting damage from attackers who gain access to your organization's resources. | ||
Asset Protection,"Asset protection implements controls to support security architecture, standards, and policy. Each asset type and security requirement is unique. The security standards for any asset type should be consistently applied to all instances. Start with a proven cloud infrastructure security approach and adapt it to your organization's needs and initial workload deployments." | ||
Security Governance,"Security governance bridges your business priorities with technical implementation like architecture, standards, and policy." | ||
Innovation Security,Innovation security protects the processes and data of innovation against cyberattacks. Innovation in the digital age takes the form of developing applications using the DevOps or DevSecOps method to rapidly innovate without waiting for the traditional waterfall ship schedule that can take months or years between releases. |
421 changes: 421 additions & 0 deletions
421
105-Well Architected/tools/Cloud_Adoption_Security_Review_Sample.csv
Large diffs are not rendered by default.
Oops, something went wrong.
627 changes: 627 additions & 0 deletions
627
105-Well Architected/tools/GenerateAssessmentReport.ps1
Large diffs are not rendered by default.
Oops, something went wrong.
302 changes: 302 additions & 0 deletions
302
105-Well Architected/tools/Go-Live/GenerateWAFReport.ps1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,302 @@ | ||
<# | ||
.SYNOPSIS | ||
Creates a customer presentation PowerPoint deck using PowerShell. | ||
.DESCRIPTION | ||
This script takes a Well-Architected Go-Live Assessment Report as input and generates a customer presentation PowerPoint deck. | ||
The report must be located in the same directory as the following files: | ||
- GenerateWAFReport.ps1 | ||
- PnP_PowerPointReport_Template.pptx | ||
- WAF Category Descriptions.csv | ||
.PARAMETER <AssessmentReport> | ||
The path to the Well-Architected Assessment Report that was generated by the Microsoft Assessments platform in the following format: <pathttothereport.csv>. | ||
.PARAMETER <AsessmentType> | ||
The type of Well-Architected Assessment that was performed. | ||
The value should be 'Go-Live' for a Go-Live Assessment. | ||
The value should be 'Core' for a Reliability, Security, Cost Optimization, Operational Excellence or Performance Efficiency Assessment. | ||
.PARAMETER <YourName> | ||
Your name in the following format: <Firstname Lastname>. | ||
.PARAMETER <YourTitle> | ||
Your title or function in your current organization in the following format: <Title>. | ||
.PARAMETER <YourOrganization> | ||
The organization name you are currently part of in the following format: <Organization>. | ||
.INPUTS | ||
This script takes a Well-Architected Assessment Report in a CSV format as input. | ||
.OUTPUTS | ||
A PowerPoint file will be created within the current directory with name in the format of: Azure Well-Architected $AssessmentType Review - Executive Summary - mmm-dd-yyyy hh.mm.ss.pptx | ||
.NOTES | ||
Version: 1.0 | ||
Author: Farouk Friha | ||
Creation Date: 06/15/2022 | ||
.EXAMPLE | ||
.\GenerateWAFReport.ps1 | ||
-AssessmentReport ".\Go_Live_Well_Architected_Review_Jul_08_2022_4_35_46_PM.csv" | ||
-AssessmentType Go-Live | ||
-YourName "Farouk Friha" | ||
-YourTitle "Cloud Solution Architect" | ||
-YourOrganization "Customer Experience & Success" | ||
.\GenerateWAFReport.ps1 | ||
-AssessmentReport ".\Reliability_Well_Architected_Review_Jul_08_2022_4_35_46_PM.csv" | ||
-AssessmentType Core | ||
-YourName "Farouk Friha" | ||
-YourTitle "Cloud Solution Architect" | ||
-YourOrganization "Customer Experience & Success" | ||
#> | ||
|
||
#---------------------------------------------------------[Initialisations]-------------------------------------------------------- | ||
[CmdletBinding()] | ||
param | ||
( | ||
[Parameter(Mandatory=$True)] | ||
[ValidateScript({Test-Path $_ }, ErrorMessage = "Unable to find the selected file. Please select a valid Well-Architected Assessment report in the <filename>.csv format.")] | ||
[string] $AssessmentReport, | ||
|
||
[Parameter(Mandatory=$True)] | ||
[ValidateSet("Go-Live", "Core")] | ||
[string] $AssessmentType, | ||
|
||
[Parameter(Mandatory=$True)] | ||
[string] $YourName, | ||
|
||
[Parameter(Mandatory=$True)] | ||
[string] $YourTitle, | ||
|
||
[Parameter(Mandatory=$True)] | ||
[string] $YourOrganization | ||
) | ||
|
||
#----------------------------------------------------------[Declarations]---------------------------------------------------------- | ||
|
||
#Get the working directory from the script | ||
$workingDirectory = (Get-Location).Path | ||
|
||
#Get PowerPoint template and description file | ||
$reportTemplate = "$workingDirectory\PnP_PowerPointReport_Template.pptx" | ||
$descriptionsFile = Import-Csv "$workingDirectory\WAF Category Descriptions.csv" | ||
$ratingDescription = @{ | ||
"Critical" = "Based on the outcome of the assessment your workload seems to be in a critical state. Please review the recommendations for each service to resolve key deployment risks and improve your results." | ||
"Moderate" = "Almost there. You have some room to improve but you are on track. Review the recommendations to see what actions you can take to improve your results." | ||
"Excellent" = "Your workload is broadly following the principles of the Well-Architected framework. Review the recommendations to see where you can improve your results even further." | ||
} | ||
|
||
#Initialize variables | ||
$summaryAreaIconX = 385.1129 | ||
$localReportDate = Get-Date -Format g | ||
$reportDate = Get-Date -Format "yyyy-MM-dd-HHmm" | ||
$summaryAreaIconY = @(180.4359, 221.6319, 262.3682, 303.1754, 343.8692, 386.6667) | ||
|
||
#-----------------------------------------------------------[Functions]------------------------------------------------------------ | ||
|
||
#Read input file content | ||
function Read-File($File) | ||
{ | ||
#Get report content | ||
$content = Get-Content $File | ||
|
||
#Get findings | ||
$findingsStartIdentifier = $content | Where-Object { $_.Contains("Category,Link-Text,Link,Priority,ReportingCategory,ReportingSubcategory,Weight,Context") } | Select-Object -Unique -First 1 | ||
$findingsStart = $content.IndexOf($findingsStartIdentifier) | ||
$endStringIdentifier = $content | Where-Object{$_.Contains("--,,")} | Select-Object -Unique -First 1 | ||
$findingsEnd = $content.IndexOf($endStringIdentifier) - 1 | ||
$findings = $content[$findingsStart..$findingsEnd] | Out-String | ConvertFrom-CSV -Delimiter "," | ||
$null = $findings | ForEach-Object { $_.Weight = [int]$_.Weight } | ||
|
||
#Get pillars | ||
$pillars = $findings | ForEach-Object { $_.Category.Split(":")[1].Trim() } | Select-Object -Unique | ||
|
||
#Get scores | ||
$scoresStart = $content.IndexOf("Recommendations for your workload,,,,,,,") + 2 | ||
$scoresEnd = $findingsStart - 5 | ||
$scores = $content[$scoresStart..$scoresEnd] | Out-String | ConvertFrom-Csv -Delimiter "," -Header 'Category', 'Criticality', 'Score' | ||
$null = $scores | ForEach-Object { $_.Score = $_.Score.Trim("'").Replace("/100", ""); $_.Score = [int]$_.Score} | ||
|
||
#Get score per pillar and weight per service | ||
[System.Collections.ArrayList]$scorecard = @{} | ||
|
||
foreach($pillar in $pillars) | ||
{ | ||
#Get services per pillar | ||
$servicesPerPillar = $scores | Where-Object Category -like "*$pillar*" | Select-Object -Property Category, Score | ||
|
||
#Get score per pillar | ||
[int]$scorePerPillar = ($servicesPerPillar.Score | Measure-Object -Sum).Sum / ($servicesPerPillar.Score | Measure-Object -Sum).Count | ||
|
||
#Get recommendations per service | ||
$recommendationsPerService = $findings | Where-Object Category -like "*$pillar*" | Select-Object -Property Category, Weight, Link-Text | Group-Object -Property Category | ||
|
||
#Get weight per service | ||
[System.Collections.ArrayList]$weightPerService = @{} | ||
|
||
foreach($recommendationPerService in $recommendationsPerService) | ||
{ | ||
$firstObject = $recommendationPerService.Group | Sort-Object -Property Weight -Descending | Select-Object -First 1 | ||
|
||
$wObject = [PSCustomObject]@{ | ||
"Service" = $recommendationPerService.Name.Split("-")[2].Split(":")[0].Trim() | ||
"Weight" = [int]($firstObject.Weight) | ||
"Recommendation" = $firstObject."Link-Text" | ||
} | ||
|
||
$null = $weightPerService.Add($wObject) | ||
} | ||
|
||
$sObject = [PSCustomObject]@{ | ||
"Pillar" = $pillar; | ||
"Weights" = $weightPerService; | ||
"Score" = $scorePerPillar; | ||
"Description" = ($descriptionsFile | Where-Object{$_.Pillar -eq $pillar -and $_.Category -eq "Survey Level Group"}).Description; | ||
"Rating" = Get-Rating -WeightOrScore $scorePerPillar | ||
} | ||
|
||
$null = $scorecard.Add($sObject) | ||
} | ||
|
||
$scorecard = $scorecard | Sort-Object -Property Score | ||
$overallScore = $content[3].Split(',')[2].Trim("'").Split('/')[0] | ||
$overallRating = Get-Rating -WeightOrScore $overallScore | ||
|
||
return $scorecard, $overallScore, $overallRating | ||
} | ||
|
||
function Get-Rating($WeightOrScore) | ||
{ | ||
if($WeightOrScore -lt 33) | ||
{ | ||
$rating = "Critical" | ||
} | ||
elseif($WeightOrScore -ge 33 -and $WeightOrScore -lt 67) | ||
{ | ||
$rating = "Moderate" | ||
} | ||
elseif($WeightOrScore -ge 67) | ||
{ | ||
$rating = "Excellent" | ||
} | ||
|
||
return $rating | ||
} | ||
|
||
function Edit-Slide($Slide, $StringToFindAndReplace, $Gauge, $Counter) | ||
{ | ||
$StringToFindAndReplace.GetEnumerator() | ForEach-Object { | ||
|
||
if($_.Key -like "*Threshold*") | ||
{ | ||
$Slide.Shapes[$_.Key].Left = [single]$_.Value | ||
} | ||
else | ||
{ | ||
$Slide.Shapes[$_.Key].TextFrame.TextRange.Text = $_.Value | ||
} | ||
|
||
if($Gauge) | ||
{ | ||
$Slide.Shapes[$Gauge].Duplicate() | Out-Null | ||
$Slide.Shapes[$Slide.Shapes.Count].Left = [single]$summaryAreaIconX | ||
$Slide.Shapes[$Slide.Shapes.Count].Top = $summaryAreaIconY[$Counter] | ||
} | ||
} | ||
} | ||
|
||
function Clear-Presentation($Slide) | ||
{ | ||
$slideToRemove = $Slide.Shapes | Where-Object {$_.TextFrame.TextRange.Text -match '^\[Pillar\]$'} | ||
$shapesToRemove = $Slide.Shapes | Where-Object {$_.TextFrame.TextRange.Text -match '^\[(W|Resource_Type_|Recommendation_)?[0-9]\]$'} | ||
|
||
if($slideToRemove) | ||
{ | ||
$Slide.Delete() | ||
} | ||
elseif ($shapesToRemove) | ||
{ | ||
foreach($shapeToRemove in $shapesToRemove) | ||
{ | ||
$shapeToRemove.Delete() | ||
} | ||
} | ||
} | ||
|
||
#-----------------------------------------------------------[Execution]------------------------------------------------------------ | ||
#Read input file | ||
$scorecard, $overallScore, $overallRating = Read-File -File $AssessmentReport | ||
|
||
#Instantiate PowerPoint variables | ||
$application = New-Object -ComObject PowerPoint.Application | ||
$reportTemplateObject = $application.Presentations.Open($reportTemplate) | ||
$slides = @{ | ||
"Cover" = $reportTemplateObject.Slides[1]; | ||
"Summary" = $reportTemplateObject.Slides[8]; | ||
"Detail" = $reportTemplateObject.Slides[9]; | ||
"End" = $reportTemplateObject.Slides[10] | ||
} | ||
|
||
#Edit cover slide | ||
$coverSlide = $slides.Cover | ||
$stringsToReplaceInCoverSlide = @{ "Cover - Assessment_Type" = "Well-Architected $AssessmentType Review"; "Cover - Your_Name" = $YourName; "Cover - Your_Title" = $YourTitle; "Cover - Your_Organization" = $YourOrganization; "Cover - Report_Date" = "Report generated: $localReportDate" } | ||
Edit-Slide -Slide $coverSlide -StringToFindAndReplace $stringsToReplaceInCoverSlide | ||
|
||
#Edit summary slide | ||
$stringsToReplaceInSummarySlide = @{ "Summary - Score_Overall" = $overallScore; "Summary - Rating_Description" = $ratingDescription.$overallRating; "Summary - Threshold" = [int]$overallScore*2.47+56 } | ||
Edit-Slide -Slide $slides.Summary -StringToFindAndReplace $stringsToReplaceInSummarySlide | ||
|
||
$i = 0 | ||
|
||
#Duplicate, move and edit summary and detail slides for each pillar | ||
foreach($pillar in $scorecard.Pillar) | ||
{ | ||
$i++ | ||
$scoreForCurrentPillar = $scorecard | Where-Object{$_.Pillar -contains $pillar} | ||
|
||
#Add score per pillar | ||
$stringsToReplaceInSummarySlide = @{ "Summary - Pillar_$i" = $pillar; "Summary - Score_$i" = [string]$scoreForCurrentPillar.score } | ||
Edit-Slide -Slide $slides.Summary -StringToFindAndReplace $stringsToReplaceInSummarySlide -Gauge "Summary - $($scoreForCurrentPillar.Rating)_Gauge" -Counter $i | ||
|
||
#Add services that need attention | ||
$newDetailSlide = $slides.Detail.Duplicate() | ||
$newDetailSlide.MoveTo($reportTemplateObject.Slides.Count-1) | ||
$stringsToReplaceInDetailSlide = @{ "Detail - Pillar" = $pillar; "Detail - Pillar_Description" = $scoreForCurrentPillar.Description; "Detail - Pillar_Score" = [string]$scoreForCurrentPillar.Score; "Detail - Threshold" = [int]$scoreForCurrentPillar.Score*2.47+56} | ||
Edit-Slide -Slide $newDetailSlide -StringToFindAndReplace $stringsToReplaceInDetailSlide | ||
|
||
if(($scoreForCurrentPillar.Weights."Service" | Measure-Object).Count -lt 5) | ||
{ | ||
$servicesPerPillar = $scoreForCurrentPillar.Weights | Sort-Object -Property "Weight" -Descending | Select-Object -First ($scoreForCurrentPillar.Weights."Service" | Measure-Object).Count | ||
} | ||
else | ||
{ | ||
$servicesPerPillar = $scoreForCurrentPillar.Weights | Sort-Object -Property "Weight" -Descending | Select-Object -First 5 | ||
} | ||
|
||
$j = 0 | ||
|
||
foreach($servicePerPillar in $servicesPerPillar) | ||
{ | ||
$j++ | ||
$stringsToReplaceInDetailSlide = @{ "Detail - Resource_Type_$j" = [string]$servicePerPillar."Service"; "Detail - Weight_$j" = [string]$servicePerPillar.Weight; "Detail - Recommendation_$j" = [string]$servicePerPillar."Recommendation"} | ||
Edit-Slide -Slide $newDetailSlide -StringToFindAndReplace $stringsToReplaceInDetailSlide | ||
} | ||
|
||
#Remove empty shapes from detail slides | ||
Clear-Presentation -Slide $newDetailSlide | ||
} | ||
|
||
#Remove empty detail slides | ||
Clear-Presentation -Slide $slides.Detail | ||
|
||
#Save presentation and close object | ||
$reportTemplateObject.SavecopyAs(“$workingDirectory\Azure Well-Architected $AssessmentType Review - Executive Summary - $reportDate.pptx”) | ||
$reportTemplateObject.Close() | ||
|
||
$application.quit() | ||
$application = $null | ||
[gc]::collect() | ||
[gc]::WaitForPendingFinalizers() |
3 changes: 3 additions & 0 deletions
3
105-Well Architected/tools/Go-Live/PnP_PowerPointReport_Template.pptx
Git LFS file not shown
Oops, something went wrong.