diff --git a/docs/content/tools-old/_index.md b/docs/content/tools-old/_index.md
deleted file mode 100644
index f415d1d2f..000000000
--- a/docs/content/tools-old/_index.md
+++ /dev/null
@@ -1,13 +0,0 @@
----
-title: Tools(Legacy)
-weight: 48
-geekdocCollapseSection: true
----
-
-This section lists of all of the information pertaining to the legacy APRL tooling/scripts. The guidance is broken down into the following sections:
-
-- [Collector Script Documentation](/Azure-Proactive-Resiliency-Library-v2/tools-old/collector)
-- [Analyzer Script Documentation](/Azure-Proactive-Resiliency-Library-v2/tools-old/analyzer)
-- [Reports Script Documentation](/Azure-Proactive-Resiliency-Library-v2/tools-old/reports)
-
-{{< toc >}}
diff --git a/docs/content/tools-old/analyzer/_index.md b/docs/content/tools-old/analyzer/_index.md
deleted file mode 100644
index 88d6ca48d..000000000
--- a/docs/content/tools-old/analyzer/_index.md
+++ /dev/null
@@ -1,122 +0,0 @@
----
-title: Analyzer Script
-weight: 20
-geekdocCollapseSection: false
----
-
-{{< toc >}}
-
-## Overview
-
-This Data Analyzer script is the second script used during Well-Architected Reliability Assessment (WARA) engagements. Based on the data generated by the Collector script, the Data Analyzer script collects the necessary information about recommendations from the Azure Proactive Resiliency Library (APRL) and generates an Action Plan Excel spreadsheet. The goal of this tool is to summarize the collected data and provide actionable insights into the health and resiliency of the Azure environment.
-
-## Requirements
-
-- Windows OS
-- [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.4)
-- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
-- Microsoft Excel installed
-- Role Based Access Control: Reader role to access to resources to be evaluated. Although access to the Azure Subscriptions is not required to run the script, the access will be required for the user to complete some manual validations of configurations of Azure resources after the script generates the Excel file.
-
-## Quick Start (Local Machine only - Cloud Shell is not supported)
-
-- Download and run the analyzer script by copying and modifying this script block
-- Once the script is downloaded you can execute it by running ./2_wara_data_analyzer.ps1
-
-```powershell
-#Create new "WARA" directory under C:\ and navigate to C:\WARA. If not Windows then do nothing and move on.
-$iswindows ? $(mkdir C:\WARA -ErrorAction SilentlyContinue;cd C:\WARA) : (Write-Host "C:\WARA - Not Required")
-
-#Download the latest version of the script
-invoke-webrequest https://aka.ms/aprl/tools/2 -out 2_wara_data_analyzer.ps1
-
-#Remove file blocking if active and running windows
-$iswindows ? (unblock-file ./2_wara_data_analyzer.ps1) : (Write-host "Unblock not required - Not Windows OS")
-
-#Modify these parameters and run the script
-./2_wara_data_analyzer.ps1 -JSONFile .\WARA_File_2024-08-08-11-57.json
-```
-
-## How to Download
-
-- [GitHub Link to Download](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/2_wara_data_analyzer.ps1)
-- Download the script using command-line
-
- ```shell
- iwr https://aka.ms/aprl/tools/2 -out 2_wara_data_analyzer.ps1
- ```
-
-- [GitHub Link to Sample Output](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/sample-output/WARA%20Action%20Plan%202024-05-07_12_07.xlsx)
-
-## How to run the script
-
-{{< hint type=important >}}
-The Data Analyzer script must be run from a Windows Machine with Excel installed.**
-{{< /hint >}}
-
-1. Change your directory to the same location that you have downloaded the WARA Data Analyzer script to.
- - We recommend running this as close to your C:\ as path to avoid errors related to file path length.
- {{< figure src="../../img/tools/collector-7.png" width="40%" >}}
-
-1. Execute script pointing the -JSONFile parameter to file created by the WARA Collector script.
- - The script accepts both short and/or full paths.
- {{< figure src="../../img/tools/analyzer-1.png" width="100%" >}}
-
-1. Select "R" to allow script to run
- {{< figure src="../../img/tools/analyzer-2.png" width="100%" >}}
-
-1. After the script completes it will create a file called `WARA Action Plan.xlsx` to the same file path.
-
-## Action Plan Analysis
-
-1. Once the script has completed, open the Excel Action Plan and familiarize yourself with the structure of the file, generated data, resources collected, pivot tables, and charts created.
- - These are the worksheets:
- - **Recommendations**: you will find all Recommendations, their category, impact, description, learn more links, and much more.
- - Note that Columns A and B are counting the number of Azure Resources associated with the RecommendationID.
- - **ImpactedResources**: you will find a list of Azure Resources associated with a RecommendationID. These are the Azure Resources NOT following Microsoft best practices for Reliability.
- - **Other-OutOfScope**: you will find a list of the Resources that are Out of Scope of the WARA engagement based on the ResourceTypes, after all filters have been applied.
- - **ResourceTypes**: you will find a list of all ResourceTypes the customer is using, number of Resources deployed for each one, and if there are Recommendations for the ResourceType in APRL.
- - **Outages**: you will find a list of all the outages that impacted the subscriptions (this worksheet might not exist if there are no Outages to be found).
- - **Retirements**: Azure services or features that are retired. You will find a list of all the next retirements in the subscriptions (this worksheet might not exist if there are no Retirements to be found).
- - **Support Tickets**: you will find a list of all the Support Tickets for the subscriptions in the past 6 months (this worksheet might not exist if there are no Support Tickets to be found).
- - **PivotTable**: you will find a couple of pivot tables used to automatically create the charts
- - **Charts**: you will find 3 charts that will be used in the Executive Summary PPTx
- - At this point, all Azure Resources with recommendations and Azure Resource Graph queries available in APRL, were automatically validated. Follow the next steps to validate the remaining services without automation or that does not exist in APRL yet.
-1. Go to the **ImpactedResources** worksheet, filter Column **A** by **IMPORTANT**, and validate manually the remaining resources for reliability.
- - **IMPORTANT - Query under development** - For each Azure Resource in each row in this category, the resource could not be validated automatically because the associated recommendation in APRL does not have a KQL/Azure Resource Graph Query yet, thus manual validation is necessary. Using the GUID of the Recommendation, go to the "Recommendations" worksheet, read the recommendation, then open the Azure Portal and validate if the resource is compliant with the recommendations. If it is compliant, delete the row.
- - **IMPORTANT - Recommendation cannot be validated with ARGs - Validate Resources manually** - For each Azure Resource in each row in this category, the resource could not be validated automatically because the associated recommendation in APRL is not possible to be validated with KQL/Azure Resource Graph Query, thus manual validation is necessary. Using the GUID of the Recommendation, go to the "Recommendations" worksheet, read the recommendation, then open the Azure Portal and validate if the resource is compliant with the recommendations. If it is compliant, delete the row.
- - **IMPORTANT - ServiceType Not Available in APRL - Validate Resources manually if Applicable, if not delete this row** - For each Azure Resource in each row in this category, the resource could not be validated automatically because there are no recommendations in APRL or Advisor for the Service, thus manual validation is necessary. Based on the Azure Documentation for each Service, go to the "Recommendations" worksheet, create your own recommendations for Reliability, then open the Azure Portal and validate if the resources are compliant with the recommendation you created. If they are compliant, delete the rows in the "ImpactedResources".
-1. Remove/add any recommendations based on your analysis prior to generating reports
-1. For relevant Outages, all Service Retirements, and relevant Support Tickets, create actionable Recommendations in the "Recommendations" worksheet.
-1. Once all manual validations of the resources in the "ImpactedResources" worksheet categorized by "IMPORTANT" are completed, and all recommendations for Service Retirements, Support Tickets and Outages were created in the "Recommendations" worksheet, the Action Plan is completed and it is time to run the last script that will generate final reports in Word and PowerPoint formats.
-1. Read how to execute the [Reports Script](../reports/_index.md) to generate the final Word and PowerPoint reports.
-
-## PARAMETERS
-
-### Debugging
-
-Switch to enable debugging mode.
-
-- **Required**: No
-- **Position**: Named
-
-### Help
-
-Switch to display help information.
-
-- **Required**: No
-- **Position**: Named
-
-### JSONFile
-
-Path to the JSON file created by the `2_wara_data_analyzer.ps1` script.
-
-- **Required**: Yes
-- **Position**: 0
-
-## EXAMPLES
-
-### Example 1
-
-```powershell
-.\2_wara_data_analyzer.ps1 -JSONFile '.\WARA_File_2024-04-01-10-01.json'
diff --git a/docs/content/tools-old/collector/_index.md b/docs/content/tools-old/collector/_index.md
deleted file mode 100644
index 59e825bb0..000000000
--- a/docs/content/tools-old/collector/_index.md
+++ /dev/null
@@ -1,501 +0,0 @@
----
-title: Collector Script
-weight: 10
-geekdocCollapseSection: false
----
-
-{{< toc >}}
-
-## Overview
-
-This script is part of the Microsoft Well-Architected Reliability Assessment (WARA) engagement. It helps customers validate whether their Azure resources are architected and configured according to Microsoft best practices. The script achieves this by running Azure Resource Graph queries (Kusto/KQL) against Azure subscriptions and resources. Additionally, it collects information about closed support tickets, active Azure Advisor reliability recommendations, past Azure Service Health retirement and outage notifications, and the configuration of Azure Service Health alerts, all of which are relevant for the reliability recommendations provided at the end of the engagement. The collected data is then structured and exported into a JSON file, which is later used as input for the second script, the Data Analyzer script (2_wara_data_analyzer.ps1).
-
-{{< hint type=important >}}
-These Azure Resource Graph queries only read ARM (Azure Resource Manager) data. They do not access or collect any keys, secrets, passwords, or other confidential information. The queries only gather information about how resources are deployed and configured. If you would like to learn more, you can explore the Azure Resource Graph Explorer and run some of the query examples provided in the Azure portal.
-{{< /hint >}}
-
-## Requirements
-
-- [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.4)
-- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
-- [Azure PowerShell modules](https://learn.microsoft.com/en-us/powershell/azure/install-azps-windows?view=azps-12.1.0&tabs=powershell&pivots=windows-psgallery)
- - Az.ResourceGraph
- - Az.Accounts
-- Role Based Access Control: Reader role to access to resources to be evaluated
-
-## Quick Start (Cloud Shell or Local Machine)
-
-- We recommend running the script from a *Non-OneDrive* folder.
- - The script block below will handle this for you.
-- Download and run the collector script by copying and modifying this script block
-- You must replace the TenantID and SubscriptionIds/ResourceGroups to match your tenant and scope resource ids.
-- Once the script is downloaded you can execute it by running ./1_wara_collector.ps1
-
-```powershell
-#Create new "WARA" directory under C:\ and navigate to C:\WARA. If not Windows then do nothing and move on.
-$iswindows ? $(mkdir C:\WARA -ErrorAction SilentlyContinue;cd C:\WARA) : (Write-Host "C:\WARA - Not Required")
-
-#Download the latest version of the script
-invoke-webrequest https://aka.ms/aprl/tools/1 -out 1_wara_collector.ps1
-
-#Remove file blocking if active and running windows
-$iswindows ? (unblock-file ./1_wara_collector.ps1) : (Write-host "Unblock not required - Not Windows OS")
-
-#Modify these parameters and run the script
-./1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000"
-```
-
-### Local Machine
-
-
-
-### Cloud Shell
-
-
-
-## How to download
-
-- [GitHub Link to Download](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/1_wara_collector.ps1)
-
-- Download the script using command-line
-
- ```shell
- iwr https://aka.ms/aprl/tools/1 -out 1_wara_collector.ps1
- ```
-
-- [GitHub Link to Sample Output](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/sample-output/WARA_File_2024-05-07_11_59.json)
-
-## How to run the script
-
-See at the end of this page various examples of how to run this script - [Examples](#how-to-run-the-1_wara_collectorps1)
-
-**You have two options to run the collector script:**
-
-1. Cloud Shell
-
-1. Local Machine - Requires current modules leveraged in the script be installed
-
-### 1.1 - Cloud Shell
-
-1. From the [Azure Portal](https://portal.azure.com/) open Cloud Shell, select PowerShell instead of BASH
- - If this is your first time using Cloud Shell, refer to the getting started guide from Microsoft Learn - [Azure Cloud Shell](https://learn.microsoft.com/en-us/azure/cloud-shell/get-started/classic?tabs=azurecli#start-cloud-shell).
- {{< figure src="../../img/tools/collector-1.png" width="100%" >}}
-
-1. Upload the WARA Collector Script to Cloud Shell
- {{< figure src="../../img/tools/collector-2.png" width="60%" >}}
- Or download the script from GitHub
-
- ```shell
- iwr https://aka.ms/aprl/tools/1 -out 1_wara_collector.ps1
- ```
-
-1. Execute script leveraging parameters
- - The script accepts both short and/or full paths.
- {{< figure src="../../img/tools/collector-3.png" width="100%" >}}
- For complex Subscription, ResourceGroups and Tags filtering scenarios we highly recommend using [ConfigFiles - See here an example under config.txt in Example 5](#example-5)
-
-1. Select "A" to allow modules to install
- {{< figure src="../../img/tools/collector-4.png" width="100%" >}}
-
-1. After Script completes, download the produced json file to your machine
- {{< figure src="../../img/tools/collector-5.png" width="100%" >}}
-
-1. Read how to execute the [Analyzer Script](../analyzer/) to generate the Excel report.
-
-### 1.2 Local Machine
-
-1. To run the script there are 5 prerequisites that must be completed first:
- 1. **The script must be executed from PowerShell 7. Other versions are not supported, for example: Windows PowerShell and PowerShell ISE**
- {{< figure src="../../img/tools/collector-6.png" width="40%" >}}
- 1. **Git must be installed on the local machine - [Git](https://git-scm.com/download/win)**
- 1. **Install required PowerShell Modules:**
- - `Install-Module -Name ImportExcel -Force -SkipPublisherCheck`
- - `Install-Module -Name Az.ResourceGraph -SkipPublisherCheck`
- - `Install-Module -Name Az.Accounts -SkipPublisherCheck`
- 1. **Unblock the Script**
- - So at this moment, you need to allow the execution of scripts not signed locally:
- - `Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser`
- - `Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope LocalMachine`
- 1. **Reader permissions to target subscription(s)**
-
-1. Open a new **PowerShell 7 session** after completing prerequisites
-
-1. Change your directory to the same location where you are hosting your WARA Collector script.
-
- - We recommend running this as close to your `C:\` as path to avoid errors related to file path length. Create a `c:\wara\` folder and save all scripts in this folder.
- {{< figure src="../../img/tools/collector-7.png" width="40%" >}}
-
-1. Access the folder `c:\wara\` and Execute script leveraging the necessary parameters
-
- - {{< figure src="../../img/tools/collector-8.png" width="100%" >}}
-
-1. Authenticate with the account that has Reader permissions to the target subscription(s)
- {{< figure src="../../img/tools/collector-9.png" width="40%" >}}
-
-1. After script completes, a json file with all the results will be saved to the same folder location.
-
-1. Read how to execute the [Analyzer Script](../analyzer/) to generate the Excel report.
-
-## Resource Filtering
-
-The filtering capabilities are designed for targeting specific Azure resources, enabling precise and flexible reliability assessments. The scope of the feature includes functionalities that allow users to define the scope and tags and criteria of their reliability checks using parameters or text files.
-
-### Order of operations
-
-1. Subscriptions
- - Subscription scopes like `-SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000"` or `[subscriptionIds]`
-
- `/subscriptions/11111111-1111-1111-1111-111111111111` in a configuration file always take explicit precedence over any smaller, more specific scope.
-
-1. Resource Groups
- - These scopes can be used explicitly where you need to grab a resource group from a subscription but not evaluate the whole subscription.
-
-1. Tags
- - When your resources have been explicitly scoped as above - the script will then further refine your results based on the tags provided to the script via parameters or configuration file.
-
-### Filtering Considerations
-
-- If you set a subscription filter for `subscription1` and you also set a resource group filter for `subscription1/resourcegroups/rg-demo1` your results will contain **all** of the resources in `subscription1`
- - This is because we specified `subscription1` and so all of `subscription1` will be evaluated. If we only wanted to evaluate `subscription1/resourcegroups/rg-demo1` then we would include that resource group as a filter and not the full subscription.
-- If you set a subscription filter for `subscription2` and a resourcegroup filter for `subscription1/resourcegroups/rg-demo1` you will evaluate all of `subscription2` and only the resource group `rg-demo-1`.
-- Setting a subscription filter for `subscription3`, a resource group filter for `subscription1/resourcegroups/rg-demo1`, and a tag filter for `environment=~prod` will return only resources or those in resource groups tagged with `environment=~prod` within subscription3 and `subscription1/resourcegroups/rg-demo1`.
-
-### Tags Filtering
-
-The tag filtering feature can be broken into two distinct types:
-
-- `=~` Equals (non-case sensitive) to define your name/value pair values.
-- `!~` Not Equals (non-case sensitive) to define your name/value pair values.
-
-These tags can be further broken down into their `Key:Value` pairs and allow for the following logical operands:
-
-- `||` Or operations, when one or more TagName(s) could be equal to one or more TagValue(s).
-
-This separator to separate name/value pairs.
-
-- `,` to separate name/value pairs.
-
-This allows you to build logical tag filtering:
-
-- The following example shows where the tag name can be `App` or `Application` and the value attributed to these tag names must be `App1` or `App2`. In addition, a new entry acts as an `AND` operator. So the first line must be true, so must the second line where we state that the tag name can be `env` or `environment` and the value can be `prod` or `production`. Only when all of these criteria are met would a resource become included in the output file.
-
-In the configFile.txt the configuration looks like:
-
-```text
-[tags]
-App||Application=~App1||App2
-env||environment=~prod||production
-```
-
-In PowerShell command line the configuration looks like:
-
-```powershell
--tags "App||Application=~App1||App2","env||environment=~prod||production""
-```
-
-- Our next example will demonstrate how we can filter using a `NOT` operator. This will return all resources in scope, except those that meet the requirements of `app` or `application` not equalling `App3`, `env` or `environment` not equalling `dev` or `qa`.
-
-In the configFile.txt the configuration looks like:
-
-```text
-[tags]
-App||Application!~App3
-env||environment!~dev||qa
-```
-
-In PowerShell command line the configuration looks like:
-
-```powershell
--tags "App||Application!~App3","env||environment!~dev||qa""
-```
-
-## Runbooks
-
-{{< hint type=important >}}
-Runbooks are an advanced feature designed for specific workload-aligned use cases. If you're not sure if you need runbooks, you probably don't. Before diving into runbooks, [try using the filtering feature to see if it meets your needs](#resource-filtering).
-{{< /hint >}}
-
-Learn more about using runbooks with the WARA collector script in the [runbooks docs](runbooks.md).
-
-## How to run the 1_wara_collector.ps1
-
-### Example 1
-
-The workload is entirely hosted in a single subscription that is not shared with other workloads:
-
-Provide parameters in command line:
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000"
-```
-
-Provide parameters via ConfigFile:
-
-```powershell
-.\1_Wara_Collector.ps1 -configFile config.txt
-```
-
-config.txt
-
-```text
-[tenantId]
-00000000-0000-0000-0000-000000000000
-
-[subscriptionIds]
-/subscriptions/00000000-0000-0000-0000-000000000000
-```
-
-### Example 2
-
-The workload is hosted in two subscriptions (Sub-0 and Sub-5), but the Sub-5 subscription is shared with other workloads. I want to filter it by a single ResourceGroup specifically where the components of my workload are hosted:
-
-Provide parameters in command line:
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" -ResourceGroups "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/RG-1"
-```
-
-Provide parameters via ConfigFile:
-
-```powershell
-.\Wara_Collector.ps1 -configFile config.txt
-```
-
-config.txt
-
-```text
-[tenantId]
-00000000-0000-0000-0000-000000000000
-
-[subscriptionIds]
-/subscriptions/00000000-0000-0000-0000-000000000000
-
-[resourceGroups]
-/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/RG-1
-```
-
-{{< hint type=important >}}
-As you're filtering Sub-5 by ResourceGroup, do not pass Sub-5 in the Subscriptions parameter.
-{{< /hint >}}
-
-### Example 3
-
-The workload is hosted in three subscriptions (Sub-0, Sub-3, and Sub-5). However, since the Sub-5 subscription is shared with other workloads, I need to filter it not only by a specific Resource Group where the components of my workload are hosted but also by two tags, Criticality and Env, as all my subscriptions are hosting non-production resources as well.
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000","/subscriptions/33333333-3333-3333-3333-333333333333" -ResourceGroups "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/RG-1" -Tags 'Criticality=~High','Env=~Prod'
-```
-
-Provide parameters via ConfigFile:
-
-```powershell
-.\1_Wara_Collector.ps1 -configFile config.txt
-```
-
-config.txt
-
-```text
-[tenantid]
-00000000-0000-0000-0000-000000000000
-
-[subscriptionIds]
-/subscriptions/00000000-0000-0000-0000-000000000000
-/subscriptions/33333333-3333-3333-3333-333333333333
-
-[resourceGroups]
-/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/RG-1
-
-[tags]
-Criticality=~High
-Env=~Prod
-```
-
-{{< hint type=important >}}
-NAS you're filtering Sub-5 by ResourceGroup, you do not pass Sub-5 in the Subscriptions parameter. In this scenario, the script will set as scope all resources in Sub-0 and Sub-3, and in Sub5/RG1, as long as they all have both Tags, Criticality and Env equal to the values that I defined, High and Prod. Resource that do meet these requirements will be put in a separate array called "out-of-scope", you will see a Worksheet in the excel file with this name and all resources not validated by the tool.
-{{< /hint >}}
-
-### Example 4
-
-The workload is hosted in three subscriptions (Sub-0, Sub-4, and Sub-5). However, since the Sub-4 and Sub-5 subscriptions are shared with other workloads, I need to filter them not only by the Resource Groups where the components of my workload are hosted but also by two tags, Criticality and Env, as all my subscriptions are hosting non-production resources as well.
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" -ResourceGroups "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/RG-1","
-","/subscriptions/44444444-4444-4444-4444-444444444444/resourceGroups/RG-2" -Tags 'Criticality=~High','Env=~Prod'
-```
-
-Provide parameters via ConfigFile:
-
-```powershell
-.\Wara_Collector.ps1 -configFile config.txt
-```
-
-config.txt
-
-```text
-[tenantid]
-00000000-0000-0000-0000-000000000000
-
-[subscriptionIds]
-/subscriptions/00000000-0000-0000-0000-000000000000
-
-[resourceGroups]
-/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/RG-1
-/subscriptions/44444444-4444-4444-4444-444444444444/resourceGroups/RG-2
-
-[tags]
-Criticality=~High
-Env=~Prod
-```
-
-{{< hint type=note >}}
-Multiple values do not have to be in the same subscription. You can specify multiple resource groups in unique subscriptions.
-{{< /hint >}}
-
-{{< hint type=note >}}
-In the configuration file, we separate multiple entries for a filter by new lines. Where as, from the command line we would pass multiple subscriptions or resource groups using the "string1","string2" pattern. The configuration file is useful for repeated runs, or numerous filters where it may be difficult to troubleshoot syntax in the command line.
-{{< /hint >}}
-
-### Example 5
-
-The workload is hosted across three subscriptions (Sub-0, Sub-4, and Sub-5). Since Sub-4 and Sub-5 are shared with other workloads, I need to filter them by specific Resource Groups where my workload components are located, as well as by two sets of tags: 'Criticality' and 'Env' (or 'Environment'). This filtering will ensure that non-production resources, such as QA and DEV environments, are excluded from my assessment.
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" -ResourceGroups "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/RG-1","
-","/subscriptions/44444444-4444-4444-4444-444444444444/resourceGroups/RG-2" -Tags 'Criticality=~High','Env||Environment!~Dev||QA'
-```
-
-Provide parameters via ConfigFile:
-
-```powershell
-.\Wara_Collector.ps1 -configFile config.txt
-```
-
-config.txt
-
-```text
-[tenantId]
-00000000-0000-0000-0000-000000000000
-
-[subscriptionIds]
-/subscriptions/00000000-0000-0000-0000-000000000000
-
-[resourceGroups]
-/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/RG-1
-/subscriptions/44444444-4444-4444-4444-444444444444/resourceGroups/RG-2
-
-[tags]
-Criticality=~High
-Env||Environment!~Dev||QA
-```
-
-### Runbook Example
-
-{{< hint type=tip >}}
-Learn more about runbooks [here](/Azure-Proactive-Resiliency-Library-v2/tools/collector/runbooks/)
-{{< /hint >}}
-
-Run a runbook.
-
-```powershell
-.\1_wara_collector.ps1 `
- -TenantID "00000000-0000-0000-0000-000000000000" `
- -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" `
- -RunbookFile ".\runbook.json"
-```
-
-Run a runbook using implicit runbook selectors.
-
-```powershell
-.\1_wara_collector.ps1 `
- -TenantID "00000000-0000-0000-0000-000000000000" `
- -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" `
- -RunbookFile ".\runbook.json"
- -UseImplicitRunbookSelectors
-```
-
-{{< hint type=caution >}}
-Note that `-SubscriptionIds` are required when using a runbook. Runbooks are not compatible with `-ConfigFile`, `-ResourceGroups`, `-Tags`, `-SAP`, `-AVS`, `-HPC`, `-AVD` parameters. Specify subscriptions in scope using `-SubscriptionIds` parameter.
-{{< /hint >}}
-
-## Parameters
-
-When calling the Collector script, you must provide some required parameters. Optional parameters can also be included. See the list below:
-
-- **TenantID**
- - Required
- - Description: Target Tenant where the workload resides
- - Type: String (GUID)
- - Example:
- - `"00000000-0000-0000-0000-000000000000"`
-- **SubscriptionIds**
- - Required if ResourceGroups is not provided
- - Description: Specifies Subscription(s) to be included in the analysis.
- - Type: String array
- - Example:
- - `"/subscriptions/00000000-0000-0000-0000-000000000000","/subscriptions/AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA"`
-- **ResourceGroups**
- - Required if SubscriptionIds is not provided
- - Description: Specifies Resource Group(s) to be included in the analysis
- - Type: String array
- - Example:
- - `"/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ResourceGroup1","/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ResourceGroup2"`
-- **Tags**:
- - Optional
- - Type: String array
- - Description: Specifies Tags to be used for filtering the resources.
- - Operators:
- - **=~** for "Equal" (non-case sensitive) to define your name/value pair values.
- - **!~** for "Non Equal" (non-case sensitive) to define your name/value pair values.
- - **||** for "Or" operations, when one or more TagName(s) could be equal to one or more TagValue(s).
- - **,** to separate name/value pairs.
- - Examples:
- - `"TagName=~TagValue"`
- - `"TagName=~TagValue","TagName1=~TagValue1"`
- - `"TagName1||TagName2=~TagValue1"`
- - `"TagName1=~TagValue1||TagValue2"`
- - `"TagName1||TagName2=~TagValue1||TagValue2"`
- - `"Env||Environment=~Production||Prod","App=~Ecommerce"`
- - (Result: Subscriptions or ResourceGroups or Resources must have the Tag `Env` OR `Environment` EQUAL to `Production` OR `Prod`, AND must have the Tag `App` EQUAL to `Ecommerce` or `Ecom` (All non-case sensitive). If the Tag requirement is met at Subscription level, all Resources within the Subscription are included, if met at ResourceGroup level, all ResourceGroups with the Tags and all their resources are included; if only met at the Resource level, then only resources that met the tag requirement are included).
-- **ConfigFile**:
- - Required when the following parameters are nor provided via command line: `TenantId`, `SubscriptionIDs`, `ResourceGroups` .
- - **Note**: It can't be used in combination with command line parameters.
- - Description: Alternate option to providing command line parameters. Specifies a file for filtering of Subscription, ResourceGroup, ResourceId, and Tags.
- - Type: String (file name and extension)
- - Example:
- - `-configFile configFileName.txt`
- - See ConfigFile example [here](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/configfile.example)
-- **AzureEnvironment**:
- - Optional
- - Description: Specifies the Azure Environment to used for the analysis: AzureCloud, AzureUSGovernment.
- - Type: String
- - Examples:
- - `-AzureEnvironment AzureCloud`
- - or
- - `AzureUSGovernment`
-- **SAP, AVS, AVD, HPC**:
- - Optional
- - Description: Used for specialized workload analysis.
- - Type: Switch
- - Example:
- - `-sap` or `-avs` or `-avd` or `-hpc`
-- **Debugging**:
- - Optional
- - Description: Writes Debugging information of the script during the execution.
- - Type: Switch
- - Format/Values:
- - `-debugging`
-- **RunbookFile**:
- - Optional
- - Description: Specifies the file with the runbook (selectors & checks) to be used. Only used for a particular specialized workload. The parameters section defines the parameters used by the runbook. These parameters will be automatically merged into selectors and queries at runtime.
- - The selectors section identifies groups of Azure resources that specific checks will be run against. Selectors can be any valid KQL predicate (e.g., `resourceGroup =~ 'rg1'`).
- - The checks section maps resource graph queries (identified by GUIDs) to specific selectors.
- - The query_overrides section enables catalogs of specialized resource graph queries to be included in the review.
- - Type: String (file name and extension)
- - Format/Values:
- - `-RunbookFile runbook.json`
- - **Note**: It can't be used in combination with `-ConfigFile`, `-ResourceGroups`, or `-Tags` parameters. Specify subscriptions in scope using `-SubscriptionIds` parameter.
-- **UseImplicitRunbookSelectors**:
- - Optional
- - Description: Enables the use of implicit runbook selectors. When this switch is enabled, each resource graph query will be wrapped in an inner join that filters the results to only include resources that match the selector. This is useful when queries do not include selectors.
- - Type: Switch
- - `-UseImplicitRunbookSelectors`
diff --git a/docs/content/tools-old/collector/quickstartexample.gif b/docs/content/tools-old/collector/quickstartexample.gif
deleted file mode 100644
index 71999faa5..000000000
Binary files a/docs/content/tools-old/collector/quickstartexample.gif and /dev/null differ
diff --git a/docs/content/tools-old/collector/quickstartexample_cloudshell.gif b/docs/content/tools-old/collector/quickstartexample_cloudshell.gif
deleted file mode 100644
index f8571180d..000000000
Binary files a/docs/content/tools-old/collector/quickstartexample_cloudshell.gif and /dev/null differ
diff --git a/docs/content/tools-old/reports/_index.md b/docs/content/tools-old/reports/_index.md
deleted file mode 100644
index 0df44bf82..000000000
--- a/docs/content/tools-old/reports/_index.md
+++ /dev/null
@@ -1,186 +0,0 @@
----
-title: Reports Generator Script
-weight: 30
-geekdocCollapseSection: false
----
-
-{{< toc >}}
-
-## Overview
-
-The Reports Generator script serves as the final step in a Well-Architected Reliability Assessment (WARA) engagement. It takes the Excel spreadsheet generated by the Data Analyzer script and converts it into Microsoft Word and PowerPoint formats. The Reports Generator automates the process of creating comprehensive reports from the analyzed data, making it easier to share insights and recommendations.
-
-## Requirements
-
-- [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.4)
-- Microsoft Excel, Word and PowerPoint installed
-- Role Based Access Control: Reader role to access to resources to be evaluated. Although access to the Azure Subscriptions is not required to run the script, the access will be required for the user to complete some manual validations of configurations of Azure resources after the script generates the Excel file.
-
-## Quick Start (Local Machine only - Cloud Shell is not supported)
-
-- Download and run the reports generator script by copying and modifying this script block
-- Once the script is downloaded you can execute it by running ./3_wara_reports_generator.ps1
-
-```powershell
-#Create new "WARA" directory under C:\ and navigate to C:\WARA. If not Windows then do nothing and move on.
-$iswindows ? $(mkdir C:\WARA -ErrorAction SilentlyContinue;cd C:\WARA) : (Write-Host "C:\WARA - Not Required")
-
-#Download the latest version of the script
-invoke-webrequest https://aka.ms/aprl/tools/3 -out 3_wara_reports_generator.ps1
-
-#Remove file blocking if active and running windows
-$iswindows ? (unblock-file ./3_wara_reports_generator.ps1) : (Write-host "Unblock not required - Not Windows OS")
-
-#Modify these parameters and run the script
-.\3_wara_reports_generator.ps1 -CustomerName 'Contoso' -WorkloadName 'E-Commerce' -ExcelFile '.\WARA Action Plan 2024-08-08-11-57.xlsx'
-```
-
-## How to download
-
-- [GitHub Link to Download](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/3_wara_reports_generator.ps1)
-- Download the script using command-line
-
- ```shell
- iwr https://aka.ms/aprl/tools/3 -out 3_wara_reports_generator.ps1
- ```
-
-- Download the PowerPoint template using command-line
-
- ```shell
- iwr https://aka.ms/aprl/tools/pptx -out 'Mandatory - Executive Summary presentation - Template.pptx'
- ```
-
-- Download the Word template using command-line
-
- ```shell
- iwr https://aka.ms/aprl/tools/docx -out 'Optional - Assessment Report - Template.docx'
- ```
-
-- [GitHub Link to Sample Output - Executive Summary Presentation](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/sample-output/Executive%20Summary%20Presentation%20-%20Contoso%20Hotels%20-%202024-05-07-12-12.pptx)
-- [GitHub Link to Sample Output - Assessment Report](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/sample-output/Assessment%20Report%20-%20Contoso%20Hotels%20-%202024-05-07-12-12.docx)
-
-## How to run the script
-
-{{< hint type=important >}}
- The Reports Generator script must be run from a Windows Machine with Excel, Word, and PowerPoint installed.
-{{< /hint >}}
-
-### Local Machine - Reports Generator
-
-1. You will need to have both the Word and PowerPoint templates downloaded to the same file location.
- {{< figure src="../../img/tools/generator-1.png" width="80%" >}}
-
-1. Change your directory to the same location that you have downloaded the WARA Reports Generator script to.
-
- - We recommend running this as close to your C:\ as path to avoid errors related to file path length.
- {{< figure src="../../img/tools/collector-7.png" width="40%" >}}
-
-1. Execute script leveraging needed parameters
- - The script accepts both short and/or full paths.
-
- ```powershell
- .\3_wara_reports_generator.ps1 -CustomerName 'Contoso' -WorkloadName 'E-Commerce' -ExcelFile '.\WARA Action Plan 2024-08-08-11-57.xlsx'
- ```
-
- {{< figure src="../../img/tools/generator-2.png" width="100%" >}}
-
-1. Select "R" to allow script to run
- {{< figure src="../../img/tools/generator-3.png" width="100%" >}}
-
-1. After the script successfully runs, you will find two new files saved in your folder. Some of the information will be automatically populated based on the Action Plan.
-
- {{< hint type=important >}}
- Updates will need to be made prior to presenting to any audience.
- {{< /hint >}}
-
-## PARAMETERS
-
-### Help
-
-Switch to display help information.
-
-- **Required**: No
-- **Position**: Named
-
-### Debugging
-
-Switch to enable debugging mode.
-
-- **Required**: No
-- **Position**: Named
-
-### CustomerName
-
-Name of the customer for whom the report is being generated.
-
-- **Required**: No
-- **Position**: Named
-
-### WorkloadName
-
-Name of the workload being assessed.
-
-- **Required**: No
-- **Position**: Named
-
-### ExcelFile
-
-Path to the Excel file created by the `2_wara_data_analyzer` script.
-
-- **Required**: Yes
-- **Position**: 0
-
-### Heavy
-
-Switch to enable heavy processing mode. When enabled, this mode introduces additional delays using Start-Sleep at various points in the script to handle heavy environments more gracefully. This can help in scenarios where the system resources are limited or the operations being performed are resource-intensive, ensuring the script doesn't overwhelm the system.
-
-- **Required**: No
-- **Position**: Named
-- **Notes**: Use this parameter when your excel action plan has over 10,000 resources or is greater than 10MB. This will ensure your workstation is minimally impacted by the processing.
-
-### PPTTemplateFile
-
-Path to the PowerPoint template file.
-
-- **Required**: No
-- **Position**: Named
-
-### WordTemplateFile
-
-Path to the Word template file.
-
-- **Required**: No
-- **Position**: Named
-
-## EXAMPLES
-
-### Example 1
-
-```powershell
-.\3_wara_reports_generator.ps1 -ExcelFile '.\WARA Action Plan 2024-03-07-16-06.xlsx' -CustomerName 'ABC Customer' -WorkloadName 'SAP On Azure' -Heavy -PPTTemplateFile '.\Template.pptx' -WordTemplateFile '.\Template.docx'
-```
-
-## Frequently asked questions
-
-### The specified Excel file may be encrypted. If a sensitivity label is applied to the file, please change the sensitivity label to the label without encryption temporarily
-
-The specified Excel file may be has a sensitivity label (encrypted). The 3_wara_reports_generator.ps1 script does not support encrypted Excel file currently. To avoid this issue, you need to change the sensitivity label to the label without encryption temporarily. For example, **Confidential/Any User (No Protection)** sensitivity. After completing the script running, you can re-apply the original sensitivity label (recommended).
-
-You can change the sensitivity label on the file by **Excel** or **Information Protection File Labeler**.
-
-- Option 1: Excel
-
- 1. Select a sensitivity label that you want from the sensitivity bar at the top of the Excel window.
- 2. Save the Excel file.
-
- Learn more about the [Sensitivity bar in Microsoft 365](https://support.microsoft.com/office/2f96e7cd-d5a4-403b-8bd7-4cc636bae0f9).
-
-- Option 2: Information Protection File Labeler
-
- 1. Install the [Microsoft Purview Information Protection client](https://www.microsoft.com/en-us/download/details.aspx?id=53018)
- 2. Right click the Excel file in the File Explorer then select **Show more options**.
- 3. Select **Apply sensitivity label with Microsoft Purview**
- 4. Select a sensitivity label that you want.
- 5. Click the **Apply** button.
-
- Learn more about the [detailed usage of the Information Protection File Labeler](https://support.microsoft.com/topic/67829155-2d0e-4122-9677-7c53c8cba18a).
diff --git a/docs/content/tools-old/script-overviews/_index.md.old b/docs/content/tools-old/script-overviews/_index.md.old
deleted file mode 100644
index 3fb847442..000000000
--- a/docs/content/tools-old/script-overviews/_index.md.old
+++ /dev/null
@@ -1,426 +0,0 @@
----
-title: Overview and Usage of APRL Scripts
-weight: 10
-geekdocCollapseSection: false
----
-
-This section provides an overview of the Azure Proactive Resiliency Library v2 (APRL) scripts and how to use them. The following scenarios are covered:
-
-{{< toc >}}
-
-# Well-Architected Reliability Assessment (WARA) tools
-
-## 1. Collector Script
-
-This script is part of the Microsoft Well-Architected Reliability Assessment (WARA) engagement, and helps customers to validate if Azure resources are architected and configured following Microsoft best practices. It accomplishes that by running Azure resource graph queries (Kusto/KQL) against Azure Subscriptions and Resources, and it also collects information about closed Support Tickets opened, active Azure Advisor Reliability recommendations, past Azure Service Health Retirements and Outages notifications, and configuration of Azure Service Health Alerts, which are relevant for the Reliability recommendations provided at the end of the engagement. The collected data is then structured and exported in a JSON file that is later used as an input for the second script, the Data-analyzer script (2_wara_data_analyzer.ps1).
-
-**Important:** This Azure Resource Graph Queries can only read ARM data (Azure Resource Manager), it DOES NOT have access or collects any keys, secrets, password, or any confidential information, only information about how resources are deployed and configured. If you would like to learn more about it, please go to Azure Resource Graph Explorer and run some of the query examples provided by the Portal.
-
-### Requirements
-
-- [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.4)
-- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
-- [Azure PowerShell modules](https://learn.microsoft.com/en-us/powershell/azure/install-azps-windows?view=azps-12.1.0&tabs=powershell&pivots=windows-psgallery)
- - Az.ResourceGraph
- - Az.Accounts
-- Role Based Access Control: Reader role to access to resources to be evaluated
-
-### How to download
-
-- [GitHub Link to Download](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/1_wara_collector.ps1)
-- Download the script using command-line
- ```shell
- iwr https://aka.ms/aprl/tools/1 -out 1_wara_collector.ps1
- ```
-- [GitHub Link to Sample Output](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/sample-output/WARA_File_2024-05-07_11_59.json)
-
-### Parameters
-
-When calling the Collector script, you must provide some required parameters. Optional parameters can also be included. See the list below:
-
-- **TenantID**
- - Required
- - Description: Target Tenant where the workload resides
- - Type: String (GUID)
- - Example:
- - "00000000-0000-0000-0000-000000000000"
-- **SubscriptionIds**
- - Required if ResourceGroups is not provided
- - Description: Specifies Subscription(s) to be included in the analysis.
- - Type: String array
- - Example:
- - "/subscriptions/00000000-0000-0000-0000-000000000000","/subscriptions/AAAAAAAA-AAAA-AAAA-AAAA-AAAAAAAAAAAA"
-- **ResourceGroups**
- - Required if SubscriptionIds is not provided
- - Description: Specifies Resource Group(s) to be included in the analysis
- - Type: String array
- - Example:
- - "/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ResourceGroup1","/subscriptions/YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY/resourceGroups/ResourceGroup2"
-- **Tags**:
- - Optional
- - Type: String array
- - Description: Specifies Tags to be used for filtering the resources.
- - Operators:
- - **=~** for "Equal" (non-case sensitive) to define your name/value pair values.
- - **!~** for "Non Equal" (non-case sensitive) to define your name/value pair values.
- - **||** for "Or" operations, when one or more TagName(s) could be equal to one or more TagValue(s).
- - **,** to separate name/value pairs.
- - Examples:
- - "TagName=~TagValue"
- - "TagName=~TagValue","TagName1=~TagValue1"
- - "TagName1||TagName2=~TagValue1"
- - "TagName1=~TagValue1||TagValue2"
- - "TagName1||TagName2=~TagValue1||TagValue2"
- - "Env||Environment=~Production||Prod","App=~Ecommerce" (Result: Subscriptions or ResourceGroups or Resources must have the Tag **Env** OR **Environment** EQUAL to **Production** OR **Prod**, AND must have the Tag **App** EQUAL to **Ecommerce** or **Ecom** (All non-case sensitive). If the Tag requirement is met at Subscription level, all Resources within the Subscription are included, if met at ResourceGroup level, all ResourceGroups with the Tags and all their resources are included; if only met at the Resource level, then only resources that met the tag requirement are included).
-- **ConfigFile**:
- - Required when the following parameters are nor provided via command line: TenantId, SubscriptionIDs, ResourceGroups
- - Description: Alternate option to providing command line parameters. Specifies a file for filtering of Subscription, ResourceGroup, ResourceId, and Tags.
- - Type: String (file name and extension)
- - Example:
- - configFileName.txt
- - See ConfigFile.Example [here](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/configfile.example)
-- **AzureEnvironment**:
- - Optional
- - Description: Specifies the Azure Environment to used for the analysis: AzureCloud, AzureUSGovernment.
- - Type: String
- - Examples:
- - AzureCloud
- - or
- - AzureUSGovernment
-- **SAP, AVS, AVD, HPC**:
- - Optional
- - Description: Used for specialized workload analysis.
- - Type: Switch
- - Example:
- - No values are required, simply pass the parameter (-sap or -avs or -avd or -hpc)
-- **Debugging**:
- - Optional
- - Description: Writes Debugging information of the script during the execution.
- - Type: Switch
- - Format/Values:
- - No values are required, simply pass the parameter (-debugging)
-- **RunbookFile**:
- - Optional
- - Description: Specifies the file with the runbook (selectors & checks) to be used. Only used for a particular specialized workload.
- - Type: String (file name and extension)
- - Format/Values:
- - runbook.json
-
-### How to run the script
-
-See at the end of this page various examples of how to run this script - [Examples](#how-to-run-the-1_wara_collectorps1)
-
-**You have two options to run the collector script:**
-
-1. Cloud Shell - Requires Cloud Shell be configured with write access to a file share within the same tenant
-
-2. Local Machine - Requires current modules leveraged in the script be installed
-
-#### 1.1 - Cloud Shell
-
-1. From the [Azure Portal](https://portal.azure.com/) open Cloud Shell, select PowerShell instead of BASH
-
- - If this is your first time using Cloud Shell, refer to the getting started guide from Microsoft Learn - [Azure Cloud Shell](https://learn.microsoft.com/en-us/azure/cloud-shell/get-started/classic?tabs=azurecli#start-cloud-shell).
-
- {{< figure src="../../img/tools/collector-1.png" width="100%" >}}
-
-2. Upload the WARA Collector Script to Cloud Shell
- {{< figure src="../../img/tools/collector-2.png" width="60%" >}}
-
- Or download the script from GtiHub
-
- ```shell
- iwr https://aka.ms/aprl/tools/1 -out 1_wara_collector.ps1
- ```
-
-3. Execute script leveraging parameters
-
- {{< figure src="../../img/tools/collector-3.png" width="100%" >}}
-
- For complex Subscription, ResourceGroups and Tags filtering scenarios we highly recommend using [ConfigFiles - See here an example](#example-6---configfile-example)
-
-4. Select "A" to allow modules to install
- {{< figure src="../../img/tools/collector-4.png" width="100%" >}}
-
-1. After Script completes, download the results
- {{< figure src="../../img/tools/collector-5.png" width="100%" >}}
-
-#### 1.2 Local Machine
-
-1. To run the script there are 5 prerequisites that must be completed first:
- 1. **The script must be executed from PowerShell 7. Other versions are not supported, for example: Windows PowerShell and PowerShell ISE**
- {{< figure src="../../img/tools/collector-6.png" width="40%" >}}
- 2. **Git must be installed on the local machine - [Git](https://git-scm.com/download/win)**
- 3. **Install required PowerShell Modules:**
- - Install-Module -Name ImportExcel -Force -SkipPublisherCheck
- - Install-Module -Name Az.ResourceGraph -SkipPublisherCheck
- - Install-Module -Name Az.Accounts -SkipPublisherCheck
- 4. **Unblock the Script**
- - The script is digitally signed, but the PowerShell module ImportExcel is not. So at this moment, you need to allow the execution of scripts not signed locally:
- - Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser
- - Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope LocalMachine
- 5. **Reader permissions to target subscription(s)**
-
-2. Open a new PowerShell 7 session after completing prerequisites
-
-3. Change your directory to the same location where you are hosting your WARA Collector script.
-
- - We recommend running this as close to your C:\ as path to avoid errors related to file path length. Create a **"c:\scripts\wara\"** folder and save all scripts in this folder.
- {{< figure src="../../img/tools/collector-7.png" width="40%" >}}
-
-4. Execute script leveraging the necessary parameters
-
- - {{< figure src="../../img/tools/collector-8.png" width="100%" >}}
-
-5. Authenticate with the account that has Reader permissions to the target subscription(s)
- {{< figure src="../../img/tools/collector-9.png" width="40%" >}}
-
-6. After script completes, the results will be saved to the same folder location.
-
-
-
-## 2. Data Analyzer Script
-
-This Data Analyzer script is the second script used during Well-Architected Reliability (WARA) engagements. Based on the data generated by the Collector script, the Data Analyzer will collect necessary information about Recommendations from the Azure Proactive Resiliency Library (APRL) and will generate an ActionPlan Excel spreadsheet. The goal of this tool is to summarize the collected data and provide actionable insights into the health and resiliency of the Azure environment.
-
-### Requirements
-
-- [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.4)
-- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
-- Microsoft Excel installed
-- Role Based Access Control: Reader role to access to resources to be evaluated. Although access to the Azure Subscriptions is not required to run the script, the access will be required for the user to complete some manual validations of configurations of Azure resources after the script generates the Excel file.
-
-### How to download
-
-- [GitHub Link to Download](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/2_wara_data_analyzer.ps1)
-- Download the script using command-line
- ```shell
- iwr https://aka.ms/aprl/tools/2 -out 2_wara_data_analyzer.ps1
- ```
-- [GitHub Link to Sample Output](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/sample-output/WARA%20Action%20Plan%202024-05-07_12_07.xlsx)
-
-### How to run the script
-
-**Important: The Data Analyzer script must be run from a Windows Machine with Excel installed.**
-
-1. Change your directory to the same location that you have downloaded the WARA Data Analyzer script to.
-
- - We recommend running this as close to your C:\ as path to avoid errors related to file path length.
- {{< figure src="../../img/tools/collector-7.png" width="40%" >}}
-
-2. Execute script pointing the -JSONFile parameter to file created by the WARA Collector script.
- {{< figure src="../../img/tools/analyzer-1.png" width="100%" >}}
-
-3. Select "R" to allow script to run
- {{< figure src="../../img/tools/analyzer-2.png" width="100%" >}}
-
-4. After the script completes it will save a WARA Action Plan.xlsx file to the same file path.
-
-#### Action Plan Analysis
-
-1. Once the script has completed, open the Excel Action Plan and familiarize yourself with the structure of the file, generated data, resources collected, pivot tables, and charts created.
-
- - These are the worksheets:
- - **Recommendations**: you will find all Recommendations, their category, impact, description, learn more links, and much more.
- - Note that Columns A and B are counting the number of Azure Resources associated with the RecommendationID.
- - **ImpactedResources**: you will find a list of Azure Resources associated with a RecommendationID. These are the Azure Resources NOT following Microsoft best practices for Reliability.
- - **Other-OutOfScope**: you will find a list of the Resources that are Out of Scope of the WARA engagement based on the ResourceTypes, after all filters have been applied.
- - **ResourceTypes**: you will find a list of all ResourceTypes the customer is using, number of Resources deployed for each one, and if there are Recommendations for the ResourceType in APRL.
- - **Outages**: you will find a list of all the outages that impacted the subscriptions (this worksheet might not exist if there are no Outages to be found).
- - **Retirements**: you will find a list of all the next retirements in the subscriptions (this worksheet might not exist if there are no Retirements to be found).
- - **Support Tickets**: you will find a list of all the Support Tickets for the subscriptions in the past 6 months (this worksheet might not exist if there are no Support Tickets to be found).
- - **PivotTable**: you will find a couple of pivot tables used to automatically create the charts
- - **Charts**: you will find 3 charts that will be used in the Executive Summary PPTx
- - At this point, all Azure Resources with recommendations and Azure Resource Graph queries available in APRL, were automatically validated. Follow the next steps to validate the remaining services without automation or that does not exist in APRL yet.
-
-2. Go to the "ImpactedResources" worksheet, filter Column "B" by "IMPORTANT", and validate manually the remaining resource configurations for reliability patterns.
-
- - "IMPORTANT - Query under development"
- - "IMPORTANT - Recommendation cannot be validated with ARGs - Validate Resources manually"
- - "IMPORTANT - ServiceType Not Available in APRL - Validate Resources manually if Applicable, if not delete this line"
-
-3. Remove/add any recommendations based on your analysis prior to generating reports
-
-4. For relevant Outages, all Service Retirements, and relevant Support Tickets, create actionable Recommendations in the "Recommendations" worksheet.
-
-
-
-## 3. Generator Script
-
-The Reports Generator script serves as the final step during an Well-Architected Reliability Assessment engagement. It takes the Excel spreadsheet generated by the Data Analyzer script and converts it into Microsoft Word and PowerPoint formats. The Reports Generator automates the process of creating comprehensive reports from the analyzed data, making it easier to share insights and recommendations.
-
-### Requirements
-
-- [PowerShell 7](https://learn.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-7.4)
-- [Git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git)
-- Microsoft Excel, Word and PowerPoint installed
-- Role Based Access Control: Reader role to access to resources to be evaluated. Although access to the Azure Subscriptions is not required to run the script, the access will be required for the user to complete some manual validations of configurations of Azure resources after the script generates the Excel file.
-
-### How to download
-
-- [GitHub Link to Download](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/3_wara_reports_generator.ps1)
-- Download the script using command-line
- ```shell
- iwr https://aka.ms/aprl/tools/3 -out 3_wara_reports_generator.ps1
- ```
-- Download the PowerPoint template using command-line
- ```shell
- iwr https://aka.ms/aprl/tools/pptx -out 'Mandatory - Executive Summary presentation - Template.pptx'
- ```
-- Download the Word template using command-line
- ```shell
- iwr https://aka.ms/aprl/tools/docx -out 'Optional - Assessment Report - Template.docx'
- ```
-- [GitHub Link to Sample Output - Executive Summary Presentation](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/sample-output/Executive%20Summary%20Presentation%20-%20Contoso%20Hotels%20-%202024-05-07-12-12.pptx)
-- [GitHub Link to Sample Output - Assessment Report](https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/blob/main/tools/sample-output/Assessment%20Report%20-%20Contoso%20Hotels%20-%202024-05-07-12-12.docx)
-
-### How to run the script
-
-**Important: The Data Analyzer script must be run from a Windows Machine with Excel installed.**
-
-#### Local Machine - Report Generation
-
-1. You will need to have both the Word and PowerPoint templates downloaded to the same file location.
- {{< figure src="../../img/tools/generator-1.png" width="80%" >}}
-
-2. Change your directory to the same location that you have downloaded the WARA Reports Generator script to.
-
- - We recommend running this as close to your C:\ as path to avoid errors related to file path length.
- {{< figure src="../../img/tools/collector-7.png" width="40%" >}}
-
-3. Execute script leveraging needed parameters
-
- - Parameters include:
- - **ExcelFile**: *Mandatory*; WARA Excel file generated by '2_wara_data_analyzer.ps1' script and customized.
- - **CustomerName**: *Optional*; specifies the Name of the Customer to be added to the PPTx and DOCx files.
- - **Heavy**: *Optional*; runs the script at a lower pace to handle heavy environments.
- - **WorkloadName**: *Optional*; specifies the Name of the Workload of the analyses to be added to the PPTx and DOCx files.
- - **PPTTemplateFile**: *Optional*; specifies the PPTx template file to be used as source. If not specified the script will look for the file in the same path as the script.
- - **WordTemplateFile**: *Optional*; specifies the DOCx template file to be used as source. If not specified the script will look for the file in the same path as the script.
- - **Debugging**: *Optional*; Writes a Debugging information to a log file.
- {{< figure src="../../img/tools/generator-2.png" width="100%" >}}
-
-4. Select "R" to allow script to run
- {{< figure src="../../img/tools/generator-3.png" width="100%" >}}
-
-5. After the script successfully runs, you will find two new files saved in your folder. Some of the information will be automatically populated based on the Action Plan.
-
- {{< hint type=important >}}
- Updates will need to be made prior to presenting to any audience.
- {{< /hint >}}
-
-### Frequently asked questions
-
-## How to run the 1_wara_collector.ps1
-
-### Example 1
-
-Run against one subscriptions in tenant `00000000-0000-0000-0000-000000000000`:
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000"
-```
-
-### Example 2
-
-Run against one subscription and one resource group in tenant `00000000-0000-0000-0000-000000000000`:
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" -ResourceGroups "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/Demo1-RG"
-```
-
-### Example 3
-
-Run against two subscriptions and one resource group in tenant using tags to filter resources within the scope of the subscription and resource group in the tenant`00000000-0000-0000-0000-000000000000`:
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000","/subscriptions/33333333-3333-3333-3333-333333333333" -ResourceGroups "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/Demo1-RG" -Tags 'Criticality=~High','Env=~Prod'
-```
-
-### Example 4
-
-Run against one subscription and two resource groups in tenant `00000000-0000-0000-0000-000000000000` using tags to filter resources within the scope of the subscription and resource group in the tenant`00000000-0000-0000-0000-000000000000`:
-
-```powershell
-.\1_wara_collector.ps1 -TenantID "00000000-0000-0000-0000-000000000000" -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" -ResourceGroups "/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/Demo1-RG","/subscriptions/44444444-4444-4444-4444-444444444444/resourceGroups/Demo2-RG" -Tags 'Criticality=~High','Env=~Prod'
-```
-
-**Note**: Multiple values do not have to be in the same subscription. You can specify multiple resource groups in unique subscriptions.
-
-### Example 5
-
-Run a configuration file:
-
-```powershell
-.\1_wara_collector.ps1 -ConfigFile ".\config.txt"
-```
-
-### Example 6 - ConfigFile Example
-
-```text
-[tenantid]
-00000000-0000-0000-0000-000000000000
-
-[subscriptions]
-/subscriptions/11111111-1111-1111-1111-111111111111
-
-[resourcegroups]
-/subscriptions/55555555-5555-5555-5555-555555555555/resourceGroups/Demo1-RG
-/subscriptions/22222222-2222-2222-2222-222222222222/resourceGroups/Demo1-RG
-
-[tags]
-env==prod
-application=~demoapp1
-```
-
-**Note**: In a configuration file we separate multiple entries for a filter by new lines. Where as, from the command line we would pass multiple subscriptions or resource groups using the "string1","string2" pattern. The configuration file is useful for repeated runs, or numerous filters where it may be difficult to troubleshoot syntax in the command line.
-
-### Example 7 - Runbook Example
-
-> Learn more about runbooks [here](runbooks.md).
-
-Run a runbook.
-
-```powershell
-.\1_wara_collector.ps1 `
- -TenantID "00000000-0000-0000-0000-000000000000" `
- -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" `
- -RunbookFile ".\runbook.json"
-```
-
-Run a runbook using implicit runbook selectors.
-
-```powershell
-.\1_wara_collector.ps1 `
- -TenantID "00000000-0000-0000-0000-000000000000" `
- -SubscriptionIds "/subscriptions/00000000-0000-0000-0000-000000000000" `
- -RunbookFile ".\runbook.json"
- -UseImplicitRunbookSelectors
-```
-
-> Note that `-SubscriptionIds` are required when using a runbook.
-
-## 3_wara_reports_generator.ps1
-
-### The specified Excel file may be encrypted. If a sensitivity label is applied to the file, please change the sensitivity label to the label without encryption temporarily
-
-The specified Excel file may be has a sensitivity label (encrypted). The 3_wara_reports_generator.ps1 script does not support encrypted Excel file currently. To avoid this issue, you need to change the sensitivity label to the label without encryption temporarily. For example, **Confidential/Any User (No Protection)** sensitivity. After completing the script running, you can re-apply the original sensitivity label (recommended).
-
-You can change the sensitivity label on the file by **Excel** or **Information Protection File Labeler**.
-
-- Option 1: Excel
-
- 1. Select a sensitivity label that you want from the sensitivity bar at the top of the Excel window.
- 2. Save the Excel file.
-
- Learn more about the [Sensitivity bar in Microsoft 365](https://support.microsoft.com/office/2f96e7cd-d5a4-403b-8bd7-4cc636bae0f9).
-
-- Option 2: Information Protection File Labeler
-
- 1. Install the [Microsoft Purview Information Protection client](https://www.microsoft.com/en-us/download/details.aspx?id=53018)
- 2. Right click the Excel file in the File Explorer then select **Show more options**.
- 3. Select **Apply sensitivity label with Microsoft Purview**
- 4. Select a sensitivity label that you want.
- 5. Click the **Apply** button.
-
- Learn more about the [detailed usage of the Information Protection File Labeler](https://support.microsoft.com/topic/67829155-2d0e-4122-9677-7c53c8cba18a).
diff --git a/docs/content/tools/collector/_index.md b/docs/content/tools/collector/_index.md
index e62d49444..d9b4fce0b 100644
--- a/docs/content/tools/collector/_index.md
+++ b/docs/content/tools/collector/_index.md
@@ -159,6 +159,28 @@ In PowerShell command line the configuration looks like:
-tags "App||Application!~App3","env||environment!~dev||qa""
```
+## Configuration File
+
+The configuration file is a text file that contains the parameters for the collector. The configuration file can be used to specify the subscriptions, resource groups, and tags to be included in the collector run.
+
+### Example Configuration File
+
+```text
+[tenantId]
+tenantid
+
+[subscriptionIds]
+/subscriptions/
+
+[resourcegroups]
+/subscriptions//resourceGroups/Demo1-RG
+/subscriptions//resourceGroups/Demo2-RG
+
+[tags]
+env=~prod
+application=~demoapp1
+```
+
### Examples
#### Run the collector against a specific subscription
@@ -214,3 +236,11 @@ Start-WARACollector -ConfigFile "C:\path\to\config.txt"
```PowerShell
Start-WARACollector -ConfigFile "C:\path\to\config.txt" -SAP -AVD -HPC -AVS -AI_GPT_RAG
```
+
+## Runbooks
+
+{{< hint type=important >}}
+Runbooks are an advanced feature designed for specific workload-aligned use cases. If you're not sure if you need runbooks, you probably don't. Before diving into runbooks, [try using the filtering feature to see if it meets your needs](#resource-filtering).
+{{< /hint >}}
+
+Learn more about using runbooks with the WARA collector script in the [runbooks docs](runbooks.md).
diff --git a/docs/content/tools-old/collector/runbooks.md b/docs/content/tools/collector/runbooks.md
similarity index 100%
rename from docs/content/tools-old/collector/runbooks.md
rename to docs/content/tools/collector/runbooks.md
diff --git a/tools/1_wara_collector.ps1 b/tools/1_wara_collector.ps1
deleted file mode 100644
index 4facac9c5..000000000
--- a/tools/1_wara_collector.ps1
+++ /dev/null
@@ -1,1800 +0,0 @@
-#Requires -Version 7
-
-<#
-.SYNOPSIS
-Well-Architected Reliability Assessment (WARA) v2 collector script
-
-.DESCRIPTION
-This script is used to collect data from Azure subscriptions to be used in the Well-Architected Reliability Assessment (WARA) v2. The script collects data from the subscriptions, resource groups, and resources, and then runs resource graph queries (Kusto/KQL) to extract information about the resources. The script also collects information about outages, support tickets, advisor recommendations, service retirements, and service health alerts. The collected data is then used to generate a JSON file with recommendations for improving the reliability of the resources/ Typically, this JSON file is used as an input for the WARA v2 data analyzer script (2_wara_data_analyzer.ps1).
-
-By default, the script executes all relevant checks in the Azure Proactive Resiliency Library v2 but it can also be configured to run checks against specific groups of resources using a runbook (-RunbookFile).
-
-.LINK
-https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2
-
-.PARAMETER Debugging
-[Switch]: Enables debugging output.
-
-.PARAMETER TenantID
-Specifies the Entra tenant ID to be used to authenticate to Azure.
-
-.PARAMETER SubscriptionIds
-Specifies the subscription IDs to be included in the review. Multiple subscription IDs should be separated by commas. Subscription IDs must be in either GUID form (e.g., 00000000-0000-0000-0000-000000000000) or full subscription ID form (e.g., /subscriptions/00000000-0000-0000-0000-000000000000).
-
-NOTE: Can't be used in combination with -ConfigFile parameter.
-
-.PARAMETER ResourceGroups
-Specifies the resource groups to be included in the review. Multiple resource groups should be separated by commas. Resource groups must be in full resource group ID form (e.g., /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg1).
-
-NOTE: Can't be used in combination with -ConfigFile or -RunbookFile parameters.
-
-.PARAMETER Tags
-Specifies the tags to be used to filter resources.
-
-NOTE: Can't be used in combination with -ConfigFile or -RunbookFile parameters.
-
-.PARAMETER ConfigFile
-Specifies the configuration file to be used.
-
-NOTE: Can't be used in combination with -RunbookFile, -SubscriptionIds, -ResourceGroups, or -Tags parameters.
-
-.PARAMETER AzureEnvironment
-Specifies the Azure environment to be used. Valid values are 'AzureCloud' and 'AzureUSGovernment'. Default value is 'AzureCloud'.
-
-.PARAMETER SAP
-[Switch]: Enables recommendations and queries for the SAP specialized workload.
-
-.PARAMETER AVD
-[Switch]: Enables recommendations and queries for the AVD specialized workload.
-
-.PARAMETER AVS
-[Switch]: Enables recommendations and queries for the AVS specialized workload.
-
-.PARAMETER HPC
-[Switch]: Enables recommendations and queries for the HPC specialized workload.
-
-.PARAMETER RunbookFile
-Specifies the runbook file to be used. More information about runbooks:
-
-- The parameters section defines the parameters used by the runbook. These parameters will be automatically merged into selectors and queries at runtime.
-- The selectors section identifies groups of Azure resources that specific checks will be run against. Selectors can be any valid KQL predicate (e.g., resourceGroup =~ 'rg1').
-- The checks section maps resource graph queries (identified by GUIDs) to specific selectors.
-- The query_overrides sections enables catalogs of specialized resoruce graph queries to by included in the review.
-
-NOTE: Can't be used in combination with -ConfigFile, -ResourceGroups, or -Tags parameters. Specify subscriptions in scope using -SubscriptionIds parameter.
-
-.PARAMETER UseImplicitRunbookSelectors
-[Switch]: Enables the use of implicit runbook selectors. When this switch is enabled, each resource graph query will be wrapped in an inner join that filters the results to only include resources that match the selector. This is useful when queries do not include selector injection comments (e.g., // selector, // selector:x).
-
-NOTE: This parameter is only used when a runbook file (-RunbookFile) is provided.
-
-.PARAMETER RepoUrl
-Specifies the git repository URL that contains APRL contents if you want to use custom APRL repository.
-
-.EXAMPLE
-Run against all subscriptions in tenant "00000000-0000-0000-0000-000000000000":
-.\1_wara_collector.ps1 -TenantID 00000000-0000-0000-0000-000000000000
-
-.EXAMPLE
-Run against specific subscriptions in tenant "00000000-0000-0000-0000-000000000000":
-.\1_wara_collector.ps1 -TenantID 00000000-0000-0000-0000-000000000000 -SubscriptionIds /subscriptions/00000000-0000-0000-0000-000000000000,/subscriptions/11111111-1111-1111-1111-111111111111
-
-.EXAMPLE
-Run against specific subscriptions, resource groups, and resources defined in a configuration file:
-.\1_wara_collector.ps1 -ConfigFile ".\config.json"
-
-.EXAMPLE
-Use a runbook:
-.\1_wara_collector.ps1 -TenantID 00000000-0000-0000-0000-000000000000 -SubscriptionIds /subscriptions/00000000-0000-0000-0000-000000000000 -RunbookFile "runbook.json"
-
-.OUTPUTS
-A JSON file with the collected data.
-#>
-
-
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'False positive as Write-Host does not represent a security risk and this script will always run on host consoles')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'False positive as parameters are not always required')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments', '', Justification = 'Variable is reserved for future use')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars', '', Justification = 'This will be fixed in refactor')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', '', Justification = 'This will be fixed in refactor')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'This will be fixed in refactor')]
-
-
-Param(
- [switch]$Debugging,
- [switch]$SAP,
- [switch]$AVD,
- [switch]$AVS,
- [switch]$HPC,
- [ValidatePattern('^(\/subscriptions\/)?[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')]
- [String[]]$SubscriptionIds,
- [ValidatePattern('^\/subscriptions\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\/resourceGroups\/[a-zA-Z0-9._-]+$')]
- [String[]]$ResourceGroups,
- [GUID]$TenantID,
- [ValidatePattern('^[^<>&%\\?/]+=~[^<>&%\\?/]+$|[^<>&%\\?/]+!~[^<>&%\\?/]+$')]
- [String[]]$Tags,
- [ValidateSet('AzureCloud', 'AzureUSGovernment')]
- $AzureEnvironment = 'AzureCloud',
- [ValidateScript({ Test-Path $_ -PathType Leaf })]
- $ConfigFile,
- [ValidatePattern('^https:\/\/.+$')]
- [string]$RepoUrl = 'https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2',
- # Runbook parameters...
- [switch]$UseImplicitRunbookSelectors,
- $RunbookFile
-)
-
-
-#import-module "./modules/collector.psm1" -Force
-
-$Script:ShellPlatform = $PSVersionTable.Platform
-
-if ($Tags) { $TagsPresent = $true }else { $TagsPresent = $false }
-
-$Script:Runtime = Measure-Command -Expression {
-
- Function Test-TagPattern {
- param (
- [string[]]$InputValue
- )
- $pattern = '^[^<>&%\\?/]+=~[^<>&%\\?/]+$|[^<>&%\\?/]+!~[^<>&%\\?/]+$'
-
- $allMatch = $true
-
- $InputValue | ForEach-Object {
- if ($_ -notmatch $Pattern) {
- $allMatch = $false
- }
- }
- return $allMatch
- }
-
- Function Test-ResourceGroupId {
- param (
- [string[]]$InputValue
- )
- $pattern = '\/subscriptions\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}\/resourceGroups\/[a-zA-Z0-9._-]+'
-
- $allMatch = $true
-
- $InputValue | ForEach-Object {
- if ($_ -notmatch $Pattern) {
- $allMatch = $false
- }
- }
- return $allMatch
- }
-
- Function Test-SubscriptionId {
- param (
- [string[]]$InputValue
- )
- $pattern = '\/subscriptions\/[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}'
-
- $allMatch = $true
-
- $InputValue | ForEach-Object {
- if ($_ -notmatch $Pattern) {
- $allMatch = $false
- }
- }
- return $allMatch
- }
-
- Function Get-AllAzGraphResource {
- param (
- [string[]]$subscriptionId,
- [string]$query = 'Resources | project id, resourceGroup, subscriptionId, name, type, location'
- )
-
- $result = $subscriptionId ? (Search-AzGraph -Query $query -First 1000 -Subscription $subscriptionId) : (Search-AzGraph -Query $query -First 1000 -UseTenantScope) # -first 1000 returns the first 1000 results and subsequently reduces the amount of queries required to get data.
-
- # Collection to store all resources
- $allResources = @($result)
-
- # Loop to paginate through the results using the skip token
- while ($result.SkipToken) {
- # Retrieve the next set of results using the skip token
- $result = $subscriptionId ? (Search-AzGraph -Query $query -SkipToken $result.SkipToken -Subscription $subscriptionId -First 1000) : (Search-AzGraph -Query $query -SkipToken $result.SkipToken -First 1000 -UseTenantScope)
- # Add the results to the collection
- $allResources += $result
- }
-
- # Output all resources
- return $allResources
- }
-
- function Get-AllResourceGroup {
- param (
- [string[]]$SubscriptionIds
- )
-
- # Query to get all resource groups in the tenant
- $q = "resourcecontainers
- | where type == 'microsoft.resources/subscriptions'
- | project subscriptionId, subscriptionName = name
- | join (resourcecontainers
- | where type == 'microsoft.resources/subscriptions/resourcegroups')
- on subscriptionId
- | project subscriptionName, subscriptionId, resourceGroup, id=tolower(id)"
-
- $r = $SubscriptionIds ? (Get-AllAzGraphResource -query $q -subscriptionId $SubscriptionIds -usetenantscope) : (Get-AllAzGraphResource -query $q -usetenantscope)
-
- # Returns the resource groups
- return $r
- }
-
- function Import-ConfigFileData($file) {
- # Read the file content and store it in a variable
- $filecontent, $linetable, $objarray, $count, $start, $stop, $configsection = $null
- $filecontent = (Get-Content $file).trim().tolower()
-
- # Create an array to store the line number of each section
- $linetable = @()
- $objarray = [ordered]@{}
-
- $filecontent = $filecontent | Where-Object { $_ -ne '' -and $_ -notlike '*#*' }
-
- #Remove empty space.
- foreach ($line in $filecontent) {
- $index = $filecontent.IndexOf($line)
- if ($line -match '^\[([^\]]+)\]$' -and ($filecontent[$index + 1] -match '^\[([^\]]+)\]$' -or [string]::IsNullOrEmpty($filecontent[$index + 1]))) {
- # Set this line to empty because the next line is a section as well.
- $filecontent[$index] = ''
- }
- }
-
- #Remove empty space again.
- $filecontent = $filecontent | Where-Object { $_ -ne '' -and $_ -notlike '*#*' }
-
- # Iterate through the file content and store the line number of each section
- foreach ($line in $filecontent) {
- if (-not [string]::IsNullOrWhiteSpace($line) -and -not $line.startswith('#')) {
- #Get the Index of the current line
- $index = $filecontent.IndexOf($line)
- # If the line is a section, store the line number
- if ($line -match '^\[([^\]]+)\]$') {
- # Store the section name and line number. Remove the brackets from the section name
- $linetable += $filecontent.indexof($line)
- }
- }
- }
-
- # Iterate through the line numbers and extract the section content
- $count = 0
- foreach ($entry in $linetable) {
-
- # Get the section name
- $name = $filecontent[$entry]
- # Remove the brackets from the section name
- $name = $name.replace('[', '').replace(']', '')
-
- # Get the start and stop line numbers for the section content
- # If the section is the last one, set the stop line number to the end of the file
- $start = $entry + 1
-
- if ($linetable.count -eq $count + 1) {
- $stop = $filecontent.count - 1
- } else {
- $stop = $linetable[$count + 1] - 1
- }
-
-
- # Extract the section content
- $configsection = $filecontent[$start..$stop]
-
- # Add the section content to the object array
- $objarray += @{$name = $configsection }
-
- # Increment the count
- $count++
- }
-
- # Return the object array and cast to PSCustomObject
- return [pscustomobject]$objarray
- }
-
- function Get-ResourceGroupsByList {
- param (
- [Parameter(Mandatory = $true)]
- [array]$ObjectList,
-
- [Parameter(Mandatory = $true)]
- [array]$FilterList,
-
- [Parameter(Mandatory = $true)]
- [string]$KeyColumn
- )
-
- $matchingObjects = @()
-
- foreach ($obj in $ObjectList) {
- if (($obj.$KeyColumn.split('/')[0..4] -join '/') -in $FilterList) {
- $matchingObjects += $obj
- }
- }
-
- return $matchingObjects
- }
-
- function Test-ScriptParameters {
- $IsValid = $true
-
- if ($RunbookFile) {
-
- if (!(Test-Path $RunbookFile -PathType Leaf)) {
- Write-Host "Runbook file (-RunbookFile) not found: [$RunbookFile]" -ForegroundColor Red
- $IsValid = $false
- }
-
- if ($ConfigFile) {
- Write-Host 'Runbook file (-RunbookFile) and configuration file (-ConfigFile) cannot be used together.' -ForegroundColor Red
- $IsValid = $false
- }
-
- if (!($SubscriptionIds)) {
- Write-Host 'Subscription ID(s) (-SubscriptionIds) is required when using a runbook file (-RunbookFile).' -ForegroundColor Red
- $IsValid = $false
- }
-
- if ($ResourceGroups -or $Tags) {
- Write-Host 'Resource group(s) (-ResourceGroups) and tags (-Tags) cannot be used with a runbook file (-RunbookFile).' -ForegroundColor Red
- $IsValid = $false
- }
-
- } else {
-
- if ($UseImplicitRunbookSelectors) {
- Write-Host 'Implicit runbook selectors (-UseImplicitRunbookSelectors) can only be used with a runbook file (-RunbookFile).' -ForegroundColor Red
- $IsValid = $false
- }
-
- if ($ConfigFile) {
-
- if (!(Test-Path $ConfigFile -PathType Leaf)) {
- Write-Host "Configuration file (-ConfigFile) not found: [$ConfigFile]" -ForegroundColor Red
- $IsValid = $false
- }
-
- if ($SubscriptionIds -or $ResourceGroups -or $Tags) {
- Write-Host 'Configuration file (-ConfigFile) and [Subscription ID(s) (-SubscriptionIds), resource group(s) (-ResourceGroups), or tags (-Tags)] cannot be used together.' -ForegroundColor Red
- $IsValid = $false
- }
-
- if ($TenantId) {
- Write-Host 'Tenant ID (-TenantId) cannot be used with a configuration file (-ConfigFile). Include tenant ID in the [tenantid] section of the config file.' -ForegroundColor Red
- $IsValid = $false
- }
-
- } else {
-
- if (!($TenantId)) {
- Write-Host 'Tenant ID (-TenantId) is required.' -ForegroundColor Red
- $IsValid = $false
- }
-
- if (!($SubscriptionIds) -and !($ResourceGroups)) {
- Write-Host 'Subscription ID(s) (-SubscriptionIds) or resource group(s) (-ResourceGroups) are required.' -ForegroundColor Red
- $IsValid = $false
- }
- }
- }
-
- return $IsValid
- }
-
- function Invoke-ResetVariable {
- $Script:SubIds = ''
- $Script:AllResourceTypes = @()
- $Script:SupportedResTypes = @()
- $Script:AllResourceTypesOrdered = @()
- $Script:AllAdvisories = @()
- $Script:Advisories = @()
- $Script:AllRetirements = @()
- $Script:AllServiceHealth = @()
- $Script:results = @()
- $Script:InScope = @()
- $Script:OutOfScope = @()
- $Script:PreInScopeResources = @()
- $Script:PreOutOfScopeResources = @()
- $Script:TaggedResources = @()
- $Script:AdvisorTypes = @()
-
-
- # Runbook stuff
- $Script:RunbookChecks = @{}
- $Script:RunbookParameters = @{}
- $Script:RunbookQueryOverrides = @()
- $Script:RunbookSelectors = @{}
- }
-
- function Test-Requirement {
- # Install required modules
- try {
- Write-Host 'Validating ' -NoNewline
- Write-Host 'Az.ResourceGraph' -ForegroundColor Cyan -NoNewline
- Write-Host ' Module..'
- $AzModules = Get-Module -Name Az.ResourceGraph -ListAvailable -ErrorAction silentlycontinue
- if ($null -eq $AzModules) {
- Write-Host 'Installing Az Modules' -ForegroundColor Yellow
- Install-Module -Name Az.ResourceGraph -SkipPublisherCheck -InformationAction SilentlyContinue
- }
-
- Write-Host 'Validating ' -NoNewline
- Write-Host 'Git' -ForegroundColor Cyan -NoNewline
- Write-Host ' Installation..'
- $GitVersion = git --version
- if ($null -eq $GitVersion) {
- Write-Host 'Missing Git' -ForegroundColor Red
- Exit
- }
- $Script:ScriptData = [pscustomobject]@{
- Version = $Script:Version
- SAP = if ($SAP.IsPresent) { $true }else { $false }
- AVD = if ($AVD.IsPresent) { $true }else { $false }
- AVS = if ($AVS.IsPresent) { $true }else { $false }
- HPC = if ($HPC.IsPresent) { $true }else { $false }
- Debugging = if ($Debugging.IsPresent) { $true }else { $false }
- ConfigFile = if ($ConfigFile) { $true }else { $false }
- ConfigFileTenant = if ($ConfigFile) { $TenantID }else { $false }
- ConfigFileScopes = if ($ConfigFile) { $Scopes }else { $false }
- ConfigFilelocations = if ($ConfigFile) { $locations }else { $false }
- ConfigFileTags = if ($ConfigFile) { $Tags }else { $false }
- SubscriptionIds = if ($SubscriptionIds) { $SubscriptionIds }else { $false }
- ResourceGroups = if ($ResourceGroups) { $ResourceGroups }else { $false }
- Tags = if ($TagsPresent) { $Tags }else { $false }
- RepoUrl = $RepoUrl
- }
- } catch {
- # Report Error
- $errorMessage = $_.Exception.Message
- Write-Host "Error executing function Requirements: $errorMessage" -ForegroundColor Red
- }
- }
-
- function Set-LocalFile {
- [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')]
- param()
-
- if ($PSCmdlet.ShouldProcess('')) {
- Write-Debug 'Setting local path'
- try {
- # Clone the GitHub repository to a temporary folder
-
- # Define script path as the default path to save files
- $workingFolderPath = $PSScriptRoot
- Set-Location -Path $workingFolderPath;
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $Script:clonePath = "$workingFolderPath\Azure-Proactive-Resiliency-Library-v2"
- } else {
- $Script:clonePath = "$workingFolderPath/Azure-Proactive-Resiliency-Library-v2"
- }
- Write-Debug 'Checking default folder'
- if ((Get-ChildItem -Path $Script:clonePath -Force -ErrorAction SilentlyContinue | Measure-Object).Count -gt 0) {
- Write-Debug 'APRL Folder does exist. Reseting it...'
- Get-Item -Path $Script:clonePath | Remove-Item -Recurse -Force
- git clone $Script:ScriptData.RepoUrl $clonePath --quiet
- } else {
- git clone $Script:ScriptData.RepoUrl $clonePath --quiet
- }
- Write-Debug 'Checking the version of the script'
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $RepoVersion = Get-Content -Path "$clonePath/tools/Version.json" -ErrorAction SilentlyContinue | ConvertFrom-Json
- } else {
- $RepoVersion = Get-Content -Path "$clonePath\tools\Version.json" -ErrorAction SilentlyContinue | ConvertFrom-Json
- }
- if ($Version -ne $RepoVersion.Collector) {
- Write-Host 'This version of the script is outdated. ' -BackgroundColor DarkRed
- Write-Host 'Please use a more recent version of the script.' -BackgroundColor DarkRed
- } else {
- Write-Host 'This version of the script is current version. ' -BackgroundColor DarkGreen
- }
-
- # Validates if queries are applicable based on Resource Types present in the current subscription
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $RootTypes = Get-Content -Path "$clonePath\tools\WARAinScopeResTypes.csv" | ConvertFrom-Csv
- } else {
- $RootTypes = Get-Content -Path "$clonePath/tools/WARAinScopeResTypes.csv" | ConvertFrom-Csv
- }
- $Script:SupportedResTypes = (($RootTypes | Where-Object { $_.WARAinScope -eq 'yes' }).ResourceType).tolower()
- $Script:AdvisorTypes = (($RootTypes | Where-Object { $_.inAprlAndOrAdvisor -eq 'yes' }).ResourceType).tolower()
- } catch {
- # Report Error
- $errorMessage = $_.Exception.Message
- Write-Host "Error executing function LocalFiles: $errorMessage" -ForegroundColor Red
- }
- }
- }
-
- function Connect-ToAzure {
- [CmdletBinding()]
- param
- (
- [Parameter(Mandatory = $true)]
- [ValidatePattern('^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$')]
- [GUID]$TenantID,
-
- [ValidateSet('AzureCloud', 'AzureChinaCloud', 'AzureGermanCloud', 'AzureUSGovernment')]
- [string]$AzureEnvironment = 'AzureCloud'
- )
-
- begin {
- Write-Verbose 'Starting connection process to Azure Tenant.'
- $AzContext = $null
- }
-
- process {
- try {
- # Attempt to get the current Azure context
- $AzContext = Get-AzContext -ErrorAction SilentlyContinue
-
- # Check if a valid context is available or if it matches the provided Tenant ID
- if ($null -eq $AzContext -or $AzContext.Tenant.Id -ne $TenantID) {
- Write-Verbose "Not logged into a tenant with any of the specified subscriptions. Authenticating to Azure. `n"
-
- # Check if EnableLoginByWam is true
- if ((Get-AzConfig -EnableLoginByWam).Value -eq $true) {
- Write-Verbose "Process: Disabling interactive login experience (EnableLoginByWam).`n"
- # Disable the WAM login experience for the current PowerShell session
- Update-AzConfig -EnableLoginByWam $false -Scope Process | Out-Null
- }
-
- # Check if LoginExperienceV2 is 'On'
- if ((Get-AzConfig -LoginExperienceV2).Value -eq 'On') {
- Write-Verbose "Process: Disabling interactive login experience (LoginExperienceV2).`n"
- # Disable the new login experience for the current PowerShell session
- Update-AzConfig -LoginExperienceV2 Off -Scope Process | Out-Null
- }
-
- Write-Verbose 'Process: Connecting to Azure.'
- Write-Verbose 'No existing context found or context does not match TenantID. Connecting to Azure...'
- Connect-AzAccount -Tenant $TenantID -Environment $AzureEnvironment -ErrorAction Stop -WarningAction Ignore -InformationAction Ignore
- $AzContext = Get-AzContext -ErrorAction Stop
- Write-Verbose "Successfully connected to Azure Tenant: $TenantID"
- } else {
- Write-Host "`nAlready connected to Azure Tenant: $($AzContext.Tenant.Id)`n" -ForegroundColor Green
- }
-
- # Validate that the provided Subscription IDs exist in the current context
- $Script:SubIds = Get-AzSubscription -ErrorAction Stop -WarningAction Ignore
- Write-Verbose "Connected to Azure Tenant: $($AzContext.Tenant.Id) with Subscriptions: $($SubscriptionIds -join ', ')"
- } catch {
- throw "Failed to connect to Azure Tenant: $TenantID or retrieve subscriptions. Error: $_"
- }
- }
-
- end {
- if ($AzContext) {
- Write-Verbose 'Connection process completed successfully.'
- } else {
- throw 'Connection process failed. No valid Azure context available.'
- }
- }
- }
-
- function Test-Runbook {
- # Checks if a runbook file was provided and, if so, loads selectors and checks hashtables
- if (![string]::IsNullOrEmpty($RunbookFile)) {
-
- Write-Host '[-RunbookFile]: A runbook has been configured. Only checks configured in the runbook will be run.' -ForegroundColor Cyan
-
- # Check that the runbook file actually exists
- if (Test-Path $RunbookFile -PathType Leaf) {
-
- # Try to load runbook JSON
- $RunbookJson = Get-Content -Raw $RunbookFile | ConvertFrom-Json
-
- # Try to load parameters
- $RunbookJson.parameters.PSObject.Properties | ForEach-Object {
- $Script:RunbookParameters[$_.Name] = $_.Value
- }
-
- # Try to load selectors
- $RunbookJson.selectors.PSObject.Properties | ForEach-Object {
- $Script:RunbookSelectors[$_.Name.ToLower()] = $_.Value
- }
-
- # Try to load checks
- $RunbookJson.checks.PSObject.Properties | ForEach-Object {
- $Script:RunbookChecks[$_.Name.ToLower()] = $_.Value
- }
-
- # Try to load query overrides
- $RunbookJson.query_overrides | ForEach-Object {
- $Script:RunbookQueryOverrides += [string]$_
- }
- }
- } else {
- Write-Host '[-RunbookFile]: No runbook (-RunbookFile) configured.' -ForegroundColor DarkGray
- }
- }
-
- function Start-ScopesLoop {
- $Date = (Get-Date).AddMonths(-24)
- $DateOutages = (Get-Date).AddMonths(-3)
- $DateCore = (Get-Date).AddMonths(-3)
- $Date = $Date.ToString('MM/dd/yyyy')
- if ($AzureEnvironment -eq 'AzureUSGovernment') {
- $BaseURL = 'management.usgovcloudapi.net'
- } else {
- $BaseURL = 'management.azure.com'
- }
- $LoopedSub = @()
-
- foreach ($Scope in $Scopes) {
- if (![string]::IsNullOrEmpty($Scope)) {
- $ScopeWithoutParameter = $Scope.split(' -')[0]
- $ScopeParameters = $Scope.split(' -')
- $ScopeParameters = $ScopeParameters[1..($ScopeParameters.Length - 1)]
- $Subscription = $ScopeWithoutParameter.split('/')[2]
- $RGroup = if (![string]::IsNullOrEmpty($ScopeWithoutParameter.split('/')[4])) { $ScopeWithoutParameter.split('/')[4] }else { $null }
- $SubId = $SubIds | Where-Object { $_.Id -eq $Subscription }
- Write-Host '---------------------------------------------------------------------'
- Write-Host 'Validating Scope: ' -NoNewline
- Write-Host $ScopeWithoutParameter -ForegroundColor Cyan
-
- Set-AzContext -Subscription $Subscription -ErrorAction SilentlyContinue -WarningAction SilentlyContinue | Out-Null
- Select-AzSubscription -Subscription $Subscription -WarningAction SilentlyContinue -InformationAction SilentlyContinue | Out-Null
-
- if ($SubId -notin $LoopedSub) {
- try{
- $Token = Get-AzAccessToken -AsSecureString -WarningAction SilentlyContinue
- }
- catch {
- Write-Host 'Failed to get token for subscription: ' -NoNewline
- Write-Host $SubId.Name -ForegroundColor Red
- Connect-ToAzure -TenantID $TenantID -AzureEnvironment $AzureEnvironment
- }
-
-
- $header = @{
- 'Authorization' = 'Bearer ' + ($Token.Token | ConvertFrom-SecureString -AsPlainText)
- }
-
- try {
- Write-Host '----------------------------'
- Write-Host 'Collecting: ' -NoNewline
- Write-Host 'Outages' -ForegroundColor Magenta
- $url = ('https://' + $BaseURL + '/subscriptions/' + $Subid + '/providers/Microsoft.ResourceHealth/events?api-version=2022-10-01&queryStartTime=' + $Date)
- $Outages = Invoke-RestMethod -Uri $url -Headers $header -Method GET
- $Script:Outageslist += $Outages.value | Where-Object { $_.properties.impactStartTime -gt $DateOutages } | Sort-Object @{Expression = 'properties.eventlevel'; Descending = $false }, @{Expression = 'properties.status'; Descending = $false } | Select-Object -Property name, properties
- $Script:RetiredOutages += $Outages.value | Sort-Object @{Expression = 'properties.eventlevel'; Descending = $false }, @{Expression = 'properties.status'; Descending = $false } | Select-Object -Property name, properties
- } catch { $null }
-
- try {
- Write-Host '----------------------------'
- Write-Host 'Collecting: ' -NoNewline
- Write-Host 'Support Tickets' -ForegroundColor Magenta
- $supurl = ('https://' + $BaseURL + '/subscriptions/' + $Subid + '/providers/Microsoft.Support/supportTickets?api-version=2020-04-01')
- $SupTickets = Invoke-RestMethod -Uri $supurl -Headers $header -Method GET
- $Script:SupportTickets += $SupTickets.value | Where-Object { $_.properties.severity -ne 'Minimal' -and $_.properties.createdDate -gt $DateCore } | Select-Object -Property name, properties
- } catch { $null }
- }
-
- Write-Host '----------------------------'
- Write-Host 'Collecting: ' -NoNewline
- Write-Host 'Resources Details' -ForegroundColor Magenta
- if ($ScopeWithoutParameter.split('/').count -lt 5) {
- $InScopeSub = $ScopeWithoutParameter.split('/')[2]
- $ScopeQuery = "resources | where subscriptionId =~ '$InScopeSub' | project id, resourceGroup, subscriptionId, name, type, location"
- } elseif ($ScopeWithoutParameter.split('/').count -gt 4 -and $Scope.split('/').count -lt 8) {
- $InScopeSub = $Scope.split('/')[2]
- $InScopeRG = $Scope.split('/')[4]
- $ScopeQuery = "resources | where subscriptionId =~ '$InScopeSub' and resourceGroup =~ '$InScopeRG' | project id, resourceGroup, subscriptionId, name, type, location"
- } elseif ($ScopeWithoutParameter.split('/').count -ge 9) {
- $ScopeQuery = "resources | where id =~ '$ScopeWithoutParameter' | project id, resourceGroup, subscriptionId, name, type, location"
- }
- #Filter out the Supported Types
- if ($Debugging.IsPresent) {
- Write-Host $ScopeQuery -ForegroundColor Cyan
- }
- $ScopeResources = Get-AllAzGraphResource -query $ScopeQuery -subscriptionId $Subid
- foreach ($Resource in $ScopeResources) {
- if ($Resource.type -in $Script:SupportedResTypes) {
- if ($Resource.id -notin $Script:PreInScopeResources.id) {
- $Script:PreInScopeResources += $Resource
- }
- } else {
- $Script:PreOutOfScopeResources += $Resource
- }
- }
-
- if ($Tags) {
- Write-Host '----------------------------'
- Write-Host 'Collecting: ' -NoNewline
- Write-Host 'Tagged Resources' -ForegroundColor Magenta
- Invoke-TagFiltering -Scope $ScopeWithoutParameter
- }
-
- Write-Host '----------------------------'
- Write-Host 'Collecting: ' -NoNewline
- Write-Host 'Advisor Recommendations' -ForegroundColor Magenta
- $AdvGroup = $null
- if (![string]::IsNullOrEmpty($RGroup)) {
- $AdvGroup = $RGroup.split('/')[4]
- }
- Invoke-AdvisoryExtraction -SubId $SubId -ResourceGroup $AdvGroup
-
- if ($SubId -notin $LoopedSub) {
- Write-Host '----------------------------'
- Write-Host 'Collecting: ' -NoNewline
- Write-Host 'Service Retirements Notifications' -ForegroundColor Magenta
- Invoke-RetirementExtraction $Subid
-
- Write-Host '----------------------------'
- Write-Host 'Collecting: ' -NoNewline
- Write-Host 'Service Health Alerts' -ForegroundColor Magenta
- Invoke-ServiceHealthExtraction $Subid
- $LoopedSub += $SubId
- }
- Write-Host '----------------------------'
- Write-Host 'Running: ' -NoNewline
- Write-Host 'Queries' -ForegroundColor Magenta
- Write-Host '----------------------------'
- Start-ResourceExtraction -Scope $ScopeWithoutParameter
- }
- }
- }
-
- function Invoke-TagFiltering {
- param($Scope)
-
- $Scope = $Scope.split(' -')[0]
- if ($Scope.split('/').count -lt 5) {
- $InScopeSub = $Scope.split('/')[2]
- $ResourceScopeQuery = "resources | where subscriptionId =~ '$InScopeSub' "
- $ContainerScopeQuery = "resourceContainers | where id has '$Scope' "
- } elseif ($Scope.split('/').count -gt 4 -and $Scope.split('/').count -lt 8) {
- $InScopeSub = $Scope.split('/')[2]
- $InScopeRG = $Scope.split('/')[4]
- $ResourceScopeQuery = "resources | where subscriptionId =~ '$InScopeSub' and resourceGroup =~ '$InScopeRG' "
- $ContainerScopeQuery = "resourceContainers | where id =~ '$Scope' "
- } elseif ($Scope.split('/').count -ge 9) {
- $ResourceScopeQuery = "resources | where id =~ '$Scope' "
- $ContainerScopeQuery = "resourceContainers | where id =~ '$Scope' "
- }
-
- $TagFilter = $Tags
-
- # Each line in the Tag Filtering file will be processed
- $AllTaggedResources = @()
- $ResetTags = $false
- Foreach ($TagLine in $TagFilter) {
- $AllTaggedResourceGroups = ''
- # Finding the TagKey and all the TagValues in the line
- if ($TagLine -like '*=~*') {
- $TagKeys = $TagLine.split('=~')[0]
- $TagValues = $TagLine.split('=~')[1]
- } elseif ($TagLine -like '*!~*') {
- $TagKeys = $TagLine.split('!~')[0]
- $TagValues = $TagLine.split('!~')[1]
- }
-
- $TagKeys = $TagKeys.split('||')
- $TagValues = $TagValues.split('||')
-
- $TagKey = if ($TagKeys.count -gt 1) { $TagKeys | ForEach-Object { "'$_'," } }else { $TagKeys }
- $TagKey = [string]$TagKey
- $TagKey = if ($TagKey -like "*',*") { $TagKey -replace '.$' }else { "'$TagKey'" }
-
- $TagValue = if ($TagValues.count -gt 1) { $TagValues | ForEach-Object { "'$_'," } }else { $TagValues }
- $TagValue = [string]$TagValue
- $TagValue = if ($TagValue -like "*',*") { $TagValue -replace '.$' }else { "'$TagValue'" }
-
- if ($Debugging.IsPresent) {
- Write-Host ('Running Resource Group Tag Inventory for: ' + $TagKey + ' : ' + $TagValue)
- }
-
- if ($TagLine -like '*=~*') {
- #Getting all the Resource Groups with the Tags, this will be used later
- $RGTagQuery = "$ContainerScopeQuery | mvexpand tags | extend tagKey = tostring(bag_keys(tags)[0]) | extend tagValue = tostring(tags[tagKey]) | where tagKey in~ ($TagKey) and tagValue in~ ($TagValue) | project id | order by id"
- } elseif ($TagLine -like '*!~*') {
- $RGTagQuery = "$ContainerScopeQuery | mvexpand tags | extend tagKey = tostring(bag_keys(tags)[0]) | extend tagValue = tostring(tags[tagKey]) | where tagKey in~ ($TagKey) and tagValue !in~ ($TagValue) | project id | order by id"
- }
- $TaggedResourceGroups = Get-AllAzGraphResource -query $RGTagQuery -subscriptionId $InScopeSub
- if ($Debugging.IsPresent) {
- Write-Host 'Tagged Resource Containers Found: ' -NoNewline
- $Tagged = [string]$TaggedResourceGroups.count
- Write-Host $Tagged -ForegroundColor Magenta
- }
-
- if ($TaggedResourceGroups) {
- foreach ($ResourceGroup in $TaggedResourceGroups.id) {
- if ($Debugging.IsPresent) {
- Write-Host ('Checking Resources Inside: ' + $ResourceGroup)
- }
- $ResourcesTagQuery = "Resources | where id startswith '$ResourceGroup' | project id, name, subscriptionId, type, resourceGroup, location | order by id"
-
- $AllTaggedResourceGroups = Get-AllAzGraphResource -query $ResourcesTagQuery -subscriptionId $InScopeSub
- if ($Debugging.IsPresent) {
- Write-Host 'Resources Found Inside the Container: ' -NoNewline
- $Tagged = [string]$AllTaggedResourceGroups.count
- Write-Host $Tagged -ForegroundColor Magenta
- }
- }
- }
-
- if ($Debugging.IsPresent) {
- Write-Host ('Running Resource Tag Inventory for: ' + $TagKey + ' : ' + $TagValue)
- }
- if ($TagLine -like '*=~*') {
- #Getting all the resources within the TAGs
- $ResourcesTagQuery = "$ResourceScopeQuery | mvexpand tags | extend tagKey = tostring(bag_keys(tags)[0]) | extend tagValue = tostring(tags[tagKey]) | where tagKey in~ ($TagKey) and tagValue in~ ($TagValue) | project id, name, subscriptionId, type, resourceGroup, location | order by id"
- } elseif ($TagLine -like '*!~*') {
- $ResourcesTagQuery = "$ResourceScopeQuery | mvexpand tags | extend tagKey = tostring(bag_keys(tags)[0]) | extend tagValue = tostring(tags[tagKey]) | where tagKey in~ ($TagKey) and tagValue !in~ ($TagValue) | project id, name, subscriptionId, type, resourceGroup, location | order by id"
- }
- $ResourcesWithTHETag = Get-AllAzGraphResource -query $ResourcesTagQuery -subscriptionId $InScopeSub
-
- if ($Debugging.IsPresent) {
- Write-Host 'Tagged Resources Found: ' -NoNewline
- $Tagged = [string]$ResourcesWithTHETag.count
- Write-Host $Tagged -ForegroundColor Magenta
- }
-
- if (![string]::IsNullOrEmpty($ResourcesWithTHETag) -and [string]::IsNullOrEmpty($AllTaggedResources) -and $ResetTags -eq $false) {
- $AllTaggedResources += $ResourcesWithTHETag
- $AllTaggedResources += $AllTaggedResourceGroups
- } elseif ([string]::IsNullOrEmpty($ResourcesWithTHETag) -and ![string]::IsNullOrEmpty($AllTaggedResourceGroups)) {
- $AllTaggedResources += $AllTaggedResourceGroups
- } elseif ([string]::IsNullOrEmpty($ResourcesWithTHETag) -and [string]::IsNullOrEmpty($AllTaggedResourceGroups)) {
- if ($Debugging.IsPresent) {
- Write-Host 'No Tagged Resources were found. Reseting Values.'
- }
- $AllTaggedResources = @()
- $ResetTags = $true
- } elseif (![string]::IsNullOrEmpty($AllTaggedResources) -and $ResetTags -eq $false) {
- foreach ($resource in $AllTaggedResources) {
- if ($resource.id -notin $ResourcesWithTHETag.id) {
- $AllTaggedResources = $AllTaggedResources | Where-Object { $_.id -ne $resource.id }
- }
- }
- }
- }
- $Script:TaggedResources += $AllTaggedResources | Select-Object -Property id, name, subscriptionId, type, resourceGroup, location -Unique -CaseInsensitive
- if ($Debugging.IsPresent) {
- Write-Host 'Tagged Resources Final Value: ' -NoNewline
- $Tagged = [string]$Script:TaggedResources.count
- Write-Host $Tagged -ForegroundColor Magenta
- }
- }
-
- function Invoke-QueryExecution {
- param($type, $Subscription, $query, $checkId, $checkName, $selector, $validationAction)
-
- $TempResult = @()
-
- if ($Debugging.IsPresent) {
- Write-Host $query -ForegroundColor Yellow
- }
-
- try {
- $ResourceType = $Script:AllResourceTypes | Where-Object { $_.Name -eq $type }
- if (![string]::IsNullOrEmpty($resourceType)) {
- # Execute the query and collect the results
- # $queryResults = Search-AzGraph -Query $query -First 1000 -Subscription $Subid -ErrorAction SilentlyContinue
- $queryResults = Get-AllAzGraphResource -query $query -subscriptionId $Subscription
-
- $queryResults = $queryResults | Sort-Object -Property name, id, param1, param2, param3, param4, param5 -Unique
-
- foreach ($row in $queryResults) {
- $result = @{
- validationAction = [string]$validationAction;
- recommendationId = [string]$checkId;
- name = [string]$row.name;
- Type = [string]$type;
- id = [string]$row.id;
- param1 = [string]$row.param1;
- param2 = [string]$row.param2;
- param3 = [string]$row.param3;
- param4 = [string]$row.param4;
- param5 = [string]$row.param5;
- checkName = [string]$checkName;
- selector = [string]$selector
- }
- $TempResult += $result
- }
- }
-
- if ($type -like '*azure-specialized-workloads/*') {
- $result = @{
- validationAction = [string]$validationAction;
- recommendationId = [string]$checkId;
- name = [string]'';
- Type = [string]$type;
- id = [string]'';
- param1 = [string]$type;
- param2 = [string]'';
- param3 = [string]'';
- param4 = [string]'';
- param5 = [string]'';
- checkName = [string]$checkName;
- selector = [string]$selector
- }
- $TempResult += $result
- }
-
- return $TempResult
-
- } catch {
- # Report Error
- $errorMessage = $_.Exception.Message
- Write-Host "Error processing query results: $errorMessage" -ForegroundColor Red
- }
- }
-
- function Start-ResourceExtraction {
- [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')]
- param($Scope)
-
- $TempResult = @()
- if ($PSCmdlet.ShouldProcess('')) {
- $Scope = $Scope.split(' -')[0]
-
- if ($Scope.split('/').count -lt 5) {
- $Subid = $Scope.split('/')[2]
- $ResourceGroup = $null
- } elseif ($Scope.split('/').count -gt 4 -and $Scope.split('/').count -lt 8) {
- $Subid = $Scope.split('/')[2]
- $ResourceGroup = $Scope.split('/')[4]
- } elseif ($Scope.split('/').count -ge 9) {
- $Subid = $Scope.split('/')[2]
- $ResourceGroup = $Scope.split('/')[4]
- }
-
- # Set the variables used in the loop
- if ($Scope.split('/').count -lt 5) {
- # Extract and display resource types with the query with subscriptions, we need this to filter the subscriptions later
- $resultAllResourceTypes = $Script:PreInScopeResources | Where-Object { $_.id -like "/subscriptions/$Subid*" } | Group-Object -Property type -NoElement
- $Script:AllResourceTypes += $resultAllResourceTypes
- } elseif ($Scope.split('/').count -gt 4 -and $Scope.split('/').count -lt 8) {
- $resultAllResourceTypes = $Script:PreInScopeResources | Where-Object { $_.id -like "/subscriptions/$Subid/resourcegroups/$ResourceGroup*" } | Group-Object -Property type -NoElement
- $Script:AllResourceTypes += $resultAllResourceTypes
- } elseif ($Scope.split('/').count -ge 9) {
- $resultAllResourceTypes = $Script:PreInScopeResources | Where-Object { $_.id -eq $Scope } | Group-Object -Property type -NoElement
- $Script:AllResourceTypes += $resultAllResourceTypes
- }
-
- # Create the arrays used to store the kusto queries
- $kqlQueryMap = @{}
- $aprlKqlFiles = @()
- $ServiceNotAvailable = @()
-
- foreach ($Type in $resultAllResourceTypes.Name) {
- if ($Type.ToLower() -in $Script:SupportedResTypes) {
- $Type = $Type.replace('microsoft.', '')
- $Provider = $Type.split('/')[0]
- $ResourceType = $Type.split('/')[1]
-
- $Path = ''
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $Path = ($clonePath + '\azure-resources\' + $Provider + '\' + $ResourceType)
- $RecommendationsPath = ($clonePath + '\azure-resources\' + $Provider + '\' + $ResourceType + '\recommendations.yaml')
- $RecommendationValidation = ''
- $RecommendationValidation = Get-ChildItem -Path $RecommendationsPath -File -ErrorAction SilentlyContinue -WarningAction SilentlyContinue
- if (![string]::IsNullOrEmpty($RecommendationValidation)) {
- $aprlKqlFiles += Get-ChildItem -Path $Path -Filter '*.kql' -Recurse
- } else {
- if (('microsoft.' + $Type) -notin $Script:AdvisorTypes) {
- $ServiceNotAvailable += ('microsoft.' + $Type)
- }
- }
- } else {
- $Path = ($clonePath + '/azure-resources/')
- $ProvPath = ($Provider + '/' + $ResourceType)
- $RecommendationValidation = Get-ChildItem -Path $Path -Filter 'recommendations.yaml' -Recurse | Where-Object { $_.FullName -like "*$ProvPath*" }
- if (![string]::IsNullOrEmpty($RecommendationValidation)) {
- $aprlKqlFiles += Get-ChildItem -Path $Path -Filter '*.kql' -Recurse | Where-Object { $_.FullName -like "*$ProvPath*" }
- } else {
- if (('microsoft.' + $Type) -notin $Script:AdvisorTypes) {
- $ServiceNotAvailable += ('microsoft.' + $Type)
- }
- }
- }
- }
- }
-
- # Checks if specialized workloads will be validated
- if ($SAP.IsPresent) {
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $aprlKqlFiles += Get-ChildItem -Path ($clonePath + '\azure-specialized-workloads\sap') -Filter '*.kql' -Recurse
- } else {
- $aprlKqlFiles += Get-ChildItem -Path ($clonePath + '/azure-specialized-workloads/sap') -Filter '*.kql' -Recurse
- }
- }
-
- if ($AVD.IsPresent) {
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $aprlKqlFiles += Get-ChildItem -Path ($clonePath + '\azure-specialized-workloads\avd') -Filter '*.kql' -Recurse
- } else {
- $aprlKqlFiles += Get-ChildItem -Path ($clonePath + '/azure-specialized-workloads/avd') -Filter '*.kql' -Recurse
- }
- }
-
- if ($AVS.IsPresent) {
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $aprlKqlFiles += Get-ChildItem -Path ($clonePath + '\azure-specialized-workloads\avs') -Filter '*.kql' -Recurse
- } else {
- $aprlKqlFiles += Get-ChildItem -Path ($clonePath + '/azure-specialized-workloads/avs') -Filter '*.kql' -Recurse
- }
- }
-
- if ($HPC.IsPresent) {
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $aprlKqlFiles += Get-ChildItem -Path ($clonePath + '\azure-specialized-workloads\hpc') -Filter '*.kql' -Recurse
- } else {
- $aprlKqlFiles += Get-ChildItem -Path ($clonePath + '/azure-specialized-workloads/hpc') -Filter '*.kql' -Recurse
- }
- }
-
- # Populates the QueryMap hashtable
- foreach ($aprlKqlFile in $aprlKqlFiles) {
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $kqlShort = [string]$aprlKqlFile.FullName.split('\')[-1]
- } else {
- $kqlShort = [string]$aprlKqlFile.FullName.split('/')[-1]
- }
- $kqlName = $kqlShort.split('.')[0]
-
- # Create APRL query map based on recommendation
- $kqlQueryMap[$kqlName] = $aprlKqlFile
- }
-
- if ($Script:RunbookQueryOverrides) {
- foreach ($queryOverridePath in $($Script:RunbookQueryOverrides)) {
- Write-Host "[-RunbookFile]: Loading [$($queryOverridePath)] query overrides..." -ForegroundColor Cyan
-
- $overrideKqlFiles = Get-ChildItem -Path $queryOverridePath -Filter '*.kql' -Recurse
-
- foreach ($overrideKqlFile in $overrideKqlFiles) {
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $kqlShort = [string]$overrideKqlFile.FullName.split('\')[-1]
- } else {
- $kqlShort = [string]$overrideKqlFile.FullName.split('/')[-1]
- }
- $kqlName = $kqlShort.split('.')[0]
-
- if ($kqlQueryMap.ContainsKey($kqlName)) {
- Write-Host "[-RunbookFile]: Original [$kqlName] APRL query overridden by [$($overrideKqlFile.FullName)]." -ForegroundColor Cyan
- }
-
- # Override APRL query map based on recommendation
- $kqlQueryMap[$kqlName] = $overrideKqlFile
- }
- }
- }
-
- $kqlFiles = $kqlQueryMap.Values
-
- $queries = @()
- # Loop through each KQL file and execute the queries
- foreach ($kqlFile in $kqlFiles) {
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $kqlshort = [string]$kqlFile.FullName.split('\')[-1]
- } else {
- $kqlshort = [string]$kqlFile.FullName.split('/')[-1]
- }
-
- $kqlname = $kqlshort.split('.')[0]
-
- # Read the query content from the file
- $baseQuery = Get-Content -Path $kqlFile.FullName | Out-String
- if ($Script:ShellPlatform -eq 'Win32NT') {
- $typeRaw = $kqlFile.DirectoryName.split('\')
- } else {
- $typeRaw = $kqlFile.DirectoryName.split('/')
- }
-
- $kqltype = ('Microsoft.' + $typeRaw[-3] + '/' + $typeRaw[-2])
- $checkId = $kqlname.Split('/')[-1].ToLower()
-
- if ($Script:RunbookChecks -and $Script:RunbookChecks.Count -gt 0) {
- # A runbook has been provided...
-
- if ($Script:RunbookChecks.ContainsKey($checkId)) {
- # A check has been configured in the runbook for this query...
-
- $runbookCheckCt = 0
-
- $check = $Script:RunbookChecks[$checkId]
-
- $check.PSObject.Properties | ForEach-Object {
- $checkName = $_.Name
- $defaultSelectorName = $_.Value
-
- if ($Script:RunbookSelectors.ContainsKey($defaultSelectorName)) {
- # If a matching selector exists, add a new query to the queries array
- # that includes the appropriate selector...
-
- $selectorQuery = $baseQuery
-
- # Resolve named selectors...
- foreach ($selectorKey in $Script:RunbookSelectors.Keys) {
- $namedSelector = $Script:RunbookSelectors[$selectorKey]
- $selectorQuery = $selectorQuery.Replace("// selector:$selectorKey", "| where $namedSelector")
- $selectorQuery = $selectorQuery.Replace("//selector:$selectorKey", "| where $namedSelector")
- }
-
- # Then, resolve any default selectors...
- $checkSelector = $Script:RunbookSelectors[$defaultSelectorName]
- $selectorQuery = $selectorQuery.Replace('//selector', "| where $checkSelector")
- $selectorQuery = $selectorQuery.Replace('// selector', "| where $checkSelector")
-
- if ($UseImplicitRunbookSelectors) {
- # Then, wrap the entire query in an inner join to apply a global selector.
- # With this approach, queries that implement the APRL interface
- # (projecting the recId, id, tags, etc.) columns can be refined using
- # selectors without any changes to the original query. The original query
- # is wrapped in an inner join that limits the results to only those that
- # match the selector.
-
- $selectorQuery = 'resources ' `
- + " | where $checkSelector " `
- + ' | project id ' `
- + ' | join kind=inner ( ' `
- + " $selectorQuery ) on id " `
- + ' | project-away id1'
- }
-
- # Merge parameters after selectors have been applied (selectors may include parameters)...
- foreach ($parameterName in $Script:RunbookParameters.Keys) {
- $value = $Script:RunbookParameters[$parameterName]
- $selectorQuery = $selectorQuery.Replace("{{$parameterName}}", $value)
- }
-
- $queries += [PSCustomObject]@{
- checkId = [string]$checkId
- checkName = [string]$checkName
- selector = [string]$defaultSelectorName
- query = [string]$selectorQuery
- type = [string]$kqltype
- }
-
- $runbookCheckCt++
-
- } else {
- Write-Host "[-RunbookFile]: Selector $selectorName not found in runbook. Skipping check..." -ForegroundColor Yellow
- }
- }
-
- if ($queries.Count -gt 0) {
- Write-Host "[-RunbookFile]: There are $runbookCheckCt runbook check(s) configured for $checkId. Running checks..." -ForegroundColor Cyan
- }
- }
- } else {
- # A runbook hasn't been configured. The queries array will contain
- # just one element -- the original query. No selectors.
-
- $queries += [PSCustomObject]@{
- checkId = [string]$checkId
- checkName = [string]$null
- selector = 'APRL'
- query = [string]$baseQuery
- type = [string]$kqltype
- }
- }
- }
-
- foreach ($queryDef in $queries) {
- $checkId = $queryDef.checkId
- $checkName = $queryDef.checkName
- $query = $queryDef.query
- $selector = $queryDef.selector
- $type = $queryDef.type
-
- Write-Host '++++++++++++++++++ ' -NoNewline
- if ($selector -eq 'APRL') {
- Write-Host "[APRL]: $type - $checkId" -ForegroundColor Green -NoNewline
- } else {
- Write-Host "[-RunbookFile]: [$checkName (selector: '$selector')]: $checkId" -ForegroundColor Green -NoNewline
- }
- Write-Host ' +++++++++++++++'
-
- # Validating if Query is Under Development
- if ($query -match 'development') {
- Write-Host "Query $checkId under development - Validate Recommendation manually" -ForegroundColor Yellow
- $query = "resources | where type =~ '$type' | project name,id"
- $TempResult += Invoke-QueryExecution -type $type -Subscription $Subid -query $query -checkId $checkId -checkName $checkName -selector $selector -validationAction 'IMPORTANT - Query under development - Validate Resources manually'
- } elseif ($query -match 'cannot-be-validated-with-arg') {
- Write-Host "IMPORTANT - Recommendation $checkId cannot be validated with ARGs - Validate Resources manually" -ForegroundColor Yellow
- $query = "resources | where type =~ '$type' | project name,id"
- $TempResult += Invoke-QueryExecution -type $type -Subscription $Subid -query $query -checkId $checkId -checkName $checkName -selector $selector -validationAction 'IMPORTANT - Recommendation cannot be validated with ARGs - Validate Resources manually'
- } else {
- $TempResult += Invoke-QueryExecution -type $type -Subscription $Subid -query $query -checkId $checkId -checkName $checkName -selector $selector -validationAction 'APRL - Queries'
- }
- }
-
- if ($Scope.split('/').count -gt 4 -and $Scope.split('/').count -lt 8) {
- if (![string]::IsNullOrEmpty($TempResult)) {
- $Script:results += Get-ResourceGroupsByList -ObjectList $TempResult -FilterList $Scope -KeyColumn 'id'
- }
-
- } else {
- if (![string]::IsNullOrEmpty($TempResult)) {
- $Script:results += $TempResult
- }
- }
-
-
-
- # Unless we're using a runbook...
- if (!($Script:RunbookChecks -and $Script:RunbookChecks.Count -gt 0)) {
- # Store all resourcetypes not in APRL
- foreach ($type in $ServiceNotAvailable) {
- Write-Host "Type $type Not Available In APRL - Validate Service manually" -ForegroundColor Yellow
- $query = "resources | where type =~ '$type' | project name,id"
- $Script:results += Invoke-QueryExecution -type $type -Subscription $Subid -query $query -checkId $type -selector 'APRL' -checkName '' -validationAction 'IMPORTANT - Resource Type is not available in either APRL or Advisor - Validate Resources manually if Applicable, if not Delete this line'
- }
- }
- }
- }
-
- Function Invoke-FilterResourceID {
- [cmdletbinding()]
- Param(
- $ResourceID,
- $List
- )
- ForEach ($item in $List) {
- If ($ResourceID -eq $Item.id) { $item }
- }
- }
-
- function Invoke-ResourceFiltering {
- if ($Tags) {
- Write-Host 'Filtering Resources In-Scope for Tag Filtering..' -ForegroundColor Cyan
- $Script:InScope = foreach ($Resource in $Script:PreInScopeResources) {
- if ($Resource.id -in $Script:TaggedResources.id) {
- $Resource
- }
- }
- } else {
- Write-Host 'Selecting In-Scope Resources..' -ForegroundColor Cyan
- $Script:InScope = $Script:PreInScopeResources
- }
-
- if (![string]::IsNullOrEmpty($Script:ExcludeList)) {
- Write-Host 'Filtering Excluded Resources..' -ForegroundColor Cyan
- $Script:InScope = $Script:InScope | Where-Object { $_.id -notin $Script:ExcludeList.id }
- }
-
- $Script:AllGroupedResourceTypes = $Script:InScope | Group-Object -Property type
-
- Write-Host 'Ordering Impacted Resources..' -ForegroundColor Cyan
- $Script:results = $Script:results | Sort-Object -Unique -Property validationAction, recommendationId, name, Type, id, param1, param2, param3, param4, param5, checkName, selector
-
- Write-Host 'Filtering Impacted Resources..' -ForegroundColor Cyan
- $Script:ImpactedResources = foreach ($Temp in $Script:results) {
- $TempResID = $Temp.id.split('/')
- $TempResID = ('/' + $TempResID[1] + '/' + $TempResID[2] + '/' + $TempResID[3] + '/' + $TempResID[4] + '/' + $TempResID[5] + '/' + $TempResID[6] + '/' + $TempResID[7] + '/' + $TempResID[8])
-
- if ($Temp.id -eq 'n/a') {
- $result = [PSCustomObject]@{
- validationAction = $Temp.validationAction
- recommendationId = $Temp.recommendationId
- name = 'n/a'
- id = 'n/a'
- type = 'n/a'
- location = 'n/a'
- subscriptionId = 'n/a'
- resourceGroup = 'n/a'
- param1 = $Temp.param1
- param2 = $Temp.param2
- param3 = $Temp.param3
- param4 = $Temp.param4
- param5 = $Temp.param5
- checkName = $Temp.checkName
- selector = $Temp.selector
- }
- $result
- } elseif ($TempResID -in $Script:InScope.id) {
- $TempDetails = Invoke-FilterResourceID -Resource $TempResID -List $Script:PreInScopeResources
- $result = [PSCustomObject]@{
- validationAction = $Temp.validationAction
- recommendationId = $Temp.recommendationId
- name = $Temp.name
- id = $Temp.id
- type = $TempDetails.type
- location = $TempDetails.location
- subscriptionId = $TempDetails.subscriptionId
- resourceGroup = $TempDetails.resourceGroup
- param1 = $Temp.param1
- param2 = $Temp.param2
- param3 = $Temp.param3
- param4 = $Temp.param4
- param5 = $Temp.param5
- checkName = $Temp.checkName
- selector = $Temp.selector
- }
- $result
- } elseif ($Temp.Type -like '*azure-specialized-workloads/*') {
- $result = [PSCustomObject]@{
- validationAction = $Temp.validationAction
- recommendationId = $Temp.recommendationId
- name = ''
- id = ''
- type = 'Microsoft.Subscription/Subscriptions'
- location = ''
- subscriptionId = ''
- resourceGroup = ''
- param1 = $Temp.param1
- param2 = ''
- param3 = ''
- param4 = ''
- param5 = ''
- checkName = $Temp.checkName
- selector = $Temp.selector
- }
- $result
- }
- }
-
- $Script:ImpactedResources = $Script:ImpactedResources | Sort-Object -Unique -Property validationAction, recommendationId, name, Type, id, param1, param2, param3, param4, param5, checkName, selector
-
- Write-Host 'Filtering Advisor Resources..' -ForegroundColor Cyan
- $Script:Advisories += foreach ($adv in $Script:AllAdvisories) {
- if ($adv.id -in $Script:InScope.id) {
- $adv
- }
- }
-
- Write-Host 'Filtering Out of Scope Resources..' -ForegroundColor Cyan
- $Script:OutOfScope = foreach ($ResIID in $Script:PreOutOfScopeResources) {
- if ($Tags) {
- if ($ResIID.id -in $Script:TaggedResources.id) {
- $result = [PSCustomObject]@{
- description = 'No Action Required - This ResourceType is already covered by its Parent ResourceType, or is out of scope of Well-Architected Reliability Assessment engagements.'
- type = $ResIID.type
- subscriptionId = $ResIID.subscriptionId
- resourceGroup = $ResIID.resourceGroup
- name = $ResIID.name
- location = $ResIID.location
- id = $ResIID.id
- }
- $result
- }
- } else {
- $result = [PSCustomObject]@{
- description = 'No Action Required - This ResourceType is already covered by its Parent ResourceType, or is out of scope of Well-Architected Reliability Assessment engagements.'
- type = $ResIID.type
- subscriptionId = $ResIID.subscriptionId
- resourceGroup = $ResIID.resourceGroup
- name = $ResIID.name
- location = $ResIID.location
- id = $ResIID.id
- }
- $result
- }
- }
- }
-
- function Resolve-ResourceType {
- $TempTypes = $Script:ImpactedResources | Where-Object { $_.validationAction -eq 'IMPORTANT - Resource Type is not available in either APRL or Advisor - Validate Resources manually if Applicable, if not Delete this line' }
- $Script:AllGroupedResourceTypes = $Script:AllGroupedResourceTypes | Sort-Object -Property Count -Descending
- foreach ($EnvType in $Script:AllGroupedResourceTypes) {
- if ($EnvType.Name -in $TempTypes.recommendationId) {
- $tmp = [PSCustomObject]@{
- 'Resource Type' = [string]$EnvType.Name
- 'Number of Resources' = [string]$EnvType.Count
- 'Available in APRL/ADVISOR?' = 'No'
- 'Assessment Owner' = ''
- 'Status' = ''
- 'Notes' = ''
- }
- $Script:AllResourceTypesOrdered += $tmp
- } elseif ($EnvType.Name -notin $TempTypes.recommendationId) {
- $tmp = [PSCustomObject]@{
- 'Resource Type' = [string]$EnvType.Name
- 'Number of Resources' = [string]$EnvType.Count
- 'Available in APRL/ADVISOR?' = 'Yes'
- 'Assessment Owner' = ''
- 'Status' = ''
- 'Notes' = ''
- }
- $Script:AllResourceTypesOrdered += $tmp
- }
- }
- }
-
- function Invoke-AdvisoryExtraction {
- Param($Subid, $ResourceGroup)
- if (![string]::IsNullOrEmpty($ResourceGroup)) {
- $advquery = "advisorresources | where type == 'microsoft.advisor/recommendations' and tostring(properties.category) in ('HighAvailability') | where resourceGroup =~ '$ResourceGroup' | order by id"
- $queryResults = Get-AllAzGraphResource -Query $advquery -subscriptionId $Subid
- } else {
- $advquery = "advisorresources | where type == 'microsoft.advisor/recommendations' and tostring(properties.category) in ('HighAvailability') | order by id"
- $queryResults = Get-AllAzGraphResource -Query $advquery -subscriptionId $Subid
- }
-
- $loopAdvisories = foreach ($row in $queryResults) {
- if (![string]::IsNullOrEmpty($row.properties.resourceMetadata.resourceId)) {
- $TempResource = ''
- $TempResource = Invoke-FilterResourceID -ResourceID $row.properties.resourceMetadata.resourceId -List $Script:PreInScopeResources
- $result = [PSCustomObject]@{
- recommendationId = [string]$row.properties.recommendationTypeId
- type = [string]$row.Properties.impactedField
- name = [string]$row.properties.impactedValue
- id = [string]$row.properties.resourceMetadata.resourceId
- subscriptionId = [string]$TempResource.subscriptionId
- resourceGroup = [string]$TempResource.resourceGroup
- location = [string]$TempResource.location
- category = [string]$row.properties.category
- impact = [string]$row.properties.impact
- description = [string]$row.properties.shortDescription.solution
- }
- $result
- }
- }
- $Script:AllAdvisories += $loopAdvisories
- }
-
- function Resolve-SupportTicket {
- $Tickets = $Script:SupportTickets
- $Script:SupportTickets = @()
- $Script:SupportTickets = foreach ($Ticket in $Tickets) {
- $tmp = @{
- 'Ticket ID' = [string]$Ticket.properties.supportTicketId;
- 'Severity' = [string]$Ticket.properties.severity;
- 'Status' = [string]$Ticket.properties.status;
- 'Support Plan Type' = [string]$Ticket.properties.supportPlanType;
- 'Creation Date' = [string]$Ticket.properties.createdDate;
- 'Modified Date' = [string]$Ticket.properties.modifiedDate;
- 'Title' = [string]$Ticket.properties.title;
- 'Related Resource' = [string]$Ticket.properties.technicalTicketDetails.resourceId
- }
- $tmp
- }
- }
-
- function Invoke-RetirementExtraction {
- param($Subid)
-
- $retquery = "servicehealthresources | where properties.EventSubType contains 'Retirement' | order by id"
- $queryResults = Get-AllAzGraphResource -Query $retquery -subscriptionId $Subid
-
- $theseRetirements = foreach ($row in $queryResults) {
- $OutagesRetired = $Script:RetiredOutages | Where-Object { $_.name -eq $row.properties.TrackingId }
-
- $result = [PSCustomObject]@{
- Subscription = [string]$Subid
- TrackingId = [string]$row.properties.TrackingId
- Status = [string]$row.Properties.Status
- LastUpdateTime = [string]$OutagesRetired.properties.lastUpdateTime
- Endtime = [string]$OutagesRetired.properties.impactMitigationTime
- Level = [string]$row.properties.Level
- Title = [string]$row.properties.Title
- Summary = [string]$row.properties.Summary
- Header = [string]$row.properties.Header
- ImpactedService = [string]$row.properties.Impact.ImpactedService
- Description = [string]$OutagesRetired.properties.description
- }
- $result
- }
- $Script:AllRetirements += $theseRetirements
- }
-
- function Invoke-ServiceHealthExtraction {
- param($Subid)
-
- $Servicequery = "resources | where type == 'microsoft.insights/activitylogalerts' | order by id"
- $queryResults = Get-AllAzGraphResource -Query $Servicequery -subscriptionId $Subid
-
- $Rowler = @()
- $Rowler = foreach ($row in $queryResults) {
- foreach ($type in $row.properties.condition.allOf) {
- if ($type.equals -eq 'ServiceHealth') {
- $row
- }
- }
- }
-
- $theseServiceHealth = foreach ($Row in $Rowler) {
- $SubName = ($SubIds | Where-Object { $_.Id -eq ($Row.properties.scopes.split('/')[2]) }).Name
- $EventType = if ($Row.Properties.condition.allOf.anyOf | Select-Object -Property equals) { $Row.Properties.condition.allOf.anyOf | Select-Object -Property equals | ForEach-Object { switch ($_.equals) { 'Incident' { 'Service Issues' } 'Informational' { 'Health Advisories' } 'ActionRequired' { 'Security Advisory' } 'Maintenance' { 'Planned Maintenance' } } } } Else { 'All' }
- $Services = if ($Row.Properties.condition.allOf | Where-Object { $_.field -eq 'properties.impactedServices[*].ServiceName' }) { $Row.Properties.condition.allOf | Where-Object { $_.field -eq 'properties.impactedServices[*].ServiceName' } | Select-Object -Property containsAny | ForEach-Object { $_.containsAny } } Else { 'All' }
- $Regions = if ($Row.Properties.condition.allOf | Where-Object { $_.field -eq 'properties.impactedServices[*].ImpactedRegions[*].RegionName' }) { $Row.Properties.condition.allOf | Where-Object { $_.field -eq 'properties.impactedServices[*].ImpactedRegions[*].RegionName' } | Select-Object -Property containsAny | ForEach-Object { $_.containsAny } } Else { 'All' }
- $ActionGroupName = if ($Row.Properties.actions.actionGroups.actionGroupId) { $Row.Properties.actions.actionGroups.actionGroupId.split('/')[8] } else { '' }
-
- $result = [PSCustomObject]@{
- Name = [string]$row.name
- Subscription = [string]$SubName
- Enabled = [string]$Row.properties.enabled
- EventType = $EventType
- Services = $Services
- Regions = $Regions
- ActionGroup = $ActionGroupName
- }
- $result
- }
- $Script:AllServiceHealth += $theseServiceHealth
- }
-
- function New-JsonFile {
- [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')]
- param()
-
- if ($PSCmdlet.ShouldProcess('')) {
- Write-Host $ResourceGroups -ForegroundColor Yellow
-
- $ResourceExporter = @{
- ImpactedResources = $Script:ImpactedResources
- }
- $OutOfScopeExporter = @{
- OutOfScope = $Script:OutOfScope
- }
- $ResourceTypeExporter = @{
- ResourceType = $Script:AllResourceTypesOrdered
- }
- $AdvisoryExporter = @{
- # Filter out advisories that are duplicated and have no subscription, resource group, or location.
- Advisory = $Script:Advisories.where({ !([String]::IsNullOrEmpty($_.SubscriptionId) -and [String]::IsNullOrEmpty($_.ResourceGroup) -and [String]::IsNullOrEmpty($_.Location)) }) | Select-Object -Property * -Unique
- }
- $OutageExporter = @{
- Outages = $Script:Outageslist
- }
- $RetirementExporter = @{
- Retirements = $Script:AllRetirements
- }
- $SupportExporter = @{
- SupportTickets = $Script:SupportTickets
- }
- $ServiceHealthExporter = @{
- ServiceHealth = $Script:AllServiceHealth
- }
- $ScriptDetailsExporter = @{
- ScriptDetails = $Script:ScriptData
- }
- if ($Debugging.IsPresent) {
- $InScopeExporter = @{
- InScopeResources = $Script:InScope
- }
- $PreInScopeExporter = @{
- InScopeBeforeTagFiltering = $Script:PreInScopeResources
- }
- $TaggedResourceExporter = @{
- TaggedResourcesFilter = $Script:TaggedResources
- }
- $ImpactedResourcesBeforeFilteringExporter = @{
- ImpactedResourcesBeforeFiltering = $Script:results
- }
- }
-
-
- $ExporterArray = @()
- $ExporterArray += $ResourceExporter
- $ExporterArray += $ResourceTypeExporter
- $ExporterArray += $AdvisoryExporter
- $ExporterArray += $OutageExporter
- $ExporterArray += $RetirementExporter
- $ExporterArray += $SupportExporter
- $ExporterArray += $ServiceHealthExporter
- $ExporterArray += $ScriptDetailsExporter
- $ExporterArray += $OutOfScopeExporter
- if ($Debugging.IsPresent) {
- $ExporterArray += $InScopeExporter
- $ExporterArray += $PreInScopeExporter
- $ExporterArray += $TaggedResourceExporter
- $ExporterArray += $ImpactedResourcesBeforeFilteringExporter
- }
-
- $Script:JsonFile = ($PSScriptRoot + '\WARA-File-' + (Get-Date -Format 'yyyy-MM-dd-HH-mm') + '.json')
-
- $ExporterArray | ConvertTo-Json -Depth 15 | Out-File $Script:JsonFile
- }
- }
-
- function Get-WAFObjectByList {
- param (
- [Parameter(Mandatory = $true)]
- [array]$ObjectList,
-
- [Parameter(Mandatory = $true)]
- [array]$FilterList
- )
-
-
-
- $matchingObjects = foreach ($obj in $ObjectList) {
- if ($obj -in $FilterList) {
- $obj
- }
- }
-
- return $matchingObjects
- }
-
- function Get-OtherRecommendations() {
-
- $Token = Get-AzAccessToken -AsSecureString -WarningAction SilentlyContinue
-
- $token = 'Bearer ' + ($Token.Token | ConvertFrom-SecureString -AsPlainText)
- $authHeaders = @{
- 'Authorization' = $token
- }
-
- $APRL_recommendationTypeID = $recommendationobject.recommendationTypeId | Where-Object { ![String]::IsNullOrEmpty($_) }
-
- $uri2 = 'https://management.azure.com/providers/Microsoft.Advisor/metadata?api-version=2023-01-01'
- $r = Invoke-WebRequest -Uri $uri2 -Method Get -Headers $authHeaders
-
- $advmetadata = $r.content | ConvertFrom-Json -Depth 100
- $nonadvmeta = $advmetadata.value.properties[0].supportedvalues | Where-Object { $_.recommendationCategory -ne 'HighAvailability' }
-
- $Advisor_ID = $nonadvmeta.id
-
- $RecommendationsThatAreInAdvisorAndAprlButAreNotHighAvailability = (Get-WAFObjectByList -ObjectList $APRL_recommendationTypeID -FilterList $Advisor_ID) -join "','"
-
-
- $AdvisorQueryForRecommendationsThatAreInAdvisorAndAprlButAreNotHighAvailability = `
- "advisorresources
-| where type == 'microsoft.advisor/recommendations'
-| where properties.recommendationTypeId in ('$RecommendationsThatAreInAdvisorAndAprlButAreNotHighAvailability')
-| extend resId = tolower(tostring(properties.resourceMetadata.resourceId))
-| join kind=leftouter (resources
-| project ['resId']=tolower(id), subscriptionId, resourceGroup ,location) on resId
-| project recommendationId = properties.recommendationTypeId, type = tolower(properties.impactedField), name = properties.impactedValue, id = resId1, subscriptionId = subscriptionId1,resourceGroup = resourceGroup, location = location1, category = properties.category, impact = properties.impact, description = properties.shortDescription.solution
-| order by ['id']"
-
- $tempids = $Script:ImplicitSubscriptionIds -replace '/subscriptions/', ''
-
- $return = Get-AllAzGraphResource -Query $AdvisorQueryForRecommendationsThatAreInAdvisorAndAprlButAreNotHighAvailability -subscriptionId $tempids
-
- $Script:AllAdvisories += $return
- }
-
- function Get-GlobalAdvisorRecommendations()
- {
- $q = "advisorresources
- | where type == 'microsoft.advisor/recommendations'
- | where properties.category =~ 'HighAvailability'
- | where properties.impactedField =~ 'microsoft.subscriptions/subscriptions'
- | project recommendationId = properties.recommendationTypeId, type = 'microsoft.subscription/subscriptions', name = properties.impactedValue, id = strcat('/subscriptions/',subscriptionId), subscriptionId ,resourceGroup = 'N/A', location = 'Global', category = properties.category, impact = properties.impact, description = properties.shortDescription.solution"
-
- $tempids = $Script:ImplicitSubscriptionIds -replace '/subscriptions/', ''
-
- $return = Get-AllAzGraphResource -Query $q -subscriptionId $tempids
-
- if(![String]::IsNullOrEmpty($return)){
-
- $tmp = [PSCustomObject]@{
- 'Resource Type' = 'microsoft.subscription/subscriptions'
- 'Number of Resources' = $return.Count
- 'Available in APRL/ADVISOR?' = 'Yes'
- 'Assessment Owner' = ''
- 'Status' = ''
- 'Notes' = ''
- }
-
- $Script:AllResourceTypesOrdered += $tmp
- }
-
-
-
-
- $Script:Advisories += $return
- }
-
-
- #Call the functions
- $Script:Version = '2.1.19'
- Write-Host 'Version: ' -NoNewline
- Write-Host $Script:Version -ForegroundColor DarkBlue
-
- Write-Debug 'Checking parameters...'
-
- if (!(Test-ScriptParameters)) {
- Write-Host 'Invalid parameters. Exiting...' -ForegroundColor Red
- Exit
- }
-
-
-
- if ($ConfigFile) {
- $Scopes=@()
- $ConfigData = Import-ConfigFileData -file $ConfigFile
- $TenantID = $ConfigData.TenantID | Select-Object -First 1
- $Scopes += foreach ($SubscriptionId in $ConfigData.subscriptionids) {
- if ((Test-SubscriptionId $SubscriptionId)) {
- $SubscriptionId
- } else {
- Write-Host 'Invalid Subscription parameters. Exiting...' -ForegroundColor Red
- Exit
- }
- }
- $Scopes += foreach ($resourcegroup in $ConfigData.resourcegroups) {
- if ((Test-ResourceGroupId $resourcegroup)) {
- $resourcegroup
- } else {
- Write-Host 'Invalid ResourceGroup parameters. Exiting...' -ForegroundColor Red
- Exit
- }
- }
- $Scopes += $ConfigData.resources
- $locations = $ConfigData.locations
- $RunbookFile = $ConfigData.RunbookFile
- if ($ConfigData.Tags) {
- $Tags = foreach ($tag in $ConfigData.Tags) {
- if ((Test-TagPattern $tag)) {
- $tag
- } else {
- Write-Host 'Invalid Tag parameters. Exiting...' -ForegroundColor Red
- Exit
- }
- }
- }
- } else {
- $Scopes = @()
- if ($SubscriptionIds) {
- $Scopes += foreach ($Sub in $SubscriptionIds) {
- $_guid = [Guid]::NewGuid()
-
- if ([Guid]::TryParse($Sub, [ref]$_guid)) {
- $SubId = "/subscriptions/$Sub"
- Write-Host "[-SubscriptionIds]: Fixed '$Sub' >> '$SubId'" -ForegroundColor Yellow
- "/subscriptions/$Sub" # Fixed!
- } else {
- Write-Host "[-SubscriptionIds]: $Sub" -ForegroundColor Cyan
- $Sub
- }
- }
- }
- if ($ResourceGroups) {
- $Scopes += foreach ($RG in $ResourceGroups) {
- Write-Host "[-ResourceGroups]: $RG" -ForegroundColor Cyan
- $RG
- }
- }
- }
-
- $scopes = $scopes | Where-Object {$_ -and $_.trim()}
- $Script:ImplicitSubscriptionIds = ($scopes | ForEach-Object {$_.split("/")[0..2] -join "/"} | Group-Object | Select-Object Name).Name
-
- Write-Debug 'Reseting Variables'
- Invoke-ResetVariable
-
- Write-Debug 'Calling Function: Test-Requirements'
- Test-Requirement
-
- Write-Debug 'Calling Function: Set-LocalFiles'
- Set-LocalFile
-
- Write-Debug 'Building Recommendation Object'
- $Script:RecommendationObject = Invoke-RestMethod 'https://raw.githubusercontent.com/Azure/Azure-Proactive-Resiliency-Library-v2/refs/heads/main/tools/data/recommendations.json'
-
- Write-Debug 'Calling Function: Test-Runbook'
- Test-Runbook
-
- Write-Debug 'Calling Function: Connect-ToAzure'
- Connect-ToAzure -TenantID $TenantID -AzureEnvironment $AzureEnvironment
-
- Write-Debug 'Calling Function: Start-ScopesLoop'
- Start-ScopesLoop
-
- Write-Debug 'Calling Function: Get-OtherRecommendations'
- Get-OtherRecommendations
-
- Write-Debug 'Calling Function: Invoke-ResourcesFiltering'
- Invoke-ResourceFiltering
-
- Write-Debug 'Calling Function: Get-GLobalAdvisorRecommendations'
- Get-GlobalAdvisorRecommendations
-
- Write-Debug 'Calling Function: Resolve-ResourceTypes'
- Resolve-ResourceType
-
- Write-Debug 'Calling Function: Resolve-SupportTickets'
- Resolve-SupportTicket
-
- Write-Debug 'Calling Function: New-JsonFile'
- New-JsonFile
-
-}
-
-$TotalTime = $Script:Runtime.Totalminutes.ToString('#######.##')
-
-Write-Host '---------------------------------------------------------------------'
-Write-Host ('Execution Complete. Total Runtime was: ') -NoNewline
-Write-Host $TotalTime -NoNewline -ForegroundColor Cyan
-Write-Host (' Minutes')
-Write-Host 'Result File: ' -NoNewline
-Write-Host $Script:JsonFile -ForegroundColor Blue
-Write-Host '---------------------------------------------------------------------'
diff --git a/tools/2_wara_data_analyzer.ps1 b/tools/2_wara_data_analyzer.ps1
deleted file mode 100644
index 382cd7dc1..000000000
--- a/tools/2_wara_data_analyzer.ps1
+++ /dev/null
@@ -1,1101 +0,0 @@
-#Requires -Version 7
-
-<#
-.SYNOPSIS
-Well-Architected Reliability Assessment Script
-
-.DESCRIPTION
-The script "2_wara_data_analyzer" will process the JSON file created by the "1_wara_collector" script and will create the core WARA Action Plan Excel file.
-
-.PARAMETER Debugging
-Switch to enable debugging mode.
-
-.PARAMETER Help
-Switch to display help information.
-
-.PARAMETER RepoUrl
-Specifies the git repository URL that contains APRL contents if you want to use custom APRL repository.
-
-.PARAMETER JSONFile
-Path to the JSON file created by the "1_wara_collector" script.
-
-.EXAMPLE
-.\2_wara_data_analyzer.ps1 -JSONFile 'C:\Temp\WARA_File_2024-04-01_10_01.json' -Debugging
-
-.LINK
-https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2
-#>
-
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'False positive as Write-Host does not represent a security risk and this script will always run on host consoles')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'False positive as parameters are not always required')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments','', Justification='Variable is reserved for future use')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars','', Justification='This will be fixed in refactor')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','', Justification='This will be fixed in refactor')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions','', Justification='This will be fixed in refactor')]
-
-Param(
- [switch]$Debugging,
- [switch]$Help,
- [string]$CustomRecommendationsYAMLPath,
-
- [ValidatePattern('^https:\/\/.+$')]
- [string]$RepoUrl = 'https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2',
-
- [Parameter(mandatory = $true)]
- [string] $JSONFile)
-
-# Checking the operating system running this script.
-if (-not $IsWindows) {
- Write-Host 'This script only supports Windows operating systems currently. Please try to run with Windows operating systems.'
- Exit
-}
-
-if ($Debugging.IsPresent) { $DebugPreference = 'Continue' } else { $DebugPreference = 'silentlycontinue' }
-
-$Script:FilterRecommendations = $true
-
-$Script:Runtime = Measure-Command -Expression {
-
- function Get-HelpMessage {
- Write-Host ''
- Write-Host 'Parameters'
- Write-Host ''
- Write-Host " -JSONFile : Mandatory; WARA JSON file generated by '1_wara_collector.ps1' script. "
- Write-Host ' -Debugging : Switch; Writes Debugging information of the script during the execution. '
- Write-Host " -CustomRecommendationsYAMLPath : Optional; Path to a custom YAML file with recommendations. "
- Write-Host ' -RepoUrl : Optional; Specifies the git repository URL that contains APRL contents if you want to use non-standard APRL repository.'
- Write-Host ''
- Write-Host 'Examples: '
- Write-Host ' Run using JSON file'
- Write-Host " .\2_wara_analyzer.ps1 -JSONFile 'C:\Temp\WARA_File_2024-04-01_10_01.json'"
- Write-Host ''
- Write-Host ' Run using JSON file with Debugging details'
- Write-Host " .\2_wara_analyzer.ps1 -JSONFile 'C:\Temp\WARA_File_2024-04-01_10_01.json' -Debugging"
- Write-Host ''
- Write-Host ''
- }
-
- function Test-Requirement {
- # Install required modules
- Write-Host 'Validating ' -NoNewline
- Write-Host 'ImportExcel' -ForegroundColor Cyan -NoNewline
- Write-Host ' Module..'
- $ImportExcel = Get-Module -Name ImportExcel -ListAvailable -ErrorAction silentlycontinue
- if ($null -eq $ImportExcel) {
- Write-Host 'Installing ImportExcel Module' -ForegroundColor Yellow
- Install-Module -Name ImportExcel -Force -SkipPublisherCheck
- }
- Write-Host 'Validating ' -NoNewline
- Write-Host 'Powershell-YAML' -ForegroundColor Cyan -NoNewline
- Write-Host ' Module..'
- $AzModules = Get-Module -Name powershell-yaml -ListAvailable -ErrorAction silentlycontinue
- if ($null -eq $AzModules) {
- Write-Host 'Installing Az Modules' -ForegroundColor Yellow
- Install-Module -Name powershell-yaml -SkipPublisherCheck -InformationAction SilentlyContinue
- }
- Write-Host 'Validating ' -NoNewline
- Write-Host 'Git' -ForegroundColor Cyan -NoNewline
- Write-Host ' Installation..'
- $GitVersion = git --version
- if ($null -eq $GitVersion) {
- Write-Host 'Missing Git' -ForegroundColor Red
- Exit
- }
- }
-
- function Get-RepoVersion {
- param(
- [Parameter(Mandatory = $true)]
- [string] $ClonePath
- )
-
- return Get-Content -Path "$ClonePath\tools\Version.json" -ErrorAction SilentlyContinue | ConvertFrom-Json
- }
-
- function Set-RecommendationControl {
- param (
- [string]$category
- )
-
- switch ($category) {
- 'BusinessContinuity' { return 'Business Continuity' }
- 'DisasterRecovery' { return 'Disaster Recovery' }
- 'MonitoringAndAlerting' { return 'Monitoring And Alerting' }
- 'ServiceUpgradeAndRetirement' { return 'Service Upgrade And Retirement' }
- 'OtherBestPractices' { return 'Other Best Practices' }
- 'HighAvailability' { return 'High Availability' }
- default { return $category }
- }
- }
-
-
- function Set-LocalFile {
- [CmdletBinding(SupportsShouldProcess, ConfirmImpact = 'Low')]
- param()
-
- if ($PSCmdlet.ShouldProcess('')) {
- # Clone the GitHub repository to a temporary folder
-
- # Define script path as the default path to save files
- $workingFolderPath = $PSScriptRoot
- Set-Location -Path $workingFolderPath;
- $Script:clonePath = "$workingFolderPath\Azure-Proactive-Resiliency-Library-v2"
- Write-Debug 'Checking default folder'
- if ((Get-ChildItem -Path $Script:clonePath -Force | Measure-Object).Count -gt 0) {
- Write-Debug 'APRL Folder does exist. Reseting it...'
- Get-Item -Path $Script:clonePath | Remove-Item -Recurse -Force
- git clone $RepoUrl $Script:clonePath --quiet
- } else {
- git clone $RepoUrl $Script:clonePath --quiet
- }
- Write-Debug 'Checking the version of the script'
- $RepoVersion = Get-RepoVersion -ClonePath $Script:clonePath
- if ($Script:Version -ne $RepoVersion.Analyzer) {
- Write-Host 'This version of the script is outdated. ' -BackgroundColor DarkRed
- Write-Host 'Please use a more recent version of the script.' -BackgroundColor DarkRed
- } else {
- Write-Host 'This version of the script is current version. ' -BackgroundColor DarkGreen
- }
- }
- }
-
- function Convert-JSON {
- Write-Host 'Processing JSON File'
-
- # Load the JSON file from the collector script...
- $JSONFile = Get-Item -Path $JSONFile
- $JSONFile = $JSONFile.FullName
- $results = Get-Content -Path $JSONFile | ConvertFrom-Json
-
- $Script:AllResourceTypesOrdered = $results.ResourceType
- $Script:Outages = $results.Outages
- $Script:SupportTickets = $results.SupportTickets
- $Script:Retirements = $results.Retirements
- $Script:ServiceHealth = $results.ServiceHealth
- $Script:CollectorDetails = $results.ScriptDetails
- $Script:OutOfScope = $results.OutOfScope
-
- $RepoVersion = $RepoVersion = Get-RepoVersion -ClonePath $Script:clonePath
-
- if ($Script:CollectorDetails.Version -eq $RepoVersion.Collector) {
- Write-Host 'The JSON file was created by the current version of the Collector Script. ' -BackgroundColor DarkGreen
- } else {
- Write-Host "The JSON file was created by an outdated version ($($Script:CollectorDetails.Version)) of the Collector Script. The latest version is $($RepoVersion.Collector)" -BackgroundColor DarkRed
- }
-
- $CoreResources = $results.ImpactedResources
- $CoreAdvisories = $results.Advisory
-
- $Script:ServicesYAML = Get-ChildItem -Path ($Script:clonePath + '\azure-resources') -Filter 'recommendations.yaml' -Recurse
- $Script:WAFYAML = Get-ChildItem -Path ($Script:clonePath + '\azure-waf') -Filter 'recommendations.yaml' -Recurse
-
- if ($Script:CollectorDetails.SAP -eq 'True') {
- $Script:ServicesYAML += Get-ChildItem -Path ($Script:clonePath + '\azure-specialized-workloads\sap') -Filter 'recommendations.yaml' -Recurse
- }
- if ($Script:CollectorDetails.AVD -eq 'True') {
- $Script:ServicesYAML += Get-ChildItem -Path ($Script:clonePath + '\azure-specialized-workloads\avd') -Filter 'recommendations.yaml' -Recurse
- }
- if ($Script:CollectorDetails.AVS -eq 'True') {
- $Script:ServicesYAML += Get-ChildItem -Path ($Script:clonePath + '\azure-specialized-workloads\avs') -Filter 'recommendations.yaml' -Recurse
- }
- if ($Script:CollectorDetails.HPC -eq 'HPC') {
- $Script:ServicesYAML += Get-ChildItem -Path ($Script:clonePath + '\azure-specialized-workloads\hpc') -Filter 'recommendations.yaml' -Recurse
- }
-
- $Script:AdvisorContent = $CoreAdvisories | Select-Object -Property recommendationId, type, category, impact, description -Unique
-
- # Load custom YAML content if provided...
- # Custom YAML variable is always here regardless of whether a custom file is provided.
- $Script:CustomYAMLContent = @()
-
- # If a custom file is provided, load it and add it to the custom YAML content.
- if (![string]::IsNullOrWhiteSpace(($CustomRecommendationsYAMLPath))) {
- $Script:CustomYAMLContent = Get-Content -Path $CustomRecommendationsYAMLPath | ConvertFrom-Yaml
- }
-
- $Script:ServicesYAMLContent = @()
- foreach ($YAML in $Script:ServicesYAML) {
- if (![string]::IsNullOrEmpty($YAML)) {
- $Script:ServicesYAMLContent += Get-Content -Path $YAML | ConvertFrom-Yaml
- }
- }
- $Script:WAFYAMLContent = @()
- foreach ($YAML in $Script:WAFYAML) {
- if (![string]::IsNullOrEmpty($YAML)) {
- $Script:WAFYAMLContent += Get-Content -Path $YAML | ConvertFrom-Yaml
- }
- }
-
- $Script:MergedRecommendation = @()
-
- foreach ($Recom in $CoreResources | Where-Object { $_ -ne $null }) {
- if ($($Recom.checkName) -and $($Recom.selector)) {
- # This is a runbook recommendation...
- $recomContent = $Script:CustomYAMLContent `
- | Where-Object { ($_.aprlGuid -eq $Recom.recommendationId) -and ($_.checkName -eq $Recom.checkName) } `
- | Select-Object -First 1
-
- if (-not $recomContent) {
- # If we couldn't find a check-specific recommendation, try to find a generic one...
- $recomContent = $Script:CustomYAMLContent `
- | Where-Object { ($_.aprlGuid -eq $Recom.recommendationId) } `
- | Select-Object -First 1
- }
-
- if (-not $recomContent) {
- # If we couldn't find a check-specific recommendation, try to find a generic one...
- $recomContent = $Script:ServicesYAMLContent `
- | Where-Object { ($_.aprlGuid -eq $Recom.recommendationId) } `
- | Select-Object -First 1
- }
-
- if (-not $recomContent) {
- # If we still couldn't find a recommendation, create a default one..
- $recomContent = [pscustomobject]@{
- description = [string]::Empty
- recommendationResourceType = 'Unknown'
- recommendationImpact = 'Unknown'
- }
- }
-
- $tmp = @{
- 'How was the resource/recommendation validated or what actions need to be taken?' = $Recom.validationAction;
- recommendationId = $Recom.recommendationId;
- recommendationTitle = $recomContent.description;
- resourceType = $recomContent.recommendationResourceType;
- impact = $recomContent.recommendationImpact;
- subscriptionId = $Recom.subscriptionId;
- resourceGroup = $Recom.resourceGroup;
- name = $Recom.name;
- id = $Recom.id;
- location = $Recom.location;
- param1 = $Recom.param1;
- param2 = $Recom.param2;
- param3 = $Recom.param3;
- param4 = $Recom.param4;
- param5 = $Recom.param5;
- supportTicketId = [string]::Empty;
- source = $Recom.selector;
- checkName = $Recom.checkName;
- 'WAF Pillar' = 'Reliability';
- tagged = $Recom.tagged
- }
-
- $Script:MergedRecommendation += $tmp
-
- } else {
- # This isn't a runbook recommendation...
- # Getting the recommendation details from the YAML file...
- $RecomTitle = $Script:ServicesYAMLContent | Where-Object { $_.aprlGuid -eq $Recom.recommendationId }
-
- # Filtering recommendations not superceded or present in Advisor...
- if ([string]::IsNullOrEmpty($RecomTitle.recommendationTypeId) -or (![string]::IsNullOrEmpty($RecomTitle.recommendationTypeId) -and $RecomTitle.recommendationTypeId -notin $CoreAdvisories.recommendationId)) {
- # Getting tickets related to the Impacted resource...
- $Ticket = $Script:SupportTickets | Where-Object { $_.'Related Resource' -eq $Recom.id }
- # Filtering only active recommendations...
- if ($RecomTitle.recommendationMetadataState -eq 'Active'){
- # Filtering only recommendations, generic resource types without recommendations will be populated next
- if ( $Recom.validationAction -ne 'IMPORTANT - Resource Type is not available in either APRL or Advisor - Validate Resources manually if Applicable, if not Delete this line') {
- $Tickets = if ($Ticket.'Ticket ID'.count -gt 1) { $Ticket.'Ticket ID' | ForEach-Object { $_ + ' /' } }else { $Ticket.'Ticket ID' }
- $Tickets = [string]$Tickets
- $Tickets = if ($Tickets -like '* /*') { $Tickets -replace '.$' }else { $Tickets }
- $tmp = @{
- 'How was the resource/recommendation validated or what actions need to be taken?' = $Recom.validationAction;
- recommendationId = $Recom.recommendationId;
- recommendationTitle = $RecomTitle.description;
- resourceType = $RecomTitle.recommendationResourceType;
- impact = $RecomTitle.recommendationImpact;
- subscriptionId = $Recom.subscriptionId;
- resourceGroup = $Recom.resourceGroup;
- name = $Recom.name;
- id = $Recom.id;
- location = $Recom.location;
- param1 = $Recom.param1;
- param2 = $Recom.param2;
- param3 = $Recom.param3;
- param4 = $Recom.param4;
- param5 = $Recom.param5;
- supportTicketId = $Tickets;
- source = $Recom.selector;
- checkName = $Recom.checkName;
- 'WAF Pillar' = 'Reliability';
- tagged = $Recom.tagged
- }
- $Script:MergedRecommendation += $tmp
- }
- }
- # Populating resource types without recommendations
- if ( $Recom.validationAction -eq 'IMPORTANT - Resource Type is not available in either APRL or Advisor - Validate Resources manually if Applicable, if not Delete this line') {
- $tmp = @{
- 'How was the resource/recommendation validated or what actions need to be taken?' = $Recom.validationAction;
- recommendationId = '';
- recommendationTitle = $RecomTitle.description;
- resourceType = $Recom.recommendationId;
- impact = '';
- subscriptionId = $Recom.subscriptionId;
- resourceGroup = $Recom.resourceGroup;
- name = $Recom.name;
- id = $Recom.id;
- location = $Recom.location;
- param1 = $Recom.param1;
- param2 = $Recom.param2;
- param3 = $Recom.param3;
- param4 = $Recom.param4;
- param5 = $Recom.param5;
- supportTicketId = $Tickets;
- source = $Recom.selector;
- checkName = $Recom.checkName;
- 'WAF Pillar' = 'Reliability';
- tagged = $Recom.tagged
- }
- $Script:MergedRecommendation += $tmp
- }
- }
- }
- }
-
- $Script:RecommendedAdv = @()
- foreach ($adv in $CoreAdvisories) {
- if (![string]::IsNullOrEmpty($adv.recommendationId)) {
- #$APRLADV = $Script:ServicesYAMLContent | Where-Object { $_.recommendationTypeId -eq $adv.recommendationId }
-
- #if ($APRLADV.recommendationTypeId -eq $adv.recommendationId ) {
- $Ticket = $Script:SupportTickets | Where-Object { $_.'Related Resource' -eq $adv.id }
- $Tickets = if ($Ticket.'Ticket ID'.count -gt 1) { $Ticket.'Ticket ID' | ForEach-Object { $_ + ' /' } }else { $Ticket.'Ticket ID' }
- $Tickets = [string]$Tickets
- $Tickets = if ($Tickets -like '* /*') { $Tickets -replace '.$' }else { $Tickets }
- $WAFPillar = if ($adv.category -eq 'HighAvailability') { 'Reliability' }else { $adv.category }
- $tmp = @{
- 'How was the resource/recommendation validated or what actions need to be taken?' = 'Advisor - Queries';
- recommendationId = $adv.recommendationId;
- recommendationTitle = $adv.description;
- impact = $adv.impact;
- resourceType = $adv.type;
- subscriptionId = $adv.subscriptionId;
- resourceGroup = $adv.resourceGroup;
- name = $adv.name;
- id = $adv.id;
- location = $adv.location;
- param1 = '';
- param2 = '';
- param3 = '';
- param4 = '';
- param5 = '';
- supportTicketId = $Tickets;
- source = 'ADVISOR';
- checkName = '';
- 'WAF Pillar' = $WAFPillar;
- tagged = $true
- }
- $Script:MergedRecommendation += $tmp
- $Script:RecommendedAdv += $adv.recommendationId
- #}
- }
- }
-
- foreach ($WAF in $Script:WAFYAMLContent) {
- $tmp = @{
- 'How was the resource/recommendation validated or what actions need to be taken?' = "IMPORTANT - Update this item based on Discovery Workshop Questionnaire";
- recommendationId = [string]$WAF.aprlGuid;
- recommendationTitle = [string]$WAF.description;
- resourceType = [string]$WAF.recommendationResourceType;
- impact = [string]$WAF.recommendationImpact;
- subscriptionId = '';
- resourceGroup = '';
- name = 'Entire Workload';
- id = '';
- location = '';
- param1 = '';
- param2 = '';
- param3 = '';
- param4 = '';
- param5 = '';
- supportTicketId = '';
- source = 'APRL';
- checkName = ''
- 'WAF Pillar' = 'Reliability';
- tagged = $true
- }
- $Script:MergedRecommendation += $tmp
- }
- }
-
- function Build-ExcelFile {
-
- Write-Host 'Starting Excel file Processing. '
-
- $TableStyle = 'Light19'
- $Script:Recommendations = @()
-
- # Defines the Excel file to be created in the root folder
- $Script:ExcelFile = ($PSScriptRoot + '\WARA Action Plan ' + (Get-Date -Format 'yyyy-MM-dd-HH-mm') + '.xlsx')
-
- function Add-ImpactedResource {
- #################### Creates the first sheet (ImpactedResources)
- $Styles1 = @(
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -Bold -BackgroundColor 'DarkSlateGray' -AutoSize -Range 'A1:S1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -AutoSize -NumberFormat '0' -Range 'A:B'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -Width 100 -WrapText -NumberFormat '0' -Range 'C:C'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -AutoSize -NumberFormat '0' -Range 'D:I'
- New-ExcelStyle -HorizontalAlignment Left -FontName 'Calibri' -FontSize 11 -Width 80 -Range 'J:J'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -AutoSize -NumberFormat '0' -Range 'K:S'
- )
-
- $Styles2 = @(
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -Bold -BackgroundColor 'DarkSlateGray' -AutoSize -Range 'A1:G1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -AutoSize -NumberFormat '0' -Range 'A:F'
- New-ExcelStyle -HorizontalAlignment Left -FontName 'Calibri' -FontSize 11 -Width 80 -Range 'G:G'
- )
-
- $cond = @()
- $cond += New-ConditionalText "IMPORTANT - Update this item based on Discovery Workshop Questionnaire" -Range A:A
- $cond += New-ConditionalText 'IMPORTANT' -Range A:A
-
- $cond2 = @()
- $cond2 += New-ConditionalText 'No Action Required' -Range A:A
-
- $ImpactedResourcesSheet = New-Object System.Collections.Generic.List[System.Object]
- $ImpactedResourcesSheet.Add('How was the resource/recommendation validated or what actions need to be taken?')
- $ImpactedResourcesSheet.Add('resourceType')
- $ImpactedResourcesSheet.Add('recommendationTitle')
- $ImpactedResourcesSheet.Add('recommendationId')
- $ImpactedResourcesSheet.Add('impact')
- $ImpactedResourcesSheet.Add('subscriptionId')
- $ImpactedResourcesSheet.Add('resourceGroup')
- $ImpactedResourcesSheet.Add('location')
- $ImpactedResourcesSheet.Add('name')
- $ImpactedResourcesSheet.Add('id')
- $ImpactedResourcesSheet.Add('param1')
- $ImpactedResourcesSheet.Add('param2')
- $ImpactedResourcesSheet.Add('param3')
- $ImpactedResourcesSheet.Add('param4')
- $ImpactedResourcesSheet.Add('param5')
- $ImpactedResourcesSheet.Add('supportTicketId')
- $ImpactedResourcesSheet.Add('source')
- $ImpactedResourcesSheet.Add('WAF Pillar')
- $ImpactedResourcesSheet.Add('checkName')
-
- $OutOfScopeSheet = New-Object System.Collections.Generic.List[System.Object]
- $OutOfScopeSheet.Add('description')
- $OutOfScopeSheet.Add('type')
- $OutOfScopeSheet.Add('subscriptionId')
- $OutOfScopeSheet.Add('resourceGroup')
- $OutOfScopeSheet.Add('name')
- $OutOfScopeSheet.Add('location')
- $OutOfScopeSheet.Add('id')
-
-
- $Script:MergedRecommendation | ForEach-Object { [PSCustomObject]$_ } | Select-Object $ImpactedResourcesSheet |
- Export-Excel -Path $ExcelFile -WorksheetName 'ImpactedResources' -TableName 'Table2' -ConditionalText $cond -AutoSize -TableStyle $TableStyle -Style $Styles1
-
- $Script:OutOfScope | ForEach-Object { [PSCustomObject]$_ } | Select-Object $OutOfScopeSheet |
- Export-Excel -Path $ExcelFile -WorksheetName 'Other-OutOfScope' -TableName 'UnTagTable' -ConditionalText $cond2 -AutoSize -TableStyle $TableStyle -Style $Styles2
- }
-
- function Add-ResourceType {
- #################### Creates the second sheet (ResourceTypes)
- $ResourceTypeSheet = New-Object System.Collections.Generic.List[System.Object]
- $ResourceTypeSheet.Add('Resource Type')
- $ResourceTypeSheet.Add('Number of Resources')
- $ResourceTypeSheet.Add('Available in APRL/ADVISOR?')
- $ResourceTypeSheet.Add('Assessment Owner')
- $ResourceTypeSheet.Add('Status')
- $ResourceTypeSheet.Add('Notes')
-
- $TypeStyle = @(
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -Bold -BackgroundColor 'DarkSlateGray' -AutoSize -Range 'A1:F1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -AutoSize -NumberFormat '0' -Range 'A:F'
- )
-
- $Script:AllResourceTypesOrdered | ForEach-Object { [PSCustomObject]$_ } | Select-Object $ResourceTypeSheet |
- Export-Excel -Path $ExcelFile -WorksheetName 'ResourceTypes' -TableName 'TableTypes' -AutoSize -TableStyle $TableStyle -Style $TypeStyle
-
- }
-
- function Add-Outage {
- #################### Creates the Outages sheet
- $Script:OutagesSheet = @()
- $RealOutages = $Script:Outages | Where-Object { $_.properties.description -like '*How can customers make incidents like this less impactful?*' -and $_.properties.impactStartTime -gt ((Get-Date).AddMonths(-3)) }
- foreach ($Outage in $RealOutages) {
- if (![string]::IsNullOrEmpty($Outage.name)) {
-
- try {
- $HTML = New-Object -Com 'HTMLFile'
- $HTML.write([ref]$Outage.properties.description)
- $OutageDescription = $Html.body.innerText
- $SplitDescription = $OutageDescription.split('How can we make our incident communications more useful?').split('How can customers make incidents like this less impactful?').split('How are we making incidents like this less likely or less impactful?').split('How did we respond?').split('What went wrong and why?').split('What happened?')
- $whathap = ($SplitDescription[1]).Split([Environment]::NewLine)[1]
- $whatwent = ($SplitDescription[2]).Split([Environment]::NewLine)[1]
- $howdid = ($SplitDescription[3]).Split([Environment]::NewLine)[1]
- $howarewe = ($SplitDescription[4]).Split([Environment]::NewLine)[1]
- $howcan = ($SplitDescription[5]).Split([Environment]::NewLine)[1]
- }
- catch {
- $whathap = ""
- $whatwent = ""
- $howdid = ""
- $howarewe = ""
- $howcan = ""
- }
-
- $OutProps = $Outage.properties
- $tmp = @{
- 'Tracking ID' = [string]$Outage.name;
- 'Event Type' = [string]$OutProps.eventType;
- 'Event Source' = [string]$OutProps.eventSource;
- 'Status' = [string]$OutProps.status;
- 'Title' = [string]$OutProps.title;
- 'Level' = [string]$OutProps.level;
- 'Event Level' = [string]$OutProps.eventLevel;
- 'Start Time' = [string]$OutProps.impactStartTime;
- 'Mitigation Time' = [string]$OutProps.impactMitigationTime;
- 'Impacted Service' = [string]$OutProps.impact.impactedService;
- 'What happened' = $whathap;
- 'What went wrong and why' = $whatwent;
- 'How did we respond' = $howdid;
- 'How are we making incidents like this less likely or less impactful' = $howarewe;
- 'How can customers make incidents like this less impactful' = $howcan;
- }
- $Script:OutagesSheet += $tmp
- }
- }
-
-
- $Styles3 = @(
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 14 -Range 'A1:B1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 18 -Range 'C1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 20 -Range 'D1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 55 -Range 'E1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 20 -Range 'F1:I1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 25 -Range 'J1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 80 -Range 'K1:O1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -VerticalAlignment Center -WrapText -Range 'A:O'
- )
-
- # Configure the array of fields to be used in the Recommendations sheet
- $OutagesWorksheet = New-Object System.Collections.Generic.List[System.Object]
- $OutagesWorksheet.Add('Tracking ID')
- $OutagesWorksheet.Add('Event Type')
- $OutagesWorksheet.Add('Event Source')
- $OutagesWorksheet.Add('Status')
- $OutagesWorksheet.Add('Title')
- $OutagesWorksheet.Add('Level')
- $OutagesWorksheet.Add('Event Level')
- $OutagesWorksheet.Add('Start Time')
- $OutagesWorksheet.Add('Mitigation Time')
- $OutagesWorksheet.Add('Impacted Service')
- $OutagesWorksheet.Add('What happened')
- $OutagesWorksheet.Add('What went wrong and why')
- $OutagesWorksheet.Add('How did we respond')
- $OutagesWorksheet.Add('How are we making incidents like this less likely or less impactful')
- $OutagesWorksheet.Add('How can customers make incidents like this less impactful')
-
-
- if (![string]::IsNullOrEmpty($Script:OutagesSheet)) {
- $Script:OutagesSheet | ForEach-Object { [PSCustomObject]$_ } | Select-Object $OutagesWorksheet |
- Export-Excel -Path $ExcelFile -WorksheetName 'Outages' -TableName 'TableOutage' -AutoSize -TableStyle $tableStyle -Style $Styles3
- }
-
- }
-
- function Add-Retirement {
- #################### Creates the Retirement sheet
- $Script:RetirementSheet = @()
- foreach ($Retires in $Script:Retirements) {
- if (![string]::IsNullOrEmpty($Retires)) {
- $HTML = New-Object -Com 'HTMLFile'
- $HTML.write([ref]$Retires.Summary)
- $RetirementSummary = $Html.body.innerText
-
- try {
- $HTML = New-Object -Com 'HTMLFile'
- $HTML.write([ref]$Retires.Description)
- $RetirementDescriptionFull = $Html.body.innerText
- $SplitDescription = $RetirementDescriptionFull.split('Help and support').split('Required action')
- } catch {
- $SplitDescription = ' ', ' '
- }
- $tmp = @{
- 'Subscription' = [string]$Retires.Subscription;
- 'Tracking ID' = [string]$Retires.TrackingId;
- 'Status' = [string]$Retires.Status;
- 'Last Update Time' = [string]$Retires.LastUpdateTime;
- 'End Time' = [string]$Retires.Endtime;
- 'Impacted Service' = [string]$Retires.ImpactedService;
- 'Title' = [string]$Retires.Title;
- 'Summary' = [string]$RetirementSummary;
- 'Required Action' = [string]$SplitDescription[1];
- 'Details' = [string]$SplitDescription[0]
- }
- $Script:RetirementSheet += $tmp
- }
- }
-
- $Styles4 = @(
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 50 -Range 'A1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 25 -Range 'B1:E1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 30 -Range 'F1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 70 -Range 'G1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 80 -Range 'H1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 90 -Range 'I1:J1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -VerticalAlignment Center -WrapText -Range 'A:J'
- )
-
- # Configure the array of fields to be used in the Retirement sheet
- $RetirementWorksheet = New-Object System.Collections.Generic.List[System.Object]
- $RetirementWorksheet.Add('Subscription')
- $RetirementWorksheet.Add('Tracking ID')
- $RetirementWorksheet.Add('Status')
- $RetirementWorksheet.Add('Last Update Time')
- $RetirementWorksheet.Add('End Time')
- $RetirementWorksheet.Add('Impacted Service')
- $RetirementWorksheet.Add('Title')
- $RetirementWorksheet.Add('Summary')
- $RetirementWorksheet.Add('Details')
- $RetirementWorksheet.Add('Required Action')
-
- if (![string]::IsNullOrEmpty($Script:RetirementSheet)) {
- $Script:RetirementSheet | ForEach-Object { [PSCustomObject]$_ } | Select-Object $RetirementWorksheet |
- Export-Excel -Path $ExcelFile -WorksheetName 'Retirements' -TableName 'TableRetires' -AutoSize -TableStyle $tableStyle -Style $Styles4
- }
-
- }
-
- function Add-SupportTicket {
- #################### Creates the Tickets sheet
- $Script:TicketsSheet = @()
- foreach ($Ticket in $Script:SupportTickets) {
- if (![string]::IsNullOrEmpty($Ticket)) {
- $tmp = @{
- 'Ticket ID' = [string]$Ticket.'Ticket ID';
- 'Severity' = [string]$Ticket.'Severity';
- 'Status' = [string]$Ticket.'Status';
- 'Support Plan Type' = [string]$Ticket.'Support Plan Type';
- 'Creation Date' = [string]$Ticket.'Creation Date';
- 'Modified Date' = [string]$Ticket.'Modified Date';
- 'Title' = [string]$Ticket.'Title';
- 'Related Resource' = [string]$Ticket.'Related Resource'
- }
- $Script:TicketsSheet += $tmp
- }
- }
-
- $Styles5 = @(
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 20 -Range 'A1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 15 -Range 'B1:C1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 35 -Range 'D1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 20 -Range 'E1:F1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 50 -Range 'G1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 120 -Range 'H1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -VerticalAlignment Center -WrapText -Range 'A:G'
- )
-
- # Configure the array of fields to be used in the Tickets sheet
- $TicketWorksheet = New-Object System.Collections.Generic.List[System.Object]
- $TicketWorksheet.Add('Ticket ID')
- $TicketWorksheet.Add('Severity')
- $TicketWorksheet.Add('Status')
- $TicketWorksheet.Add('Support Plan Type')
- $TicketWorksheet.Add('Creation Date')
- $TicketWorksheet.Add('Modified Date')
- $TicketWorksheet.Add('Title')
- $TicketWorksheet.Add('Related Resource')
-
- if (![string]::IsNullOrEmpty($Script:TicketsSheet)) {
- $Script:TicketsSheet | ForEach-Object { [PSCustomObject]$_ } | Select-Object $TicketWorksheet |
- Export-Excel -Path $ExcelFile -WorksheetName 'Support Tickets' -TableName 'TableTickets' -AutoSize -TableStyle $tableStyle -Style $Styles5 -NoNumberConversion *
- }
- }
-
- function Add-ServiceHealth {
- #################### Creates the Service Health sheet
- $Script:ServiceHealthSheet = @()
- foreach ($Alert in $Script:ServiceHealth) {
- if (![string]::IsNullOrEmpty($Alert)) {
- $Service = if ($Alert.Services.count -gt 1) { $Alert.Services | ForEach-Object { $_ + ' /' } }else { $Alert.Services }
- $Service = [string]$Service
- $Service = if ($Service -like '* /*') { $Service -replace '.$' }else { $Service }
- $EventT = if ($Alert.EventType.count -gt 1) { $Alert.EventType | ForEach-Object { $_ + ' /' } }else { $Alert.EventType }
- $EventT = [string]$EventT
- $EventT = if ($EventT -like '* /*') { $EventT -replace '.$' }else { $EventT }
- $Region = if ($Alert.Regions.count -gt 1) { $Alert.Regions | ForEach-Object { $_ + ' /' } }else { $Alert.Regions }
- $Region = [string]$Region
- $Region = if ($Region -like '* /*') { $Region -replace '.$' }else { $Region }
- $Action = if ($Alert.ActionGroup.count -gt 1) { $Alert.ActionGroup | ForEach-Object { $_ + ' /' } }else { $Alert.ActionGroup }
- $Action = [string]$Action
- $Action = if ($Action -like '* /*') { $Action -replace '.$' }else { $Action }
- $tmp = @{
- 'Name' = [string]$Alert.Name;
- 'Enabled' = [string]$Alert.Enabled;
- 'Subscription' = [string]$Alert.Subscription;
- 'Services' = $Service;
- 'Event Type' = $EventT;
- 'Regions' = $Region;
- 'Action Group' = $Action
- }
- $Script:ServiceHealthSheet += $tmp
- }
- }
-
- $Styles6 = @(
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 25 -NumberFormat '0' -Range 'A1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 15 -NumberFormat '0' -Range 'B1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -FontColor 'White' -VerticalAlignment Center -Bold -WrapText -BackgroundColor 'DarkSlateGray' -Width 35 -NumberFormat '0' -Range 'C1:G1'
- New-ExcelStyle -HorizontalAlignment Center -FontName 'Calibri' -FontSize 11 -VerticalAlignment Center -WrapText -NumberFormat '0' -Range 'A:G'
- )
-
- # Configure the array of fields to be used in the Tickets sheet
- $ServiceHealthtWorksheet = New-Object System.Collections.Generic.List[System.Object]
- $ServiceHealthtWorksheet.Add('Name')
- $ServiceHealthtWorksheet.Add('Enabled')
- $ServiceHealthtWorksheet.Add('Subscription')
- $ServiceHealthtWorksheet.Add('Services')
- $ServiceHealthtWorksheet.Add('Event Type')
- $ServiceHealthtWorksheet.Add('Regions')
- $ServiceHealthtWorksheet.Add('Action Group')
-
- if (![string]::IsNullOrEmpty($Script:ServiceHealthSheet)) {
- $Script:ServiceHealthSheet | ForEach-Object { [PSCustomObject]$_ } | Select-Object $ServiceHealthtWorksheet |
- Export-Excel -Path $ExcelFile -WorksheetName 'Health Alerts' -TableName 'TableAlerts' -AutoSize -TableStyle $tableStyle -Style $Styles6
- }
- }
-
- function Add-Recommendation {
- #################### Starts to process the main sheet
-
- foreach ($customRec in $Script:CustomYAMLContent) {
- $countFormula = 'COUNTIFS(ImpactedResources!D:D,"' + $customRec.aprlGuid + '",ImpactedResources!S:S,"' + $customRec.checkName + '")'
- $compliantFormula = 'IF((' + $countFormula + ')>0,"No","Yes")'
-
- $ExcelCat = Set-RecommendationControl -category $customRec.recommendationControl
-
- $Script:Recommendations += @{
- 'Implemented?Yes/No' = "=$compliantFormula"
- 'Number of Impacted Resources?' = "=$countFormula"
- 'Azure Service / Well-Architected' = 'Custom'
- 'Recommendation Source' = 'Custom'
- 'Resiliency Category' = $ExcelCat
- 'Azure Service Category / Well-Architected Area' = 'Custom'
- 'Azure Service / Well-Architected Topic' = 'Custom'
- 'Recommendation Title' = [string]$customRec.description
- 'Impact' = [string]$customRec.recommendationImpact
- 'Best Practices Guidance' = [string]$customRec.longDescription
- 'Read More' = [string]$customRec.learnMoreLink.url
- 'Potential Benefits' = [string]$customRec.potentialBenefits
- 'Add associated Outage TrackingID and/or Support Request # and/or Service Retirement TrackingID' = ''
- 'Observation / Annotation' = ''
- 'Recommendation Id' = $customRec.aprlGuid
- }
- }
-
- # Build the APRL Recommendations
- foreach ($Service in $Script:ServicesYAMLContent) {
- if ($Service.recommendationMetadataState -eq 'Active')
- {
- if (($Service.recommendationResourceType -like 'Specialized.Workload/*' -or $Service.recommendationResourceType -eq 'Microsoft.Subscription/Subscriptions' -or $Service.recommendationResourceType -in $Script:AllResourceTypesOrdered.'Resource Type' -or $Script:FilterRecommendations -eq $false) -and ([string]::IsNullOrEmpty($Service.recommendationTypeId) -or (![string]::IsNullOrEmpty($Service.recommendationTypeId) -and $Service.recommendationTypeId -notin $Script:RecommendedAdv))) {
- $ID = $Service.aprlGuid
- $resourceType = $Service.recommendationResourceType
-
- $ExcelCat = Set-RecommendationControl -category $Service.recommendationControl
-
- $tmp = @{
- 'Implemented?Yes/No' = ('=IF((COUNTIF(ImpactedResources!D:D,"' + $ID + '")=0),"Yes","No")');
- 'Number of Impacted Resources?' = ('=COUNTIF(ImpactedResources!D:D,"' + $ID + '")');
- 'Azure Service / Well-Architected' = 'Azure Service';
- 'Recommendation Source' = 'APRL';
- 'Resiliency Category' = $ExcelCat;
- 'Azure Service Category / Well-Architected Area' = if ($resourceType -like 'Specialized.Workload/*') { $resourceType }else { ($resourceType.split('/')[0]) };
- 'Azure Service / Well-Architected Topic' = if ($resourceType -like 'Specialized.Workload/*') { $resourceType }else { ($resourceType.split('/')[1]) };
- 'Recommendation Title' = $Service.description;
- 'Impact' = $Service.recommendationImpact;
- 'Best Practices Guidance' = [string]$Service.longDescription;
- 'Read More' = [string]($Service.learnMoreLink.url -join "`n");
- 'Potential Benefits' = [string]$Service.potentialBenefits;
- 'Add associated Outage TrackingID and/or Support Request # and/or Service Retirement TrackingID' = '';
- 'Observation / Annotation' = '';
- 'Recommendation Id' = [string]$Service.aprlGuid
- }
- $Script:Recommendations += $tmp
- }
- }
- }
-
- # Builds the Advisor recommendations
- foreach ($advisor in $Script:AdvisorContent) {
- if ($advisor.recommendationId -in $Script:RecommendedAdv) {
- $ID = $advisor.recommendationId
- $resourceType = $advisor.type.ToLower()
- $ExcelCat = Set-RecommendationControl -category $advisor.category
-
- $tmp = @{
- 'Implemented?Yes/No' = ('=IF((COUNTIF(ImpactedResources!D:D,"' + $ID + '")=0),"Yes","No")');
- 'Number of Impacted Resources?' = ('=COUNTIF(ImpactedResources!D:D,"' + $ID + '")');
- 'Azure Service / Well-Architected' = 'Azure Service';
- 'Recommendation Source' = 'ADVISOR';
- 'Resiliency Category' = $ExcelCat;
- 'Azure Service Category / Well-Architected Area' = ($resourceType.split('/')[0]);
- 'Azure Service / Well-Architected Topic' = ($resourceType.split('/')[1]);
- 'Recommendation Title' = $advisor.description;
- 'Impact' = $advisor.impact;
- 'Best Practices Guidance' = $advisor.description;
- 'Read More' = '';
- 'Potential Benefits' = '';
- 'Add associated Outage TrackingID and/or Support Request # and/or Service Retirement TrackingID' = '';
- 'Observation / Annotation' = '';
- 'Recommendation Id' = [string]$advisor.recommendationId
- }
- $Script:Recommendations += $tmp
- }
- }
-
- # Builds the WAF recommendations
- foreach ($WAFYAML in $Script:WAFYAMLContent) {
- $resourceType = $WAFYAML.recommendationResourceType
- $ID = $WAFYAML.aprlGuid
-
- $ExcelCat = Set-RecommendationControl -category $WAFYAML.recommendationControl
-
- $tmp = @{
- 'Implemented?Yes/No' = ('=IF((COUNTIF(ImpactedResources!D:D,"' + $ID + '")=0),"Yes","No")');
- 'Number of Impacted Resources?' = ('=COUNTIF(ImpactedResources!D:D,"' + $ID + '")');
- 'Azure Service / Well-Architected' = 'Well Architected';
- 'Recommendation Source' = 'APRL';
- 'Resiliency Category' = $ExcelCat;
- 'Azure Service Category / Well-Architected Area' = ($resourceType.split('/')[0]);
- 'Azure Service / Well-Architected Topic' = ($resourceType.split('/')[1]);
- 'Recommendation Title' = $WAFYAML.description;
- 'Impact' = $WAFYAML.recommendationImpact;
- 'Best Practices Guidance' = [string]$WAFYAML.longDescription;
- 'Read More' = [string]($WAFYAML.learnMoreLink.url -join "`n");
- 'Potential Benefits' = [string]$WAFYAML.potentialBenefits;
- 'Add associated Outage TrackingID and/or Support Request # and/or Service Retirement TrackingID' = '';
- 'Observation / Annotation' = '';
- 'Recommendation Id' = [string]$WAFYAML.aprlGuid
- }
- $Script:Recommendations += $tmp
- }
-
- $columnCommonStyle = @{
- FontName = 'Calibri'
- FontSize = 11
- WrapText = $true
- }
-
- $headerCommonStyle = @{
- FontName = 'Calibri'
- FontSize = 11
- FontColor = 'White'
- Bold = $true
- BackgroundColor = 'DarkSlateGray'
- HorizontalAlignment = 'Center'
- VerticalAlignment = 'Center'
- WrapText = $true
- }
-
- $Styles2 = @(
- # Apply the style to the columns.
- New-ExcelStyle @columnCommonStyle -Range 'A:G' -HorizontalAlignment Center -VerticalAlignment Center
- New-ExcelStyle @columnCommonStyle -Range 'H:H' -HorizontalAlignment Left -VerticalAlignment Center
- New-ExcelStyle @columnCommonStyle -Range 'I:I' -HorizontalAlignment Center -VerticalAlignment Center
- New-ExcelStyle @columnCommonStyle -Range 'J:K' -HorizontalAlignment Left -VerticalAlignment Top
- New-ExcelStyle @columnCommonStyle -Range 'L:L' -HorizontalAlignment Center -VerticalAlignment Center
- New-ExcelStyle @columnCommonStyle -Range 'M:M' -HorizontalAlignment Left -VerticalAlignment Top
- New-ExcelStyle @columnCommonStyle -Range 'N:N' -HorizontalAlignment Center -VerticalAlignment Center
-
- # Apply the style to the header row.
- New-ExcelStyle @headerCommonStyle -Range 'A1:B1' -Width 14
- New-ExcelStyle @headerCommonStyle -Range 'C1' -Width 18
- New-ExcelStyle @headerCommonStyle -Range 'D1' -Width 20
- New-ExcelStyle @headerCommonStyle -Range 'E1:F1' -Width 35
- New-ExcelStyle @headerCommonStyle -Range 'G1' -Width 20
- New-ExcelStyle @headerCommonStyle -Range 'H1' -Width 55
- New-ExcelStyle @headerCommonStyle -Range 'I1' -Width 10
- New-ExcelStyle @headerCommonStyle -Range 'J1' -Width 90
- New-ExcelStyle @headerCommonStyle -Range 'K1' -Width 45
- New-ExcelStyle @headerCommonStyle -Range 'L1:M1' -Width 35
- New-ExcelStyle @headerCommonStyle -Range 'N1' -Width 45
- )
-
- # Configure the array of fields to be used in the Recommendations sheet
- $FinalWorksheet = New-Object System.Collections.Generic.List[System.Object]
- $FinalWorksheet.Add('Implemented?Yes/No')
- $FinalWorksheet.Add('Number of Impacted Resources?')
- $FinalWorksheet.Add('Azure Service / Well-Architected')
- $FinalWorksheet.Add('Recommendation Source')
- $FinalWorksheet.Add('Azure Service Category / Well-Architected Area')
- $FinalWorksheet.Add('Azure Service / Well-Architected Topic')
- $FinalWorksheet.Add('Resiliency Category')
- $FinalWorksheet.Add('Recommendation Title')
- $FinalWorksheet.Add('Impact')
- $FinalWorksheet.Add('Best Practices Guidance')
- $FinalWorksheet.Add('Read More')
- $FinalWorksheet.Add('Add associated Outage TrackingID and/or Support Request # and/or Service Retirement TrackingID')
- $FinalWorksheet.Add('Observation / Annotation')
- $FinalWorksheet.Add('Recommendation Id')
-
- #################### Creates the recommendations sheet in Excel
- $Script:Recommendations | ForEach-Object { [PSCustomObject]$_ } | Select-Object $FinalWorksheet |
- Export-Excel -Path $ExcelFile -WorksheetName 'Recommendations' -TableName 'Table1' -AutoSize -TableStyle $tableStyle -Style $Styles2 -MoveToStart
-
- }
-
- function Build-PivotTable {
- #################### Creates the empty PivotTable sheet to be used later
- '' | Export-Excel -Path $ExcelFile -WorksheetName 'PivotTable'
-
- #################### Creates the Charts sheet and already add the first line with the yellow background
- $StyleOver = New-ExcelStyle -Range A1:G1 -Bold -FontSize 11 -BackgroundColor ([System.Drawing.Color]::Yellow) -Merge -HorizontalAlignment Left
- 'Copy the Charts below to your Word and Powerpoint Documents' | Export-Excel -Path $ExcelFile -WorksheetName 'Charts' -Style $StyleOver
-
- # Open the Excel file to add the Pivot Tables and Charts
- $Excel = Open-ExcelPackage -Path $ExcelFile
-
- $PTParams = @{
- PivotTableName = 'P0'
- Address = $Excel.PivotTable.cells['A3']
- SourceWorkSheet = $Excel.Recommendations
- PivotRows = @('Azure Service / Well-Architected', 'Azure Service / Well-Architected Topic')
- PivotColumns = @('Impact')
- PivotData = @{'Azure Service Category / Well-Architected Area' = 'Count' }
- PivotTableStyle = 'Medium8'
- Activate = $true
- PivotFilter = 'Implemented?Yes/No'
- ShowPercent = $true
- IncludePivotChart = $true
- #ShowCategory = $true
- ChartType = 'BarClustered'
- ChartRow = 80
- ChartColumn = 3
- NoLegend = $false
- ChartTitle = 'Recommendations per Services/Well-Architected Area'
- ChartHeight = 696
- ChartWidth = 450
- }
- Add-PivotTable @PTParams
-
-
- $PTParams = @{
- PivotTableName = 'P1'
- Address = $Excel.PivotTable.cells['H3']
- SourceWorkSheet = $Excel.Recommendations
- PivotRows = @('Resiliency Category')
- PivotColumns = @('Impact')
- PivotData = @{'Resiliency Category' = 'Count' }
- PivotTableStyle = 'Medium9'
- Activate = $true
- PivotFilter = 'Implemented?Yes/No'
- ShowPercent = $true
- IncludePivotChart = $true
- ChartType = 'BarClustered'
- ChartRow = 80
- ChartColumn = 30
- NoLegend = $false
- ChartTitle = 'Recommendations per Resiliency Category'
- ChartHeight = 569
- ChartWidth = 462
- }
- Add-PivotTable @PTParams
-
- Close-ExcelPackage $Excel
- }
-
- function Invoke-ExcelAPI {
- Write-Host 'Opening Excel...'
- $Script:ExcelApplication = New-Object -ComObject Excel.Application
- Start-Sleep 2
- Write-Host 'Customizing Excel Charts. '
- # Open the Excel using the API to move the charts from the PivotTable sheet to the Charts sheet and change chart style, font, etc..
- if ($Script:ExcelApplication) {
- try {
- Write-Debug 'Opening Excel File'
- $Ex = $ExcelApplication.Workbooks.Open($ExcelFile)
- Start-Sleep -Seconds 2
- Write-Debug 'Opening Excel Sheets'
- $WS = $ex.Worksheets | Where-Object { $_.Name -eq 'PivotTable' }
- $WS2 = $ex.Worksheets | Where-Object { $_.Name -eq 'Charts' }
- Write-Debug 'Moving Charts to Chart sheet'
- ($WS.Shapes | Where-Object { $_.name -eq 'ChartP0' }).DrawingObject.Cut()
- $WS2.Paste()
- ($WS.Shapes | Where-Object { $_.name -eq 'ChartP1' }).DrawingObject.Cut()
- $WS2.Paste()
-
- Write-Debug 'Reloading Excel Chart Sheet'
- $WS2 = $ex.Worksheets | Where-Object { $_.Name -eq 'Charts' }
-
- Write-Debug 'Editing ChartP0'
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP0' }).DrawingObject.Chart.ChartStyle = 222
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP0' }).DrawingObject.Chart.ChartArea.Font.Name = 'Segoe UI'
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP0' }).DrawingObject.Chart.ChartArea.Font.Size = 9
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP0' }).DrawingObject.Chart.ChartArea.Left = 18
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP0' }).DrawingObject.Chart.ChartArea.Top = 40
-
- Write-Debug 'Editing ChartP1'
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP1' }).DrawingObject.Chart.ChartStyle = 222
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP1' }).DrawingObject.Chart.ChartArea.Font.Name = 'Segoe UI'
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP1' }).DrawingObject.Chart.ChartArea.Font.Size = 9
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP1' }).DrawingObject.Chart.ChartArea.Left = 555
- ($WS2.Shapes | Where-Object { $_.name -eq 'ChartP1' }).DrawingObject.Chart.ChartArea.Top = 40
-
- Write-Debug 'Editing Pivot Filters'
- $WS.Range('B1').Formula = 'No'
- $WS.Range('I1').Formula = 'No'
-
- Write-Debug 'Saving File'
- $Ex.Save()
- Write-Debug 'Closing Excel Application'
- $Ex.Close()
- $ExcelApplication.Quit()
- # Ensures the Excel process opened by the API is closed
- Write-Debug 'Ensuring Excel Process is Closed.'
- Get-Process -Name 'excel' -ErrorAction Ignore | Where-Object { $_.CommandLine -like '*/automation*' } | Stop-Process
- } catch {
- Write-Host 'Error during the PivotTable + Charts customization' -BackgroundColor DarkRed
- }
- }
-
- }
-
- Add-ImpactedResource
- Add-ResourceType
- Add-Outage
- Add-Retirement
- Add-SupportTicket
- Add-ServiceHealth
- Add-Recommendation
- Build-PivotTable
- Invoke-ExcelAPI
-
- }
-
- #Call the functions
- $Script:Version = '2.1.20'
- Write-Host 'Version: ' -NoNewline
- Write-Host $Script:Version -ForegroundColor DarkBlue
-
- if ($Help.IsPresent) {
- Get-HelpMessage
- Exit
- }
-
- Write-Debug 'Calling Function: Test-Requirement'
- Test-Requirement
-
- Write-Debug 'Calling Function: Set-LocalFile'
- Set-LocalFile
-
- Write-Debug 'Calling Function: Convert-JSON'
- Convert-JSON
-
- Write-Debug 'Calling Function: Build-ExcelFile'
- Build-ExcelFile
-}
-
-$TotalTime = $Script:Runtime.Totalminutes.ToString('#######.##')
-
-Write-Host '---------------------------------------------------------------------'
-Write-Host ('Execution Complete. Total Runtime was: ') -NoNewline
-Write-Host $TotalTime -NoNewline -ForegroundColor Cyan
-Write-Host (' Minutes')
-Write-Host 'Excel File: ' -NoNewline
-Write-Host $Script:ExcelFile -ForegroundColor Blue
-Write-Host '---------------------------------------------------------------------'
diff --git a/tools/3_wara_reports_generator.ps1 b/tools/3_wara_reports_generator.ps1
deleted file mode 100644
index 40ea85bb3..000000000
--- a/tools/3_wara_reports_generator.ps1
+++ /dev/null
@@ -1,2288 +0,0 @@
-#Requires -Version 7
-
-<#
-.SYNOPSIS
-Well-Architected Reliability Assessment Report Generator Script
-
-.DESCRIPTION
-The script "3_wara_reports_generator" processes the Excel file created by the "2_wara_data_analyzer" script and generates the final PowerPoint and Word reports for the Well-Architected Reliability Assessment.
-
-.PARAMETER Help
-Switch to display help information.
-
-.PARAMETER Debugging
-Switch to enable debugging mode.
-
-.PARAMETER CustomerName
-Name of the customer for whom the report is being generated.
-
-.PARAMETER WorkloadName
-Name of the workload being assessed.
-
-.PARAMETER ExcelFile
-Path to the Excel file created by the "2_wara_data_analyzer" script.
-
-.PARAMETER Heavy
-Switch to enable heavy processing mode. When enabled, this mode introduces additional delays using Start-Sleep at various points in the script to handle heavy environments more gracefully. This can help in scenarios where the system resources are limited or the operations being performed are resource-intensive, ensuring the script doesn't overwhelm the system.
-
-.PARAMETER PPTTemplateFile
-Path to the PowerPoint template file.
-
-.PARAMETER WordTemplateFile
-Path to the Word template file.
-
-.EXAMPLE
-.\3_wara_reports_generator.ps1 -ExcelFile 'C:\WARA_Script\WARA Action Plan 2024-03-07_16_06.xlsx' -CustomerName 'ABC Customer' -WorkloadName 'SAP On Azure' -Heavy -PPTTemplateFile 'C:\Templates\Template.pptx' -WordTemplateFile 'C:\Templates\Template.docx'
-
-.LINK
-https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2
-#>
-
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Justification = 'False positive as Write-Host does not represent a security risk and this script will always run on host consoles')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'False positive as parameters are not always required')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments','', Justification='Variable is reserved for future use')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidGlobalVars','', Justification='This will be fixed in refactor')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns','', Justification='This will be fixed in refactor')]
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions','', Justification='This will be fixed in refactor')]
-
- Param(
- [switch] $Help,
- #[switch] $GenerateCSV,
- #[switch] $includeLow,
- #[switch] $byPassValidationStatus,
- [switch] $Debugging,
- [string] $CustomerName,
- [string] $WorkloadName,
- [Parameter(mandatory = $true)]
- [string] $ExcelFile,
- [switch] $Heavy,
- [string] $PPTTemplateFile,
- [string] $WordTemplateFile
- )
-
- # Checking the operating system running this script.
- if (-not $IsWindows) {
- Write-Host 'This script only supports Windows operating systems currently. Please try to run with Windows operating systems.'
- Exit
- }
-
- if ($Heavy.IsPresent -or $GenerateCSV.IsPresent) { $Global:Heavy = $true } else { $Global:Heavy = $false }
-
- if ($Debugging.IsPresent) { $Global:CoreDebugging = $true } else { $Global:CoreDebugging = $false }
-
- if (!$PPTTemplateFile) {
- if ((Test-Path -Path ($PSScriptRoot + '\Mandatory - Executive Summary presentation - Template.pptx') -PathType Leaf) -eq $true) {
- $PPTTemplateFile = ($PSScriptRoot + '\Mandatory - Executive Summary presentation - Template.pptx')
- }
- else {
- Write-Host "This script requires specific Microsoft PowerPoint and Word templates, which are available in the Azure Proactive Resiliency Library. You can download the templates from this GitHub repository:"
- Write-Host "https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/tree/main/tools"
- Exit
- }
- }
- else
- {
- $PPTTemplateFile = (Resolve-Path -Path $PPTTemplateFile).Path
- #$PPTTemplateFile = get-item -Path $PPTTemplateFile
- #$PPTTemplateFile = $PPTTemplateFile.FullName
- }
-
-
- if (!$WordTemplateFile) {
- if ((Test-Path -Path ($PSScriptRoot + '\Optional - Assessment Report - Template.docx') -PathType Leaf) -eq $true) {
- $WordTemplateFile = ($PSScriptRoot + '\Optional - Assessment Report - Template.docx')
- }
- else {
- Write-Host "This script requires specific Microsoft PowerPoint and Word templates, which are available in the Azure Proactive Resiliency Library. You can download the templates from this GitHub repository:"
- Write-Host "https://github.com/Azure/Azure-Proactive-Resiliency-Library-v2/tree/main/tools"
- Exit
- }
- }
- else
- {
- $WordTemplateFile = (Resolve-Path -Path $WordTemplateFile).Path
- #$WordTemplateFile = get-item -Path $WordTemplateFile
- #$WordTemplateFile = $WordTemplateFile.FullName
- }
-
- if (!$CustomerName) {
- $CustomerName = '[Customer Name]'
- }
-
- if (!$WorkloadName) {
- $WorkloadName = '[Workload Name]'
- }
-
- function Get-HelpMessage {
- Write-Host ""
- Write-Host "Parameters"
- Write-Host ""
- Write-Host " -ExcelFile : Mandatory; WARA Excel file generated by '2_wara_data_analyzer.ps1' script and customized."
- Write-Host " -CustomerName : Optional; specifies the Name of the Customer to be added to the PPTx and DOCx files. "
- Write-Host " -WorkloadName : Optional; specifies the Name of the Workload of the analyses to be added to the PPTx and DOCx files. "
- Write-Host " -PPTTemplateFile : Optional; specifies the PPTx template file to be used as source. If not specified the script will look for the file in the same path as the script. "
- Write-Host " -WordTemplateFile : Optional; specifies the DOCx template file to be used as source. If not specified the script will look for the file in the same path as the script. "
- Write-Host " -GenerateCSV : Optional; when used will trigger the creation of a CSV File with the exported Impacted Resources. "
- Write-Host " -includeLow : Optional; only used in with -GenerateCSV to also include Low recommendations in the CSV File. "
- Write-Host " -byPassValidationStatus : Optional; used to skip the High and Medium Resource Validation. "
-
- byPassValidationStatus
- Write-Host " -Debugging : Optional; writes Debugging information to the screen. "
- Write-Host ""
- Write-Host "Examples: "
- Write-Host ""
- Write-Host " Running with Customer details"
- Write-Host " .\3_wara_reports_generator.ps1 -ExcelFile 'C:\WARA_Script\WARA Action Plan 2024-03-07_16_06.xlsx' -CustomerName 'ABC Customer' -WorkloadName 'SAP On Azure'"
- Write-Host ""
- Write-Host ""
- Write-Host " Running without Customer details"
- Write-Host " .\3_wara_reports_generator.ps1 -ExcelFile 'C:\WARA_Script\WARA Action Plan 2024-03-07_16_06.xlsx'"
- Write-Host ""
- Write-Host ""
- }
-
- $Global:Runtime = Measure-Command -Expression {
-
- function Test-Requirement {
- # Install required modules
- Write-Host "Validating " -NoNewline
- Write-Host "ImportExcel" -ForegroundColor Cyan -NoNewline
- Write-Host " Module.."
- $ImportExcel = Get-Module -Name ImportExcel -ListAvailable -ErrorAction silentlycontinue
- if ($null -eq $ImportExcel)
- {
- Write-Host "Installing ImportExcel Module" -ForegroundColor Yellow
- Install-Module -Name ImportExcel -Force -SkipPublisherCheck
- }
- }
- function Set-LocalFolder {
- # Define script path as the default path to save files
- try
- {
- $workingFolderPath = $PSScriptRoot
- Set-Location -path $workingFolderPath;
- $Global:clonePath = "$workingFolderPath\Azure-Proactive-Resiliency-Library-v2"
- Write-Debug "Checking the version of the script"
- $RepoVersion = Get-Content -Path "$clonePath\tools\Version.json" -ErrorAction SilentlyContinue | ConvertFrom-Json
- if ($Version -ne $RepoVersion.Generator)
- {
- Write-Host "This version of the script is outdated. " -BackgroundColor DarkRed
- Write-Host "Please use a more recent version of the script." -BackgroundColor DarkRed
- }
- else
- {
- Write-Host "This version of the script is current version. " -BackgroundColor DarkGreen
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($Debugging.IsPresent) { ('LocalFiles - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($Debugging.IsPresent) { ('LocalFiles - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
- function Get-Excel {
-
- if ($Debugging.IsPresent) { ('FunctExcel - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Processing Excel variables..') | Out-File -FilePath $LogFile -Append }
-
- if (-not (Test-Path -PathType Leaf -Path $ExcelFile))
- {
- Write-Error ('The specified Excel file "{0}" was not found.' -f $ExcelFile)
- Exit
- }
- $ExcelFile = get-item -Path $ExcelFile
- if ($Global:Heavy) {Start-Sleep -Milliseconds 100}
- $ExcelFile = $ExcelFile.FullName
- try
- {
- $Global:ExcelCore = Import-Excel -Path $ExcelFile
- if ($Global:Heavy) {Start-Sleep -Milliseconds 100}
- $Global:ExcelContent = Import-Excel -Path $ExcelFile -WorksheetName ImpactedResources
- $Global:ExcelRecommendations = Import-Excel -Path $ExcelFile -WorksheetName Recommendations
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- if (($_.Exception -is [System.Management.Automation.MethodInvocationException]) -and ($_.Exception.Message -like '*encrypted*'))
- {
- Write-Error ('The specified Excel file "{0}" may be encrypted. If a sensitivity label is applied to the file, please change the sensitivity label to the label without encryption temporarily. Learn more: https://aka.ms/aprl/tools/faq' -f $ExcelFile)
- }
- else
- {
- Write-Error $errorMessage
- }
- Exit
- }
-
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "25% Complete." -PercentComplete 25
-
- $Global:Outages = try {
- if ($Global:Heavy) {Start-Sleep -Milliseconds 100}
- Import-Excel -Path $ExcelFile -WorksheetName Outages
- }
- catch {
- if ($Debugging.IsPresent) { ('FunctExcel - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Warn - Outages not found in the Excel File..') | Out-File -FilePath $LogFile -Append }
- }
-
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "30% Complete." -PercentComplete 30
- $Global:SupportTickets = try {
- if ($Global:Heavy) {Start-Sleep -Milliseconds 100}
- Import-Excel -Path $ExcelFile -WorksheetName "Support Tickets" -AsText 'Ticket ID'
- }
- catch {
- if ($Debugging.IsPresent) { ('FunctExcel - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Warn - Support Tickets not found in the Excel File..') | Out-File -FilePath $LogFile -Append }
- }
-
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "35% Complete." -PercentComplete 35
- $Global:ServiceHealth = try {
- if ($Global:Heavy) {Start-Sleep -Milliseconds 100}
- Import-Excel -Path $ExcelFile -WorksheetName "Health Alerts"
- }
- catch {
- if ($Debugging.IsPresent) { ('FunctExcel - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Warn - Service Health Alerts not found in the Excel File..') | Out-File -FilePath $LogFile -Append }
- }
-
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "40% Complete." -PercentComplete 40
- $Global:Retirements = try {
- if ($Global:Heavy) {Start-Sleep -Milliseconds 100}
- Import-Excel -Path $ExcelFile -WorksheetName "Retirements"
- }
- catch {
- if ($Debugging.IsPresent) { ('FunctExcel - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Warn - Service Retirements not found in the Excel File..') | Out-File -FilePath $LogFile -Append }
- }
- }
- function Test-Excel {
- Param($ExcelContent,$byPassValidationStatus)
-
- $Validation = $ExcelContent | Where-Object {$_.'How was the resource/recommendation validated or what actions need to be taken?' -like 'IMPORTANT *' -and $_.impact -in ('High','Medium')}
-
- if(![string]::IsNullOrEmpty($Validation) -and !($byPassValidationStatus.IsPresent))
- {
- Write-Host ''
- Write-Host 'There are High- and/or Medium-impact recommendations in the ImpactedResources worksheet that need manual validation. '
- Write-Host ''
- Write-Host 'Open the Action Plan, go to the ImpactedResources worksheet, click the filter in Column A, deselect "APRL - Queries" and "Advisor Queries" then click the filter in Column E, and deselect "Low".'
- Write-Host ''
- Write-Host 'Ensure all listed resources are validated before generating reports.'
- Write-Host ''
- Exit
- }
- }
- function Invoke-Orchestrator {
-
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "45% Complete." -PercentComplete 45
- if ($Debugging.IsPresent) { ('Funct_Orch - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Starting Orchestrator Function..') | Out-File -FilePath $LogFile -Append }
- Start-Job -Name 'OfficeApps' -ScriptBlock {
-
- $CoreDebugging = $($args[13])
- $LogFile = $($args[14])
- $Heavy = $($args[15])
-
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Setting Variables..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $ExcelCore = $($args[0])
- $ExcelContent = $($args[1])
- $Outages = $($args[2])
- $SupportTickets = $($args[3])
- $ServiceHealth = $($args[4])
- $Retirements = $($args[5])
- $ExcelFile = $($args[6])
-
- $HighImpact = $ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'High' } | Sort-Object -Property "Number of Impacted Resources?" -Descending
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- $MediumImpact = $ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'Medium' } | Sort-Object -Property "Number of Impacted Resources?" -Descending
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- $LowImpact = $ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'Low' } | Sort-Object -Property "Number of Impacted Resources?" -Descending
-
- $ServiceHighImpact = $ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'High' -and $_.'Azure Service / Well-Architected' -eq 'Azure Service' } | Sort-Object -Property "Number of Impacted Resources?" -Descending
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- $WAFHighImpact = $ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'High' -and $_.'Azure Service / Well-Architected' -eq 'Well Architected' } | Sort-Object -Property "Number of Impacted Resources?" -Descending
-
- $ResourceIDs = $ExcelContent.id | Select-Object -Unique -CaseInsensitive
-
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Processing Resource Types..') | Out-File -FilePath $LogFile -Append }
- $Resources = @()
- Foreach ($ID in $ResourceIDs)
- {
- if (![string]::IsNullOrEmpty($ID) -and $ID -ne 'n/a')
- {
- $obj = @{
- 'ID' = $ID;
- 'Subscription' = $ID.split('/')[2];
- 'Resource Group' = $ID.split('/')[4];
- 'Resource Type' = ($ID.split('/')[6] + '/' + $ID.split('/')[7])
- }
- $Resources += $obj
- }
- }
-
- $ResourcesTypes = $Resources | Group-Object -Property 'Resource Type' | Sort-Object -Property 'Count' -Descending | Select-Object -First 10
-
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Starting Excel..') | Out-File -FilePath $LogFile -Append }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
-
- try
- {
- $CustomerName = $($args[7])
- $WorkloadName = $($args[8])
- $PPTTemplateFile = $($args[9])
- $PPTFinalFile = $($args[10])
- $WordTemplateFile = $($args[11])
- $WordFinalFile = $($args[12])
-
- $ExcelApplication = New-Object -ComObject Excel.Application
- Start-Sleep 1
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Opening Excel file..') | Out-File -FilePath $LogFile -Append }
- # Resolve the full path of the Excel file
- $ExcelFileFullPath = (Resolve-Path -Path $ExcelFile).Path
-
- # Open the Excel file using the full path
- $Ex = $ExcelApplication.Workbooks.Open($ExcelFileFullPath)
- while ([string]::IsNullOrEmpty($Ex)) {
- Start-Sleep 2
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Waiting Excel document..') | Out-File -FilePath $LogFile -Append }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
-
- $job = @()
-
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Setting PPT Thread..') | Out-File -FilePath $LogFile -Append }
- $PPT = ([PowerShell]::Create()).AddScript(
- {
- param($ResourcesTypes, $HighImpact, $MediumImpact, $LowImpact, $ServiceHighImpact, $WAFHighImpact, $ExcelContent, $Outages, $SupportTickets, $ServiceHealth, $Retirements, $Ex, $CustomerName, $WorkloadName, $ExcelCore, $PPTTemplateFile, $PPTFinalFile, $CoreDebugging, $Logfile, $Heavy)
-
- $Global:AUTOMESSAGE = 'AUTOMATICALLY MODIFIED (Please Review)'
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Starting PPT Thread..') | Out-File -FilePath $LogFile -Append }
-
- ############# Slide 1
- function Remove-Slide1 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Removing Slide 1..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- ($pres.Slides | Where-Object { $_.SlideIndex -eq 1 }).Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- $Slide1 = $pres.Slides | Where-Object { $_.SlideIndex -eq 1 }
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Slide 1 - Adding Customer name: ' + $CustomerName + '. And Workload name: ' + $WorkloadName) | Out-File -FilePath $LogFile -Append }
- ($Slide1.Shapes | Where-Object { $_.Id -eq 5 }).TextFrame.TextRange.Text = ($CustomerName + ' - ' + $WorkloadName)
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# SLide 12
- function Build-Slide12 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 12 - Workload Summary..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Slide12 = $pres.Slides | Where-Object { $_.SlideIndex -eq 12 }
-
- $TargetShape = ($Slide12.Shapes | Where-Object { $_.Id -eq 9 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- $TargetShape = ($Slide12.Shapes | Where-Object { $_.Id -eq 8 })
- $TargetShape.Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 100}
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 12 - Adding Workload name: ' + $WorkloadName) | Out-File -FilePath $LogFile -Append }
- ($Slide12.Shapes | Where-Object { $_.Id -eq 3 }).TextFrame.TextRange.Text = ('During the engagement, the Workload ' + $WorkloadName + ' has been reviewed. The solution is hosted in two Azure regions, and runs mainly IaaS resources, with some PaaS resources, which includes but is not limited to:')
-
- $loop = 1
- foreach ($ResourcesType in $ResourcesTypes)
- {
- $LogResName = $ResourcesType.Name
- $LogResCount = $ResourcesType.'Count'
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 12 - Adding Resource Type: ' + $LogResName + '. Count: ' + $LogResCount) | Out-File -FilePath $LogFile -Append }
- if ($loop -eq 1)
- {
- $ResourceTemp = ($ResourcesType.Name + ' (' + $ResourcesType.'Count' + ')')
- ($Slide12.Shapes | Where-Object { $_.Id -eq 6 }).Table.Columns(1).Width = 685
- ($Slide12.Shapes | Where-Object { $_.Id -eq 6 }).Table.Rows(1).Cells(1).Shape.TextFrame.TextRange.Text = $ResourceTemp
- ($Slide12.Shapes | Where-Object { $_.Id -eq 6 }).Table.Rows(1).Height = 20
- }
- else
- {
- $ResourceTemp = ($ResourcesType.Name + ' (' + $ResourcesType.'Count' + ')')
- ($Slide12.Shapes | Where-Object { $_.Id -eq 6 }).Table.Rows.Add() | Out-Null
- ($Slide12.Shapes | Where-Object { $_.Id -eq 6 }).Table.Rows($loop).Cells(1).Shape.TextFrame.TextRange.Text = $ResourceTemp
- }
- if ($Heavy) {Start-Sleep -Milliseconds 200}
- $loop ++
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 16
- function Build-Slide16 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 16 - Health and Risk Dashboard..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Slide16 = $pres.Slides | Where-Object { $_.SlideIndex -eq 16 }
-
- $TargetShape = ($Slide16.Shapes | Where-Object { $_.Id -eq 41 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- $count = 1
- foreach ($Impact in $ServiceHighImpact)
- {
- $LogImpactName = $Impact.'Recommendation Title'
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 16 - Adding Service High Impact Name: ' + $LogImpactName) | Out-File -FilePath $LogFile -Append }
- if ($count -le 5)
- {
- ($Slide16.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($count).text = $Impact.'Recommendation Title'
- $count ++
- }
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
-
- while (($Slide16.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs().count -gt 5)
- {
- ($Slide16.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(6).Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
-
- if ($WAFHighImpact.count -ne 0)
- {
- $count = 1
- foreach ($Impact in $WAFHighImpact)
- {
- $LogWAFImpactName = $Impact.'Recommendation Title'
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 16 - Adding WAF High Impact: ' + $LogWAFImpactName) | Out-File -FilePath $LogFile -Append }
- if ($count -lt 5)
- {
- ($Slide16.Shapes | Where-Object { $_.Id -eq 12 }).TextFrame.TextRange.Paragraphs($count).text = $Impact.'Recommendation Title'
- $count ++
- }
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- else
- {
- ($Slide16.Shapes | Where-Object { $_.Id -eq 12 }).TextFrame.TextRange.Text = ' '
- }
-
- while (($Slide16.Shapes | Where-Object { $_.Id -eq 12 }).TextFrame.TextRange.Paragraphs().count -gt 5)
- {
- ($Slide16.Shapes | Where-Object { $_.Id -eq 12 }).TextFrame.TextRange.Paragraphs(6).Delete()
- }
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 16 - Adding general values...') | Out-File -FilePath $LogFile -Append }
- #Total Recomendations
- ($Slide16.Shapes | Where-Object { $_.Id -eq 44 }).GroupItems[3].TextFrame.TextRange.Text = [string]($ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 }).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- #High Impact
- ($Slide16.Shapes | Where-Object { $_.Id -eq 44 }).GroupItems[4].TextFrame.TextRange.Text = [string]($ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'High' }).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- #Medium Impact
- ($Slide16.Shapes | Where-Object { $_.Id -eq 44 }).GroupItems[5].TextFrame.TextRange.Text = [string]($ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'Medium' }).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- #Low Impact
- ($Slide16.Shapes | Where-Object { $_.Id -eq 44 }).GroupItems[6].TextFrame.TextRange.Text = [string]($ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'Low' }).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- #Impacted Resources
- ($Slide16.Shapes | Where-Object { $_.Id -eq 44 }).GroupItems[7].TextFrame.TextRange.Text = [string]($ExcelContent.id | Where-Object { ![string]::IsNullOrEmpty($_) } | Select-Object -Unique -CaseInsensitive).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 17
- function Build-Slide17 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 17 - Health and Risk Dashboard..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Slide17 = $pres.Slides | Where-Object { $_.SlideIndex -eq 17 }
-
- $TargetShape = ($Slide17.Shapes | Where-Object { $_.Id -eq 41 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 17 - Looking Charts in Excel File...') | Out-File -FilePath $LogFile -Append }
- $WS2 = $Ex.Worksheets | Where-Object { $_.Name -eq 'Charts' }
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 17 - Replacing Chart 1..') | Out-File -FilePath $LogFile -Append }
- #Copy Excel Chart0
- ($Slide17.Shapes | Where-Object { $_.Id -eq 3 }).Chart.Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $WS2.ChartObjects('ChartP0').copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $Slide17.Shapes.Paste() | Out-Null
- Start-Sleep 2
- foreach ($Shape in $Slide17.Shapes)
- {
- if ($Shape.Name -eq 'ChartP0')
- {
- $Shape.IncrementLeft(240)
- }
- }
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 17 - Replacing Chart 2..') | Out-File -FilePath $LogFile -Append }
- #Copy Excel Chart1
- ($Slide17.Shapes | Where-Object { $_.Id -eq 5 }).Chart.Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $WS2.ChartObjects('ChartP1').copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $Slide17.Shapes.Paste() | Out-Null
- Start-Sleep 2
- foreach ($Shape in $Slide17.Shapes)
- {
- if ($Shape.Name -eq 'ChartP1')
- {
- $Shape.IncrementLeft(-260)
- $Shape.IncrementTop(45)
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 21
- function Build-Slide21 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 21 - Service Health Alerts..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $FirstSlide = 21
- $TableID = 6
- $CurrentSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
- $CoreSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
-
- $TargetShape = ($CurrentSlide.Shapes | Where-Object { $_.Id -eq 41 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 21 - Cleaning Table..') | Out-File -FilePath $LogFile -Append }
- $row = 3
- while ($row -lt 2)
- {
- $cell = 1
- while ($cell -lt 9)
- {
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells($cell).Shape.TextFrame.TextRange.Text = ''
- $Cell ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- $row ++
- }
-
- $Counter = 1
- $row = 3
- foreach ($Health in $Global:ServiceHealth)
- {
- $LogHealthName = $Health.Name
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 21 - Adding Service Health Alert: ' + $LogHealthName) | Out-File -FilePath $LogFile -Append }
- if ($Counter -lt 17)
- {
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(1).Shape.TextFrame.TextRange.Text = [string]$Health.Subscription
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(2).Shape.TextFrame.TextRange.Text = [string]$Health.Name
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(3).Shape.TextFrame.TextRange.Text = if ($Health.Services -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(4).Shape.TextFrame.TextRange.Text = if ($Health.Regions -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(5).Shape.TextFrame.TextRange.Text = if ($Health.'Event Type' -like '*Service Issues*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(6).Shape.TextFrame.TextRange.Text = if ($Health.'Event Type' -like '*Planned Maintenance*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(7).Shape.TextFrame.TextRange.Text = if ($Health.'Event Type' -like '*Health Advisories*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(8).Shape.TextFrame.TextRange.Text = if ($Health.'Event Type' -like '*Security Advisory*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(9).Shape.TextFrame.TextRange.Text = ' '
- $counter ++
- $row ++
- }
- else
- {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 21 - Creating new slide for Service Health Alerts..') | Out-File -FilePath $LogFile -Append }
- $Counter = 1
- $CustomLayout = $CurrentSlide.CustomLayout
- $FirstSlide ++
- $pres.Slides.addSlide($FirstSlide, $customLayout) | Out-Null
-
- $NextSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
- ($CoreSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 2 }).TextFrame.TextRange.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $TableID = 3
- ($CoreSlide.Shapes | Where-Object { $_.Id -eq 41 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- $rowTemp = 2
- while ($rowTemp -lt 18)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- ($NextSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($rowTemp).Cells($cell).Shape.TextFrame.TextRange.Text = ''
- $Cell ++
- }
- $rowTemp ++
- }
-
- $CurrentSlide = $NextSlide
-
- $row = 3
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(1).Shape.TextFrame.TextRange.Text = [string]$Health.Subscription
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(2).Shape.TextFrame.TextRange.Text = [string]$Health.Name
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(3).Shape.TextFrame.TextRange.Text = if ($Health.Services -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(4).Shape.TextFrame.TextRange.Text = if ($Health.Regions -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(5).Shape.TextFrame.TextRange.Text = if ($Health.'Event Type' -like '*Service Issues*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(6).Shape.TextFrame.TextRange.Text = if ($Health.'Event Type' -like '*Planned Maintenance*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(7).Shape.TextFrame.TextRange.Text = if ($Health.'Event Type' -like '*Health Advisories*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(8).Shape.TextFrame.TextRange.Text = if ($Health.'Event Type' -like '*Security Advisory*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(9).Shape.TextFrame.TextRange.Text = ' '
- $Counter ++
- $row ++
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 23
- function Build-Slide23 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 23 - High Impact Issues..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $FirstSlide = 23
- $TableID = 6
- $CurrentSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
- $CoreSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
-
- $TargetShape = ($CurrentSlide.Shapes | Where-Object { $_.Id -eq 41 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 23 - Cleaning Table..') | Out-File -FilePath $LogFile -Append }
- $row = 2
- while ($row -lt 6)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells($cell).Shape.TextFrame.TextRange.Text = ''
- $Cell ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- $row ++
- }
-
- $Counter = 1
- $RecomNumber = 1
- $row = 2
- foreach ($Impact in $HighImpact)
- {
- $LogHighImpact = $Impact.'Recommendation Title'
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 23 - Adding High Impact: ' + $LogHighImpact ) | Out-File -FilePath $LogFile -Append }
- if ($Counter -lt 14)
- {
- #Number
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(1).Shape.TextFrame.TextRange.Text = [string]$RecomNumber
- #Recommendation
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(2).Shape.TextFrame.TextRange.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected') {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(3).Shape.TextFrame.TextRange.Text = $ServiceName
- #Impacted Resources
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(4).Shape.TextFrame.TextRange.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $RecomNumber ++
- $row ++
- }
- else
- {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 23 - Adding new Slide..') | Out-File -FilePath $LogFile -Append }
- $Counter = 1
- $CustomLayout = $CurrentSlide.CustomLayout
- $FirstSlide ++
- $pres.Slides.addSlide($FirstSlide, $customLayout) | Out-Null
-
- $NextSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
- ($CoreSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 2 }).TextFrame.TextRange.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $TableID = 3
- ($CoreSlide.Shapes | Where-Object { $_.Id -eq 41 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 23 - Cleaning table of new slide..') | Out-File -FilePath $LogFile -Append }
- $rowTemp = 2
- while ($rowTemp -lt 15)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- ($NextSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($rowTemp).Cells($cell).Shape.TextFrame.TextRange.Text = ''
- $Cell ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- $rowTemp ++
- }
-
- $CurrentSlide = $NextSlide
-
- $row = 2
- #Number
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(1).Shape.TextFrame.TextRange.Text = [string]$RecomNumber
- #Recommendation
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(2).Shape.TextFrame.TextRange.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(3).Shape.TextFrame.TextRange.Text = $ServiceName
- #Impacted Resources
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(4).Shape.TextFrame.TextRange.Text = [string]$Impact.'Number of Impacted Resources?'
- $Counter ++
- $RecomNumber ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 24
- function Build-Slide24 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 24 - Medium Impact Issues..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $FirstSlide = 24
- $TableID = 6
- $CurrentSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
- $CoreSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
-
- $TargetShape = ($CurrentSlide.Shapes | Where-Object { $_.Id -eq 41 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 24 - Cleaning Table..') | Out-File -FilePath $LogFile -Append }
- $row = 2
- while ($row -lt 6)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells($cell).Shape.TextFrame.TextRange.Text = ''
- $Cell ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- $row ++
- }
-
- $Counter = 1
- $RecomNumber = 1
- $row = 2
- foreach ($Impact in $MediumImpact)
- {
- $LogMediumImpact = $Impact.'Recommendation Title'
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 24 - Adding Medium Impact: ' + $LogMediumImpact) | Out-File -FilePath $LogFile -Append }
- if ($Counter -lt 14)
- {
- #Number
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(1).Shape.TextFrame.TextRange.Text = [string]$RecomNumber
- #Recommendation
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(2).Shape.TextFrame.TextRange.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(3).Shape.TextFrame.TextRange.Text = $ServiceName
- #Impacted Resources
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(4).Shape.TextFrame.TextRange.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $RecomNumber ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- else
- {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 24 - Creating new slide..') | Out-File -FilePath $LogFile -Append }
- $Counter = 1
- $CustomLayout = $CurrentSlide.CustomLayout
- $FirstSlide ++
- $pres.Slides.addSlide($FirstSlide, $customLayout) | Out-Null
-
- $NextSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
- ($CoreSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 2 }).TextFrame.TextRange.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $TableID = 3
- ($CoreSlide.Shapes | Where-Object { $_.Id -eq 41 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 24 - Cleaning Table of new slide..') | Out-File -FilePath $LogFile -Append }
- $rowTemp = 2
- while ($rowTemp -lt 15)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- ($NextSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($rowTemp).Cells($cell).Shape.TextFrame.TextRange.Text = ''
- $Cell ++
- }
- $rowTemp ++
- }
-
- $CurrentSlide = $NextSlide
-
- $row = 2
- #Number
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(1).Shape.TextFrame.TextRange.Text = [string]$RecomNumber
- #Recommendation
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(2).Shape.TextFrame.TextRange.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(3).Shape.TextFrame.TextRange.Text = $ServiceName
- #Impacted Resources
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(4).Shape.TextFrame.TextRange.Text = [string]$Impact.'Number of Impacted Resources?'
- $Counter ++
- $RecomNumber ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 25
- function Build-Slide25 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 25 - Low Impact Issues..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $FirstSlide = 25
- $TableID = 6
- $CurrentSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
- $CoreSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
-
- $TargetShape = ($CurrentSlide.Shapes | Where-Object { $_.Id -eq 41 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 25 - Cleaning Table..') | Out-File -FilePath $LogFile -Append }
- $row = 2
- while ($row -lt 6)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells($cell).Shape.TextFrame.TextRange.Text = ''
- $Cell ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- $row ++
- }
-
- $Counter = 1
- $RecomNumber = 1
- $row = 2
- foreach ($Impact in $LowImpact)
- {
- $LogLowImpact = $Impact.'Recommendation Title'
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 25 - Adding Low Impact: ' + $LogLowImpact) | Out-File -FilePath $LogFile -Append }
- if ($Counter -lt 14)
- {
- #Number
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(1).Shape.TextFrame.TextRange.Text = [string]$RecomNumber
- #Recommendation
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(2).Shape.TextFrame.TextRange.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(3).Shape.TextFrame.TextRange.Text = $ServiceName
- #Impacted Resources
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(4).Shape.TextFrame.TextRange.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $RecomNumber ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- else
- {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 25 - Creating new Slide..') | Out-File -FilePath $LogFile -Append }
- $Counter = 1
- $CustomLayout = $CurrentSlide.CustomLayout
- $FirstSlide ++
- $pres.Slides.addSlide($FirstSlide, $customLayout) | Out-Null
-
- $NextSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $FirstSlide }
- ($CoreSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 2 }).TextFrame.TextRange.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $TableID = 3
- ($CoreSlide.Shapes | Where-Object { $_.Id -eq 41 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 25 - Cleaning Table of new slide..') | Out-File -FilePath $LogFile -Append }
- $rowTemp = 2
- while ($rowTemp -lt 15)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- ($NextSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($rowTemp).Cells($cell).Shape.TextFrame.TextRange.Text = ''
- $Cell ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- $rowTemp ++
- }
-
- $CurrentSlide = $NextSlide
-
- $row = 2
- #Number
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(1).Shape.TextFrame.TextRange.Text = [string]$RecomNumber
- #Recommendation
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(2).Shape.TextFrame.TextRange.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(3).Shape.TextFrame.TextRange.Text = $ServiceName
- #Impacted Resources
- ($CurrentSlide.Shapes | Where-Object { $_.Id -eq $TableID }).Table.Rows($row).Cells(4).Shape.TextFrame.TextRange.Text = [string]$Impact.'Number of Impacted Resources?'
- $Counter ++
- $RecomNumber ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 28
- function Build-Slide28 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 28 - Recent Microsoft Outages..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Loop = 1
- $CurrentSlide = 28
-
- if (![string]::IsNullOrEmpty($Global:Outages))
- {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 28 - Outages found..') | Out-File -FilePath $LogFile -Append }
- foreach ($Outage in $Global:Outages)
- {
- if ($Loop -eq 1)
- {
- $OutageName = ($Outage.'Tracking ID' + ' - ' + $Outage.title)
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 28 - Adding Outage: ' + $OutageName) | Out-File -FilePath $LogFile -Append }
-
- $OutageService = $Outage.'Impacted Service'
-
- $Slide28 = $pres.Slides | Where-Object { $_.SlideIndex -eq 28 }
-
- $TargetShape = ($Slide28.Shapes | Where-Object { $_.Id -eq 4 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(1).Text = $OutageName
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(2).Text = "What happened:"
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(3).Text = $Outage.'What happened'
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(2).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(4).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(4).Text = "Impacted Service:"
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(3).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(5).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(5).Text = $OutageService
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(4).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(6).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(6).Text = "How can customers make incidents like this less impactful:"
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(5).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(7).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(7).Text = $Outage.'How can customers make incidents like this less impactful'
-
- while (($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs().count -gt 7)
- {
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(8).Delete()
- }
- }
- else
- {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 28 - Creating new Slide..') | Out-File -FilePath $LogFile -Append }
- ############### NEXT 9 SLIDES
-
- $OutageName = ($Outage.'Tracking ID' + ' - ' + $Outage.title)
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 28 - Adding Outage: ' + $OutageName) | Out-File -FilePath $LogFile -Append }
-
- $OutageService = $Outage.'Impacted Service'
- $CustomLayout = $Slide28.CustomLayout
- $pres.Slides.addSlide($CurrentSlide, $customLayout) | Out-Null
-
- $NextSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $CurrentSlide }
-
- ($Slide28.Shapes | Where-Object { $_.Id -eq 6 }).TextFrame.TextRange.Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 2 }).TextFrame.TextRange.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- ($Slide28.Shapes | Where-Object { $_.Id -eq 4 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- ($Slide28.Shapes | Where-Object { $_.Id -eq 7 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(1).Text = $OutageName
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(2).Text = "What happened:"
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(3).Text = $Outage.'What happened'
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(2).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(4).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(4).Text = "Impacted Service:"
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(3).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(5).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(5).Text = $OutageService
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(4).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(6).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(6).Text = "How can customers make incidents like this less impactful:"
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(5).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(7).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(7).Text = $Outage.'How can customers make incidents like this less impactful'
-
- ($Slide28.Shapes | Where-Object { $_.Id -eq 31 }).Copy()
-
- $NextSlide.Shapes.Paste() | Out-Null
-
- while (($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs().count -gt 7)
- {
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 4 }).TextFrame.TextRange.Paragraphs(8).Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- $Loop ++
- $CurrentSlide ++
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 29
- function Build-Slide29 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 29 - Sev-A Support Requests..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Loop = 1
- $CurrentSlide = 29
- $Slide = 1
-
- if (![string]::IsNullOrEmpty($Global:SupportTickets))
- {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 29 - Support Tickets found..') | Out-File -FilePath $LogFile -Append }
- foreach ($Tickets in $Global:SupportTickets)
- {
- $TicketName = ($Tickets.'Ticket ID' + ' - ' + $Tickets.Title)
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 29 - Adding Ticket: ' + $TicketName) | Out-File -FilePath $LogFile -Append }
- $TicketStatus = $Tickets.'Status'
- $TicketDate = $Tickets.'Creation Date'
-
- if ($Slide -eq 1)
- {
- if ($Loop -eq 1)
- {
- $Slide29 = $pres.Slides | Where-Object { $_.SlideIndex -eq 29 }
- $TargetShape = ($Slide29.Shapes | Where-Object { $_.Id -eq 4 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
-
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(1).Text = $TicketName
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(2).Text = "Status: $TicketStatus"
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(3).Text = "Creation Date: $TicketDate"
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(3).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(4).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 300}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(4).Text = "Recommendation: "
-
- while (($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs().count -gt 4)
- {
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(5).Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 200}
- }
- $ParagraphLoop = 5
- $Loop ++
- }
- else
- {
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(1).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Text = $TicketName
- $ParagraphLoop ++
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(2).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Text = "Status: $TicketStatus"
- $ParagraphLoop ++
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(3).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Text = "Creation Date: $TicketDate"
- $ParagraphLoop ++
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(4).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Text = "Recommendation: "
- $ParagraphLoop ++
-
- if ($Loop -eq 4)
- {
- $Loop = 1
- $Slide ++
- $CurrentSlide ++
- }
- else
- {
- $Loop ++
- }
- Start-Sleep -Milliseconds 500
- }
- }
- else {
- if ($Loop -eq 1) {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 29 - Adding new Slide..') | Out-File -FilePath $LogFile -Append }
- $CustomLayout = $Slide29.CustomLayout
- $pres.Slides.addSlide($CurrentSlide, $customLayout) | Out-Null
-
- $NextSlide = $pres.Slides | Where-Object { $_.SlideIndex -eq $CurrentSlide }
-
- ($Slide29.Shapes | Where-Object { $_.Id -eq 6 }).TextFrame.TextRange.Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 200}
-
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 2 }).TextFrame.TextRange.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- ($Slide29.Shapes | Where-Object { $_.Id -eq 4 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 200}
-
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- ($Slide29.Shapes | Where-Object { $_.Id -eq 2 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 200}
-
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- ($Slide29.Shapes | Where-Object { $_.Id -eq 7 }).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 200}
-
- $NextSlide.Shapes.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
-
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(1).Text = $TicketName
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(2).Text = "Status: $TicketStatus"
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(3).Text = "Creation Date: $TicketDate"
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(4).Text = "Recommendation: "
-
- while (($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs().count -gt 4)
- {
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(5).Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 300}
- }
- $ParagraphLoop = 5
- $Loop ++
- }
- else {
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(1).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Text = $TicketName
- $ParagraphLoop ++
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(2).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Text = "Status: $TicketStatus"
- $ParagraphLoop ++
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(3).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Text = "Creation Date: $TicketDate"
- $ParagraphLoop ++
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs(4).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($NextSlide.Shapes | Where-Object { $_.Id -eq 9 }).TextFrame.TextRange.Paragraphs($ParagraphLoop).Text = "Recommendation: "
- $ParagraphLoop ++
-
- if ($Loop -eq 4) {
- $Loop = 1
- $Slide ++
- $CurrentSlide ++
- }
- else {
- $Loop ++
- }
- }
- }
- Start-Sleep -Milliseconds 500
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- ############# Slide 30
- function Build-Slide30 {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 30 - Service Retirement Notifications..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Loop = 1
-
- if (![string]::IsNullOrEmpty($Global:Retirements))
- {
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 30 - Service Retirement found..') | Out-File -FilePath $LogFile -Append }
- $Slide30 = $pres.Slides | Where-Object { $_.SlideIndex -eq 30 }
-
- $TargetShape = ($Slide30.Shapes | Where-Object { $_.Id -eq 4 })
- $TargetShape.TextFrame.TextRange.Text = $AUTOMESSAGE
- #$TargetShape.Delete()
-
- ($Slide30.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(1).Text = '.'
-
- while (($Slide30.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs().count -gt 2)
- {
- ($Slide30.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(2).Delete()
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
-
- foreach ($Retirement in $Global:Retirements)
- {
- if ($Loop -lt 15)
- {
- if ($Loop -eq 1)
- {
- $RetireName = ($Retirement.'Tracking ID' + ' - ' + $Retirement.Status + ' : ' + $Retirement.title)
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Slide 30 - Adding Retirement: ' + $RetireName) | Out-File -FilePath $LogFile -Append }
-
- ($Slide30.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(1).Text = $RetireName
- $Loop ++
- }
- else
- {
- $RetireName = ($Retirement.'Tracking ID' + ' - ' + $Retirement.Status + ' : ' + $Retirement.title)
-
- ($Slide30.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.InsertAfter(".") | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide30.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs(1).Copy()
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide30.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($Loop).Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 500} else {Start-Sleep -Milliseconds 100}
- ($Slide30.Shapes | Where-Object { $_.Id -eq 7 }).TextFrame.TextRange.Paragraphs($Loop).Text = $RetireName
- $Loop ++
- }
- }
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Starting PowerPoint..') | Out-File -FilePath $LogFile -Append }
- try
- {
- #Opening PPT
- $Global:Application = New-Object -ComObject PowerPoint.Application
-
- $Global:pres = $Application.Presentations.Open($PPTTemplateFile, $null, $null, $null)
-
- Remove-Slide1
- Build-Slide12
- Build-Slide16
- Build-Slide17
-
- Build-Slide30
- Build-Slide29
- Build-Slide28
-
- Build-Slide25
- Build-Slide24
- Build-Slide23
-
- Build-Slide21
-
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Closing PowerPoint..') | Out-File -FilePath $LogFile -Append }
- $Global:pres.SaveAs($PPTFinalFile)
- $Global:pres.Close()
- $Global:Application.Quit()
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('PPT_Thread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
-
- }).AddArgument($ResourcesTypes).AddArgument($HighImpact).AddArgument($MediumImpact).AddArgument($LowImpact).AddArgument($ServiceHighImpact).AddArgument($WAFHighImpact).AddArgument($ExcelContent).AddArgument($Outages).AddArgument($SupportTickets).AddArgument($ServiceHealth).AddArgument($Retirements).AddArgument($Ex).AddArgument($CustomerName).AddArgument($WorkloadName).AddArgument($ExcelCore).AddArgument($PPTTemplateFile).AddArgument($PPTFinalFile).AddArgument($CoreDebugging).AddArgument($Logfile).AddArgument($Heavy)
-
-
- if ($WordTemplateFile)
- {
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Setting Word Thread..') | Out-File -FilePath $LogFile -Append }
- $Word = ([PowerShell]::Create()).AddScript(
- {
- param($ResourcesTypes, $HighImpact, $MediumImpact, $LowImpact, $ServiceHighImpact, $WAFHighImpact, $ExcelContent, $Outages, $SupportTickets, $ServiceHealth, $Retirements, $Ex, $CustomerName, $WorkloadName, $ExcelCore, $WordTemplateFile, $WordFinalFile, $CoreDebugging, $Logfile, $Heavy)
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Starting Word Thread..') | Out-File -FilePath $LogFile -Append }
- function Build-WordCore {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Word Core File..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $MatchCase = $false
- $MatchWholeWord = $true
- $MatchWildcards = $false
- $MatchSoundsLike = $false
- $MatchAllWordForms = $false
- $Forward = $true
- $wrap = $wdFindContinue
- $wdFindContinue = 1
- $Format = $false
- $ReplaceAll = 2
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Replacing Workload name: ' + $WorkloadName) | Out-File -FilePath $LogFile -Append }
- $FindText = '[Workload Name]'
- $ReplaceWith = $WorkloadName
- $Global:Document.Content.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $wrap, $Format, $ReplaceWith, $ReplaceAll) | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 200}
-
- $FindText = 'Workload Name'
- $ReplaceWith = $WorkloadName
- $Global:Document.Content.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $wrap, $Format, $ReplaceWith, $ReplaceAll) | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 200}
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Replacing Customer name: ' + $CustomerName) | Out-File -FilePath $LogFile -Append }
- $FindText = '[Customer Name]'
- $ReplaceWith = $CustomerName
- $Global:Document.Content.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $wrap, $Format, $ReplaceWith, $ReplaceAll) | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 200}
-
- $FindText = '[Type Customer Name Here]'
- $ReplaceWith = $CustomerName
- $Global:Document.Content.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $wrap, $Format, $ReplaceWith, $ReplaceAll) | Out-Null
- $Global:Document.Sections(1).Headers(1).Range.Find.Execute($FindText, $MatchCase, $MatchWholeWord, $MatchWildcards, $MatchSoundsLike, $MatchAllWordForms, $Forward, $wrap, $Format, $ReplaceWith, $ReplaceAll) | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 200}
-
- # Total Recommendations
- $Global:Document.Content.Paragraphs(145).Range.Text = [string]($ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 }).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- #High Impact
- $Global:Document.Content.Paragraphs(155).Range.Text = [string]($ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'High' }).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- #Medium Impact
- $Global:Document.Content.Paragraphs(157).Range.Text = [string]($ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'Medium' }).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- #Low Impact
- $Global:Document.Content.Paragraphs(159).Range.Text = [string]($ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 0 -and $_.Impact -eq 'Low' }).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- #Impacted Resources
- $Global:Document.Content.Paragraphs(165).Range.Text = [string]($ExcelContent.id | Where-Object { ![string]::IsNullOrEmpty($_) } | Select-Object -Unique).count
- if ($Heavy) {Start-Sleep -Milliseconds 100}
-
- $HealthHigh = $ExcelCore | Where-Object { $_."Number of Impacted Resources?" -gt 1 -and $_.Impact -eq 'High' } | Sort-Object -Property "Number of Impacted Resources?" -Descending
-
- #Risk Assessment Result
- $Global:Document.Content.Paragraphs(176).Range.Text = ''
- $Global:Document.Content.Paragraphs(175).Range.Text = ''
-
- #$Global:Document.Content.Paragraphs(158).Range.ListFormat.ApplyListTemplate($Global:Word.Application.ListGalleries[1].ListTemplates[3])
-
- #Health Assessment Result
- $Global:Document.Content.Paragraphs(172).Range.Text = ''
-
- #$Global:Document.Content.Paragraphs(158).Range.ListFormat.ApplyListTemplate($Global:Word.Application.ListGalleries[1].ListTemplates[3])
- $Global:Document.Content.Paragraphs(171).Range.Select()
- $Loops = 1
- Foreach ($Risk in $HealthHigh)
- {
- if ([string]::IsNullOrEmpty($Risk))
- {
- $Global:Document.Content.Paragraphs(171).Range.Text = ''
- }
- $Title = $Risk.'Recommendation Title'
- if ($Loops -eq 1)
- {
- $Global:Word.Selection.TypeText($Title) | Out-Null
- }
- else
- {
- $Global:Word.Selection.TypeParagraph() | Out-Null
- $Global:Word.Selection.TypeText($Title) | Out-Null
- }
- $Loops ++
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
- function Build-WordCharts {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Word Charts..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Looking for Charts in the Excel file..') | Out-File -FilePath $LogFile -Append }
- #Charts
- $WS2 = $Global:Ex.Worksheets | Where-Object { $_.Name -eq 'Charts' }
-
- $Position = $Global:Document.Content.Paragraphs(181).Range.Start
-
- $Global:Document.Content.InlineShapes(10).Delete() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- $Global:Document.Content.InlineShapes(9).Delete() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- $Global:Document.Content.InlineShapes(8).Delete() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 100}
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Coping Chart 1..') | Out-File -FilePath $LogFile -Append }
- $WS2.ChartObjects('ChartP0').copy()
-
- $Global:Document.Range($Position, $Position).Select()
- $Global:Word.Selection.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 200}
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Coping Chart 2..') | Out-File -FilePath $LogFile -Append }
- $WS2.ChartObjects('ChartP1').copy()
- $Global:Word.Selection.Paste() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 200}
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
- function Build-WordOutages {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Outages..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Global:Document.Tables(10).Rows(2).Cells(1).Range.Text = ''
- $Global:Document.Tables(10).Rows(2).Cells(2).Range.Text = ''
- $Global:Document.Tables(10).Rows(2).Cells(3).Range.Text = ''
-
- $LineCounter = 2
- if (![string]::IsNullOrEmpty($Global:Outages))
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Outages found..') | Out-File -FilePath $LogFile -Append }
- foreach ($Outage in $Global:Outages)
- {
- if ($LineCounter -gt 3)
- {
- $Global:Document.Tables(10).Rows.Add() | Out-Null
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- $OutageName = ($Outage.'Tracking ID' + ' - ' + $Outage.title)
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Outage: ' + $OutageName) | Out-File -FilePath $LogFile -Append }
- $OutageWhat = $Outage.'What happened'
- $OutageRecom = $Outage.'How can customers make incidents like this less impactful'
-
- $Global:Document.Tables(10).Rows($LineCounter).Cells(1).Range.Text = $OutageName
- $Global:Document.Tables(10).Rows($LineCounter).Cells(2).Range.Text = $OutageWhat
- $Global:Document.Tables(10).Rows($LineCounter).Cells(3).Range.Text = $OutageRecom
-
- $LineCounter ++
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
- function Build-WordTables {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Tables..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Cleaning Table 6..') | Out-File -FilePath $LogFile -Append }
- $row = 2
- while ($row -lt 5)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- $Global:Document.Tables(6).Rows($row).Cells($cell).Range.Text = ''
- $Cell ++
- }
- $row ++
- }
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Cleaning Table 7..') | Out-File -FilePath $LogFile -Append }
- $row = 2
- while ($row -lt 3)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- $Global:Document.Tables(7).Rows($row).Cells($cell).Range.Text = ''
- $Cell ++
- }
- $row ++
- }
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Cleaning Table 8..') | Out-File -FilePath $LogFile -Append }
- $row = 2
- while ($row -lt 3)
- {
- $cell = 1
- while ($cell -lt 5)
- {
- $Global:Document.Tables(8).Rows($row).Cells($cell).Range.Text = ''
- $Cell ++
- }
- $row ++
- }
-
- #Populate Table Health and Risk Summary High
- $counter = 1
- $row = 2
- foreach ($Impact in $HighImpact)
- {
- $LogHighImpact = $Impact.'Recommendation Title'
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding High Impact: ' + $LogHighImpact) | Out-File -FilePath $LogFile -Append }
- if ($counter -lt 14)
- {
- #Number
- $Global:Document.Tables(6).Rows($row).Cells(1).Range.Text = [string]$counter
- #Recommendation
- $Global:Document.Tables(6).Rows($row).Cells(2).Range.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected') {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- $Global:Document.Tables(6).Rows($row).Cells(3).Range.Text = $ServiceName
- #Impacted Resources
- $Global:Document.Tables(6).Rows($row).Cells(4).Range.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- else
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Row to High Impact table..') | Out-File -FilePath $LogFile -Append }
- $Global:Document.Tables(6).Rows.add() | Out-Null
- #Number
- $Global:Document.Tables(6).Rows($row).Cells(1).Range.Text = [string]$counter
- #Recommendation
- $Global:Document.Tables(6).Rows($row).Cells(2).Range.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- $Global:Document.Tables(6).Rows($row).Cells(3).Range.Text = $ServiceName
- #Impacted Resources
- $Global:Document.Tables(6).Rows($row).Cells(4).Range.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
-
- #Populate Table Health and Risk Summary Medium
- $counter = 1
- $row = 2
- foreach ($Impact in $MediumImpact)
- {
- $LogMediumImpact = $Impact.'Recommendation Title'
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Medium Impact: ' + $LogMediumImpact) | Out-File -FilePath $LogFile -Append }
- if ($counter -lt 14)
- {
- #Number
- $Global:Document.Tables(7).Rows($row).Cells(1).Range.Text = [string]$counter
- #Recommendation
- $Global:Document.Tables(7).Rows($row).Cells(2).Range.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- $Global:Document.Tables(7).Rows($row).Cells(3).Range.Text = $ServiceName
- #Impacted Resources
- $Global:Document.Tables(7).Rows($row).Cells(4).Range.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- else
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Row to Medium Impact table..') | Out-File -FilePath $LogFile -Append }
- $Global:Document.Tables(7).Rows.add() | Out-Null
- #Number
- $Global:Document.Tables(7).Rows($row).Cells(1).Range.Text = [string]$counter
- #Recommendation
- $Global:Document.Tables(7).Rows($row).Cells(2).Range.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- $Global:Document.Tables(7).Rows($row).Cells(3).Range.Text = $ServiceName
- #Impacted Resources
- $Global:Document.Tables(7).Rows($row).Cells(4).Range.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
-
- #Populate Table Health and Risk Summary Low
- $counter = 1
- $row = 2
- foreach ($Impact in $LowImpact)
- {
- $LogLowImpact = $Impact.'Recommendation Title'
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Low Impact: ' + $LogLowImpact) | Out-File -FilePath $LogFile -Append }
- if ($counter -lt 14)
- {
- #Number
- $Global:Document.Tables(8).Rows($row).Cells(1).Range.Text = [string]$counter
- #Recommendation
- $Global:Document.Tables(8).Rows($row).Cells(2).Range.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- $Global:Document.Tables(8).Rows($row).Cells(3).Range.Text = $ServiceName
- #Impacted Resources
- $Global:Document.Tables(8).Rows($row).Cells(4).Range.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- else
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Row to Low Impact table..') | Out-File -FilePath $LogFile -Append }
- $Global:Document.Tables(8).Rows.add() | Out-Null
- #Number
- $Global:Document.Tables(8).Rows($row).Cells(1).Range.Text = [string]$counter
- #Recommendation
- $Global:Document.Tables(8).Rows($row).Cells(2).Range.Text = $Impact.'Recommendation Title'
- #Service
- if ($Impact.'Azure Service / Well-Architected' -eq 'Well Architected')
- {
- $ServiceName = ('WAF - ' + $Impact.'Azure Service / Well-Architected Topic')
- }
- else
- {
- $ServiceName = $Impact.'Azure Service / Well-Architected Topic'
- }
- $Global:Document.Tables(8).Rows($row).Cells(3).Range.Text = $ServiceName
- #Impacted Resources
- $Global:Document.Tables(8).Rows($row).Cells(4).Range.Text = [string]$Impact.'Number of Impacted Resources?'
- $counter ++
- $row ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
- function Build-WordRetirements {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Retirements..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Global:Document.Tables(12).Rows(2).Cells(1).Range.Text = ''
- $Global:Document.Tables(12).Rows(2).Cells(2).Range.Text = ''
- $Global:Document.Tables(12).Rows(2).Cells(3).Range.Text = ''
-
- $LineCounter = 2
- if (![string]::IsNullOrEmpty($Global:Retirements))
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Retirements found..') | Out-File -FilePath $LogFile -Append }
- foreach ($Retires in $Global:Retirements)
- {
- if ($LineCounter -gt 3)
- {
- $Global:Document.Tables(12).Rows.Add() | Out-Null
- }
- $RetireName = ($Retires.'Tracking ID' + ' - ' + $Retires.Status + ' : ' + $Retires.title)
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Retirement: ' + $RetireName) | Out-File -FilePath $LogFile -Append }
- $RetireSub = $Retires.Subscription
- $RetireDetails = $Retires.Details
-
- $Global:Document.Tables(12).Rows($LineCounter).Cells(1).Range.Text = $RetireName
- $Global:Document.Tables(12).Rows($LineCounter).Cells(2).Range.Text = $RetireSub
- $Global:Document.Tables(12).Rows($LineCounter).Cells(3).Range.Text = $RetireDetails
-
- $LineCounter ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
- function Build-WordSupports {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Support Tickets..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Global:Document.Tables(11).Rows(2).Cells(1).Range.Text = ''
- $Global:Document.Tables(11).Rows(2).Cells(2).Range.Text = ''
- $Global:Document.Tables(11).Rows(2).Cells(3).Range.Text = ''
- $Global:Document.Tables(11).Rows(2).Cells(4).Range.Text = ''
-
- $LineCounter = 2
- if (![string]::IsNullOrEmpty($Global:SupportTickets))
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Support Tickets found..') | Out-File -FilePath $LogFile -Append }
- foreach ($Ticket in $Global:SupportTickets)
- {
- if ($LineCounter -gt 3)
- {
- $Global:Document.Tables(11).Rows.Add() | Out-Null
- }
- $TicketName = ($Ticket.'Ticket ID' + ' - ' + $Ticket.Title)
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Support Ticket: ' + $TicketName) | Out-File -FilePath $LogFile -Append }
- $CreatedDate = $Ticket.'Creation Date'
-
- $Global:Document.Tables(11).Rows($LineCounter).Cells(1).Range.Text = $TicketName
- $Global:Document.Tables(11).Rows($LineCounter).Cells(2).Range.Text = $CreatedDate
- $Global:Document.Tables(11).Rows($LineCounter).Cells(3).Range.Text = " "
- $Global:Document.Tables(11).Rows($LineCounter).Cells(4).Range.Text = " "
-
- $LineCounter ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
- function Build-WordHealths {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Editing Service Health Alerts..') | Out-File -FilePath $LogFile -Append }
-
- try
- {
- $Global:Document.Tables(5).Rows(3).Cells(1).Range.Text = ''
- $Global:Document.Tables(5).Rows(3).Cells(2).Range.Text = ''
- $Global:Document.Tables(5).Rows(3).Cells(3).Range.Text = ''
- $Global:Document.Tables(5).Rows(3).Cells(4).Range.Text = ''
- $Global:Document.Tables(5).Rows(3).Cells(5).Range.Text = ''
- $Global:Document.Tables(5).Rows(3).Cells(6).Range.Text = ''
- $Global:Document.Tables(5).Rows(3).Cells(7).Range.Text = ''
- $Global:Document.Tables(5).Rows(3).Cells(8).Range.Text = ''
-
- $LineCounter = 3
- if (![string]::IsNullOrEmpty($Global:ServiceHealth))
- {
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Service Health Alerts found..') | Out-File -FilePath $LogFile -Append }
- foreach ($Health in $Global:ServiceHealth)
- {
- $LogHealthName = $Health.Name
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Adding Service Health Alert: ' + $LogHealthName) | Out-File -FilePath $LogFile -Append }
- if ($LineCounter -gt 4)
- {
- $Global:Document.Tables(5).Rows.Add() | Out-Null
- }
- $ActionGroup = $Health.'Action Group'
-
- $Global:Document.Tables(5).Rows($LineCounter).Cells(1).Range.Text = $Health.Subscription
- $Global:Document.Tables(5).Rows($LineCounter).Cells(2).Range.Text = $Health.Services
- $Global:Document.Tables(5).Rows($LineCounter).Cells(3).Range.Text = $Health.Regions
- $Global:Document.Tables(5).Rows($LineCounter).Cells(4).Range.Text = if ($Health.'Event Type' -like '*Service Issues*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- $Global:Document.Tables(5).Rows($LineCounter).Cells(5).Range.Text = if ($Health.'Event Type' -like '*Planned Maintenance*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- $Global:Document.Tables(5).Rows($LineCounter).Cells(6).Range.Text = if ($Health.'Event Type' -like '*Health Advisories*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- $Global:Document.Tables(5).Rows($LineCounter).Cells(7).Range.Text = if ($Health.'Event Type' -like '*Security Advisory*' -or $Health.'Event Type' -eq 'All') { 'Yes' }else { 'No' }
- $Global:Document.Tables(5).Rows($LineCounter).Cells(8).Range.Text = $ActionGroup
- $LineCounter ++
- if ($Heavy) {Start-Sleep -Milliseconds 100}
- }
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
- }
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Starting Word..') | Out-File -FilePath $LogFile -Append }
- try
- {
- $Global:Word = New-Object -Com Word.Application
-
- $Global:Document = $Word.documents.open($WordTemplateFile)
-
- Build-WordCharts
- Build-WordCore
- Build-WordRetirements
- Build-WordSupports
- Build-WordOutages
- Build-WordTables
- Build-WordHealths
-
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Closing Word..') | Out-File -FilePath $LogFile -Append }
- $Global:Document.SaveAs($WordFinalFile)
- if ($Heavy) {Start-Sleep -Milliseconds 200}
- $Global:Document.Close()
- $Global:Word.Quit()
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('WordThread - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
-
- }).AddArgument($ResourcesTypes).AddArgument($HighImpact).AddArgument($MediumImpact).AddArgument($LowImpact).AddArgument($ServiceHighImpact).AddArgument($WAFHighImpact).AddArgument($ExcelContent).AddArgument($Outages).AddArgument($SupportTickets).AddArgument($ServiceHealth).AddArgument($Retirements).AddArgument($Ex).AddArgument($CustomerName).AddArgument($WorkloadName).AddArgument($ExcelCore).AddArgument($WordTemplateFile).AddArgument($WordFinalFile).AddArgument($CoreDebugging).AddArgument($Logfile).AddArgument($Heavy)
- }
-
- try
- {
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Invoking PPT Thread..') | Out-File -FilePath $LogFile -Append }
- $jobPPT = $PPT.BeginInvoke()
- if ($WordTemplateFile)
- {
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Invoking Word Thread..') | Out-File -FilePath $LogFile -Append }
- $jobWord = $Word.BeginInvoke()
- }
-
- $job += $jobPPT
- if ($WordTemplateFile)
- {
- $job += $jobWord
- }
-
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Waiting Threads..') | Out-File -FilePath $LogFile -Append }
- while ($Job.Runspace.IsCompleted -contains $false) {}
-
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Finishing Threads..') | Out-File -FilePath $LogFile -Append }
- $PPT.EndInvoke($jobPPT)
- if ($WordTemplateFile)
- {
- $Word.EndInvoke($jobWord)
- }
-
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Disposing Threads..') | Out-File -FilePath $LogFile -Append }
- $PPT.Dispose()
- if ($WordTemplateFile)
- {
- $Word.Dispose()
- }
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
-
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Closing Excel..') | Out-File -FilePath $LogFile -Append }
- try
- {
- $Global:Ex.Save()
- $Global:Ex.Close()
- $Global:ExcelApplication.Quit()
- }
- catch
- {
- $errorMessage = $_.Exception
- $ErrorStack = $_.ScriptStackTrace
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $errorMessage) | Out-File -FilePath $LogFile -Append }
- if ($CoreDebugging) { ('OfficeApps - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Error - ' + $ErrorStack) | Out-File -FilePath $LogFile -Append }
- }
-
- } -ArgumentList $Global:ExcelCore, $Global:ExcelContent, $Global:Outages, $Global:SupportTickets, $Global:ServiceHealth, $Global:Retirements, $ExcelFile, $CustomerName, $WorkloadName, $PPTTemplateFile, $Global:PPTFinalFile, $WordTemplateFile, $Global:WordFinalFile, $Global:CoreDebugging, $Global:LogFile, $Global:Heavy
- }
- function Build-SummaryActionPlan {
- Param($ExcelContent,$ExcelRecommendations,$includeLow)
-
- $Recommendations = $ExcelContent | Where-Object {$_.impact -in ('High','Medium','Low')}
-
-<# if ($includeLow.IsPresent)
- {
- $Recommendations = $ExcelContent | Where-Object {$_.impact -in ('High','Medium','Low')}
- }
- else
- {
- $Recommendations = $ExcelContent | Where-Object {$_.impact -in ('High','Medium')}
- } #>
-
- $RecomCount = ($Recommendations.recommendationId | Select-Object -Unique).count
- if ($Debugging.IsPresent) { ('CSVProcess - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Creating CSV file for: '+$RecomCount+' recommendations') | Out-File -FilePath $LogFile -Append }
-
- $CXSummaryArray = Foreach ($Recommendation in $Recommendations)
- {
- $Description = $ExcelRecommendations | Where-Object {$_.'Recommendation Id' -eq $Recommendation.recommendationId}
- $tmp = [PSCustomObject]@{
- 'Recommendation Guid' = $Recommendation.recommendationId
- 'Recommendation Title' = $Recommendation.recommendationTitle
- 'Priority' = $Recommendation.impact
- 'Potential Benefits' = $Description.'Potential Benefits'
- 'Description' = $Description.'Best Practices Guidance'
- 'Resource ID' = $Recommendation.id
- 'Customer-facing annotation'= ''
- 'Internal-facing note' = ''
- }
- $tmp
- }
-
- return $CXSummaryArray
-
- }
-
- #Call the functions
- $Global:LogFile = ($PSScriptRoot + '\wara_reports_generator.log')
- $Global:Version = "2.1.7"
- Write-Host "Version: " -NoNewline
- Write-Host $Global:Version -ForegroundColor DarkBlue -NoNewline
- Write-Host " "
-
- if ($Debugging.IsPresent) { (' ---------------------------------- STARTING REPORT GENERATOR SCRIPT --------------------------------------- ') | Out-File -FilePath $LogFile -Append }
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Starting Report Generator Script..') | Out-File -FilePath $LogFile -Append }
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Script Version: ' + $Global:Version) | Out-File -FilePath $LogFile -Append }
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Excel File: ' + $ExcelFile) | Out-File -FilePath $LogFile -Append }
- if ($Debugging.IsPresent)
- {
- $ImportExcel = Get-Module -Name ImportExcel -ListAvailable -ErrorAction silentlycontinue
- foreach ($IExcel in $ImportExcel)
- {
- $IExcelPath = $IExcel.Path
- $IExcelVer = [string]$IExcel.Version
- ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - ImportExcel Module Path: ' + $IExcelPath) | Out-File -FilePath $LogFile -Append
- ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - ImportExcel Module Version: ' + $IExcelVer) | Out-File -FilePath $LogFile -Append
- }
- }
-
- if ($Help.IsPresent)
- {
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Help menu invoked..') | Out-File -FilePath $LogFile -Append }
- Get-HelpMessage
- Exit
- }
-
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "10% Complete." -PercentComplete 10
-
- Test-Requirement
-
- if ($Global:Heavy) {Start-Sleep -Milliseconds 20}
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "15% Complete." -PercentComplete 15
-
- Set-LocalFolder
-
- if ($Global:Heavy) {Start-Sleep -Milliseconds 20}
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "20% Complete." -PercentComplete 20
-
- Get-Excel
-
- if ($Global:Heavy) {Start-Sleep -Milliseconds 20}
-
- #Test-Excel -ExcelContent $Global:ExcelContent -byPassValidationStatus $byPassValidationStatus
-
- Write-Host "Editing " -NoNewline
- $Global:PPTFinalFile = ($PSScriptRoot + '\Executive Summary Presentation - ' + $CustomerName + ' - ' + (get-date -Format "yyyy-MM-dd-HH-mm") + '.pptx')
- if ($WordTemplateFile)
- {
- Write-Host "PowerPoint" -ForegroundColor DarkRed -NoNewline
- Write-Host " and " -NoNewline
- Write-Host "Word" -ForegroundColor DarkBlue -NoNewline
- Write-Host " "
- $Global:WordFinalFile = ($PSScriptRoot + '\Assessment Report - ' + $CustomerName + ' - ' + (get-date -Format "yyyy-MM-dd-HH-mm") + '.docx')
- }
- else
- {
- Write-Host "PowerPoint" -ForegroundColor DarkRed -NoNewline
- Write-Host " "
- }
-
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Calling Orchestrator function..') | Out-File -FilePath $LogFile -Append }
- Invoke-Orchestrator
- if ($Global:Heavy) {Start-Sleep -Milliseconds 100}
-
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Waiting for OfficeApps Job..') | Out-File -FilePath $LogFile -Append }
- while (Get-Job -Name 'OfficeApps' | Where-Object { $_.State -eq 'Running' })
- {
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "60% Complete." -PercentComplete 60
- Start-Sleep -Seconds 2
- }
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "80% Complete." -PercentComplete 80
-
- Get-Job -Name 'OfficeApps' | Remove-Job
-
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Trying to kill PowerPoint process.') }
- Get-Process -Name "POWERPNT" -ErrorAction Ignore | Where-Object { $_.CommandLine -like '*/automation*' } | Stop-Process
- if ($WordTemplateFile)
- {
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Trying to kill Word process..') | Out-File -FilePath $LogFile -Append }
- Get-Process -Name "WINWORD" -ErrorAction Ignore | Where-Object { $_.CommandLine -like '*/automation*' } | Stop-Process
- }
- if ($Debugging.IsPresent) { ('RootProces - ' + (get-date -Format 'yyyy-MM-dd HH:mm:ss') + ' - Info - Trying to kill Excel process..') | Out-File -FilePath $LogFile -Append }
- Get-Process -Name "excel" -ErrorAction Ignore | Where-Object { $_.CommandLine -like '*/automation*' } | Stop-Process
-
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "90% Complete." -PercentComplete 90
- }
-
-<# if($GenerateCSV.IsPresent)
- {
- $WorkloadRecommendationTemplate = Build-SummaryActionPlan -ExcelContent $ExcelContent -ExcelRecommendations $ExcelRecommendations -includeLow $includeLow
-
- $CSVFile = ($PSScriptRoot + '\Impacted Resources and Recommendations Template ' + (get-date -Format "yyyy-MM-dd-HH-mm") + '.csv')
-
- $WorkloadRecommendationTemplate | Export-Csv -Path $CSVFile
- } #>
-
- Write-Progress -Id 1 -activity "Processing Office Apps" -Status "100% Complete." -Completed
- $TotalTime = $Global:Runtime.Totalminutes.ToString('#######.##')
-
- ################ Finishing
-
- if ($Debugging.IsPresent) {Write-Debug "Debugging Log File: $Global:LogFile"}
- Write-Host "---------------------------------------------------------------------"
- Write-Host ('Execution Complete. Total Runtime was: ') -NoNewline
- Write-Host $TotalTime -NoNewline -ForegroundColor Cyan
- Write-Host (' Minutes')
- Write-Host 'PowerPoint File Saved As: ' -NoNewline
- Write-Host $PPTFinalFile -ForegroundColor Cyan
- if ($WordTemplateFile)
- {
- Write-Host 'Word File Saved As: ' -NoNewline
- Write-Host $WordFinalFile -ForegroundColor Cyan
- }
- if ($GenerateCSV.IsPresent)
- {
- Write-Host 'CSV File Saved as: ' -NoNewline
- Write-Host $CSVFile -ForegroundColor Cyan
- }
-
- Write-Host "---------------------------------------------------------------------"
diff --git a/tools/Mandatory - Executive Summary presentation - Template.pptx b/tools/Mandatory - Executive Summary presentation - Template.pptx
deleted file mode 100644
index 1c80d2e7f..000000000
Binary files a/tools/Mandatory - Executive Summary presentation - Template.pptx and /dev/null differ
diff --git a/tools/Version.json b/tools/Version.json
deleted file mode 100644
index 2c699ea3f..000000000
--- a/tools/Version.json
+++ /dev/null
@@ -1,8 +0,0 @@
-[
- {
-
- "Collector": "2.1.19",
- "Analyzer": "2.1.20",
- "Generator": "2.1.7"
- }
-]
diff --git a/tools/WARAinScopeResTypes.csv b/tools/WARAinScopeResTypes.csv
deleted file mode 100644
index 55e0c4566..000000000
--- a/tools/WARAinScopeResTypes.csv
+++ /dev/null
@@ -1,3862 +0,0 @@
-WARAinScope,ResourceType,FriendlyName,InAprlAndOrAdvisor
-yes,Microsoft.OperationalInsights/workspaces,Log Analytics,Yes
-no,Microsoft.OperationalInsights/querypacks,Log Analytics,No
-no,Microsoft.OperationalInsights/locations,Log Analytics,No
-no,Microsoft.OperationalInsights/locations/operationStatuses,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/scopedPrivateLinkProxies,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/api,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/query,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/metadata,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/purge,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/operations,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/dataSources,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/linkedStorageAccounts,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/tables,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/storageInsightConfigs,Log Analytics,No
-no,Microsoft.OperationalInsights/storageInsightConfigs,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/linkedServices,Log Analytics,No
-no,Microsoft.OperationalInsights/linkTargets,Log Analytics,No
-no,Microsoft.OperationalInsights/deletedWorkspaces,Log Analytics,No
-no,Microsoft.OperationalInsights/operations,Log Analytics,No
-no,Microsoft.OperationalInsights/clusters,Log Analytics,No
-no,Microsoft.OperationalInsights/workspaces/dataExports,Log Analytics,No
-no,Microsoft.OperationalInsights/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,Log Analytics,No
-yes,microsoft.insights/components,Application Insights,Yes
-no,microsoft.insights/components/query,Application Insights,No
-no,microsoft.insights/components/metadata,Application Insights,No
-no,microsoft.insights/components/metrics,Application Insights,No
-no,microsoft.insights/components/events,Application Insights,No
-no,microsoft.insights/components/syntheticmonitorlocations,Application Insights,No
-no,microsoft.insights/components/analyticsItems,Application Insights,No
-no,microsoft.insights/components/webtests,Application Insights,No
-no,microsoft.insights/components/workItemConfigs,Application Insights,No
-no,microsoft.insights/components/myFavorites,Application Insights,No
-no,microsoft.insights/components/operations,Application Insights,No
-no,microsoft.insights/components/exportConfiguration,Application Insights,No
-no,microsoft.insights/components/purge,Application Insights,No
-no,microsoft.insights/components/api,Application Insights,No
-no,microsoft.insights/components/aggregate,Application Insights,No
-no,microsoft.insights/components/metricDefinitions,Application Insights,No
-no,microsoft.insights/components/extendQueries,Application Insights,No
-no,microsoft.insights/components/apiKeys,Application Insights,No
-no,microsoft.insights/components/myAnalyticsItems,Application Insights,No
-no,microsoft.insights/components/favorites,Application Insights,No
-no,microsoft.insights/components/defaultWorkItemConfig,Application Insights,No
-no,microsoft.insights/components/annotations,Application Insights,No
-no,microsoft.insights/components/proactiveDetectionConfigs,Application Insights,No
-no,microsoft.insights/components/move,Application Insights,No
-no,microsoft.insights/components/currentBillingFeatures,Application Insights,No
-no,microsoft.insights/components/quotaStatus,Application Insights,No
-no,microsoft.insights/components/featureCapabilities,Application Insights,No
-no,microsoft.insights/components/getAvailableBillingFeatures,Application Insights,No
-no,microsoft.insights/webtests,Application Insights,No
-no,microsoft.insights/webtests/getTestResultFile,Application Insights,No
-no,microsoft.insights/scheduledqueryrules,Alert Rule,Yes
-no,microsoft.insights/scheduledqueryrules/networkSecurityPerimeterAssociationProxies,null,No
-no,microsoft.insights/scheduledqueryrules/networkSecurityPerimeterConfigurations,null,No
-no,microsoft.insights/components/pricingPlans,null,No
-no,microsoft.insights/migrateToNewPricingModel,null,No
-no,microsoft.insights/rollbackToLegacyPricingModel,null,No
-no,microsoft.insights/listMigrationdate,null,No
-no,microsoft.insights/logprofiles,null,No
-no,microsoft.insights/migratealertrules,null,No
-no,microsoft.insights/metricalerts,Metric Alerts,No
-no,microsoft.insights/alertrules,Alert Rules,No
-no,microsoft.insights/autoscalesettings,Auto Scale Settings,No
-no,microsoft.insights/eventtypes,null,No
-no,microsoft.insights/locations,null,No
-no,microsoft.insights/locations/operationResults,null,No
-no,microsoft.insights/vmInsightsOnboardingStatuses,VM Insights Onboarding,No
-no,microsoft.insights/operations,null,No
-no,microsoft.insights/diagnosticSettings,Diagnostic Settings,No
-no,microsoft.insights/diagnosticSettingsCategories,null,No
-no,microsoft.insights/extendedDiagnosticSettings,null,No
-no,microsoft.insights/metricDefinitions,null,No
-no,microsoft.insights/logDefinitions,null,No
-no,microsoft.insights/eventCategories,null,No
-no,microsoft.insights/metrics,null,No
-no,microsoft.insights/metricbatch,null,No
-no,microsoft.insights/metricNamespaces,null,No
-no,microsoft.insights/notificationstatus,null,No
-no,microsoft.insights/createnotifications,null,No
-no,microsoft.insights/tenantactiongroups,null,No
-no,microsoft.insights/actiongroups,Action Groups,No
-yes,microsoft.insights/activityLogAlerts,Activity Log Alerts,Yes
-no,microsoft.insights/metricbaselines,null,No
-no,microsoft.insights/workbooks,null,No
-no,microsoft.insights/workbooktemplates,null,No
-no,microsoft.insights/myWorkbooks,null,No
-no,microsoft.insights/logs,null,No
-no,microsoft.insights/transactions,null,No
-no,microsoft.insights/topology,null,No
-no,microsoft.insights/generateLiveToken,null,No
-no,microsoft.insights/monitoredObjects,null,No
-no,microsoft.insights/dataCollectionRules,null,No
-no,microsoft.insights/dataCollectionRuleAssociations,null,No
-no,microsoft.insights/dataCollectionEndpoints,null,No
-no,microsoft.insights/dataCollectionEndpoints/scopedPrivateLinkProxies,null,No
-no,microsoft.insights/actiongroups/networkSecurityPerimeterAssociationProxies,null,No
-no,microsoft.insights/actiongroups/networkSecurityPerimeterConfigurations,null,No
-no,microsoft.insights/dataCollectionEndpoints/networkSecurityPerimeterAssociationProxies,null,No
-no,microsoft.insights/dataCollectionEndpoints/networkSecurityPerimeterConfigurations,null,No
-no,microsoft.insights/privateLinkScopes,Private Link Scopes,No
-no,microsoft.insights/privateLinkScopes/privateEndpointConnections,null,No
-no,microsoft.insights/privateLinkScopes/privateEndpointConnectionProxies,null,No
-no,microsoft.insights/privateLinkScopes/scopedResources,null,No
-no,microsoft.insights/components/linkedstorageaccounts,null,No
-no,microsoft.insights/privateLinkScopeOperationStatuses,null,No
-no,microsoft.insights/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.AlertsManagement/alerts,Alerts,No
-no,Microsoft.AlertsManagement/alertsSummary,null,No
-no,Microsoft.AlertsManagement/smartGroups,null,No
-no,Microsoft.AlertsManagement/smartDetectorAlertRules,Smart Detector Alert Rules,No
-no,Microsoft.AlertsManagement/migrateFromSmartDetection,null,No
-no,Microsoft.AlertsManagement/actionRules,Action Rules,No
-no,Microsoft.AlertsManagement/alertsMetaData,null,No
-no,Microsoft.AlertsManagement/prometheusRuleGroups,null,No
-no,Microsoft.AlertsManagement/operations,null,No
-no,Microsoft.AlertsManagement/alertRuleRecommendations,null,No
-no,Microsoft.AlertsManagement/tenantActivityLogAlerts,null,No
-no,Microsoft.AlertsManagement/investigations,null,No
-yes,Microsoft.CognitiveServices/accounts,Cognitive Service,Yes
-no,Microsoft.CognitiveServices/operations,null,No
-no,Microsoft.CognitiveServices/locations/operationResults,null,No
-no,Microsoft.CognitiveServices/locations,null,No
-no,Microsoft.CognitiveServices/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.CognitiveServices/locations/checkSkuAvailability,null,No
-no,Microsoft.CognitiveServices/checkDomainAvailability,null,No
-no,Microsoft.CognitiveServices/accounts/privateLinkResources,null,No
-no,Microsoft.CognitiveServices/accounts/privateEndpointConnections,null,No
-no,Microsoft.CognitiveServices/accounts/privateEndpointConnectionProxies,null,No
-no,Microsoft.CognitiveServices/deletedAccounts,null,No
-no,Microsoft.CognitiveServices/locations/resourceGroups,null,No
-no,Microsoft.CognitiveServices/locations/resourceGroups/deletedAccounts,null,No
-no,Microsoft.CognitiveServices/locations/commitmentTiers,null,No
-no,Microsoft.CognitiveServices/locations/models,null,No
-no,Microsoft.CognitiveServices/locations/usages,null,No
-no,Microsoft.CognitiveServices/locations/raiContentFilters,null,No
-no,Microsoft.CognitiveServices/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.CognitiveServices/accounts/networkSecurityPerimeterAssociationProxies,null,No
-no,Microsoft.CognitiveServices/accounts/encryptionScopes,null,No
-no,Microsoft.CognitiveServices/commitmentPlans,null,No
-no,Microsoft.CognitiveServices/attestations,null,No
-no,Microsoft.CognitiveServices/attestationDefinitions,null,No
-no,Microsoft.Blueprint/blueprints,null,No
-no,Microsoft.Blueprint/blueprints/artifacts,null,No
-no,Microsoft.Blueprint/blueprints/versions,null,No
-no,Microsoft.Blueprint/blueprints/versions/artifacts,null,No
-no,Microsoft.Blueprint/blueprintAssignments,null,No
-no,Microsoft.Blueprint/blueprintAssignments/operations,null,No
-no,Microsoft.Blueprint/blueprintAssignments/assignmentOperations,null,No
-no,Microsoft.Blueprint/operations,null,No
-no,Microsoft.ManagedIdentity/Identities,null,No
-no,Microsoft.ManagedIdentity/userAssignedIdentities,null,No
-no,Microsoft.ManagedIdentity/operations,null,No
-no,Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials,null,No
-yes,Microsoft.Network/virtualNetworkGateways,Virtual Network Gateways,Yes
-no,Microsoft.Network/localNetworkGateways,Local Network Gateways,No
-yes,Microsoft.Network/connections,Connections,Yes
-yes,Microsoft.Network/applicationGateways,Application Gateway,Yes
-yes,Microsoft.Network/expressRouteCircuits,Expressroute Circuits,Yes
-no,Microsoft.Network/expressRouteServiceProviders,null,No
-no,Microsoft.Network/applicationGatewayAvailableWafRuleSets,null,No
-no,Microsoft.Network/applicationGatewayAvailableSslOptions,null,No
-no,Microsoft.Network/applicationGatewayAvailableServerVariables,null,No
-no,Microsoft.Network/applicationGatewayAvailableRequestHeaders,null,No
-no,Microsoft.Network/applicationGatewayAvailableResponseHeaders,null,No
-no,Microsoft.Network/routeFilters,null,No
-no,Microsoft.Network/bgpServiceCommunities,null,No
-yes,Microsoft.Network/vpnSites,VPN Sites,No
-yes,Microsoft.Network/vpnServerConfigurations,VPN Server Configurations,No
-yes,Microsoft.Network/virtualHubs,Virtual Hubs,Yes
-yes,Microsoft.Network/vpnGateways,VPN Gateways,Yes
-yes,Microsoft.Network/p2sVpnGateways,P2S Gateways,Yes
-yes,Microsoft.Network/expressRouteGateways,ExpressRoute Gateways,Yes
-no,Microsoft.Network/expressRoutePortsLocations,null,No
-yes,Microsoft.Network/expressRoutePorts,Expressroute Direct,Yes
-no,Microsoft.Network/securityPartnerProviders,null,No
-yes,Microsoft.Network/azureFirewalls,Firewall,Yes
-no,Microsoft.Network/azureFirewallFqdnTags,null,No
-yes,Microsoft.Network/applicationGatewayWebApplicationFirewallPolicies,Application Gateway Web Application Firewall Policy,Yes
-no,Microsoft.Network/locations/ApplicationGatewayWafDynamicManifests,null,No
-yes,Microsoft.Network/virtualWans,Virtual WANs,No
-no,Microsoft.Network/bastionHosts,null,No
-no,Microsoft.Network/queryExpressRoutePortsBandwidth,null,No
-yes,Microsoft.Network/trafficmanagerprofiles,Traffic Manager,Yes
-no,Microsoft.Network/trafficmanagerprofiles/heatMaps,null,No
-no,Microsoft.Network/trafficmanagerprofiles/azureendpoints,null,No
-no,Microsoft.Network/trafficmanagerprofiles/externalendpoints,null,No
-no,Microsoft.Network/trafficmanagerprofiles/nestedendpoints,null,No
-no,Microsoft.Network/checkTrafficManagerNameAvailability,null,No
-no,Microsoft.Network/checkTrafficManagerNameAvailabilityV2,null,No
-no,Microsoft.Network/trafficManagerUserMetricsKeys,null,No
-no,Microsoft.Network/trafficManagerGeographicHierarchies,null,No
-yes,Microsoft.Network/expressRouteProviderPorts,ExpressRoute Provider Ports,No
-no,Microsoft.Network/locations/hybridEdgeZone,null,No
-yes,Microsoft.Network/firewallPolicies,Firewall Policies,Yes
-no,Microsoft.Network/ipGroups,null,No
-no,Microsoft.Network/azureWebCategories,null,No
-no,Microsoft.Network/locations/nfvOperations,null,No
-no,Microsoft.Network/locations/nfvOperationResults,null,No
-yes,Microsoft.Network/virtualRouters,Virtual Routers,Yes
-no,Microsoft.Network/networkVirtualAppliances,null,No
-no,Microsoft.Network/networkVirtualApplianceSkus,null,No
-no,Microsoft.Network/frontdoorOperationResults,null,No
-no,Microsoft.Network/checkFrontdoorNameAvailability,null,No
-yes,Microsoft.Network/frontdoors,Front door,Yes
-no,Microsoft.Network/frontdoors/frontendEndpoints,null,No
-no,Microsoft.Network/frontdoors/frontendEndpoints/customHttpsConfiguration,null,No
-yes,Microsoft.Network/frontdoorWebApplicationFirewallPolicies,Web Application Firewall,Yes
-no,Microsoft.Network/frontdoorWebApplicationFirewallManagedRuleSets,null,No
-no,Microsoft.Network/networkExperimentProfiles,null,No
-yes,Microsoft.Network/dnsResolvers,DNS Resolvers,No
-no,Microsoft.Network/dnsResolvers/inboundEndpoints,null,No
-no,Microsoft.Network/dnsResolvers/outboundEndpoints,null,No
-no,Microsoft.Network/dnsForwardingRulesets,DNS Forwarding Rule Sets,No
-no,Microsoft.Network/dnsForwardingRulesets/forwardingRules,null,No
-no,Microsoft.Network/dnsForwardingRulesets/virtualNetworkLinks,null,No
-no,Microsoft.Network/virtualNetworks/listDnsResolvers,null,No
-no,Microsoft.Network/virtualNetworks/listDnsForwardingRulesets,null,No
-no,Microsoft.Network/locations/dnsResolverOperationResults,null,No
-no,Microsoft.Network/locations/dnsResolverOperationStatuses,null,No
-no,Microsoft.Network/locations/dnsResolverPolicyOperationResults,null,No
-no,Microsoft.Network/locations/dnsResolverPolicyOperationStatuses,null,No
-no,Microsoft.Network/networkManagers,Network Managers,No
-no,Microsoft.Network/networkManagerConnections,null,No
-no,Microsoft.Network/networkSecurityPerimeters,null,No
-no,Microsoft.Network/locations/perimeterAssociableResourceTypes,null,No
-no,Microsoft.Network/locations/queryNetworkSecurityPerimeter,null,No
-no,Microsoft.Network/virtualNetworks/listNetworkManagerEffectiveConnectivityConfigurations,null,No
-no,Microsoft.Network/virtualNetworks/listNetworkManagerEffectiveSecurityAdminRules,null,No
-no,Microsoft.Network/networkGroupMemberships,null,No
-no,Microsoft.Network/locations/commitInternalAzureNetworkManagerConfiguration,null,No
-no,Microsoft.Network/locations/internalAzureVirtualNetworkManagerOperation,null,No
-yes,Microsoft.Network/privateDnsZones,Private Dns Zones,Yes
-no,Microsoft.Network/privateDnsZones/virtualNetworkLinks,null,No
-no,Microsoft.Network/privateDnsOperationResults,null,No
-no,Microsoft.Network/privateDnsOperationStatuses,null,No
-no,Microsoft.Network/privateDnsZonesInternal,null,No
-no,Microsoft.Network/privateDnsZones/A,null,No
-no,Microsoft.Network/privateDnsZones/AAAA,null,No
-no,Microsoft.Network/privateDnsZones/CNAME,null,No
-no,Microsoft.Network/privateDnsZones/PTR,null,No
-no,Microsoft.Network/privateDnsZones/MX,null,No
-no,Microsoft.Network/privateDnsZones/TXT,null,No
-no,Microsoft.Network/privateDnsZones/SRV,null,No
-no,Microsoft.Network/privateDnsZones/SOA,null,No
-no,Microsoft.Network/privateDnsZones/all,null,No
-no,Microsoft.Network/virtualNetworks/privateDnsZoneLinks,null,No
-yes,Microsoft.Network/dnszones,DNS Zones,Yes
-no,Microsoft.Network/dnsOperationResults,null,No
-no,Microsoft.Network/dnsOperationStatuses,null,No
-no,Microsoft.Network/getDnsResourceReference,null,No
-no,Microsoft.Network/internalNotify,null,No
-no,Microsoft.Network/dnszones/A,null,No
-no,Microsoft.Network/dnszones/AAAA,null,No
-no,Microsoft.Network/dnszones/CNAME,null,No
-no,Microsoft.Network/dnszones/PTR,null,No
-no,Microsoft.Network/dnszones/MX,null,No
-no,Microsoft.Network/dnszones/TXT,null,No
-no,Microsoft.Network/dnszones/SRV,null,No
-no,Microsoft.Network/dnszones/SOA,null,No
-no,Microsoft.Network/dnszones/NS,null,No
-no,Microsoft.Network/dnszones/CAA,null,No
-no,Microsoft.Network/dnszones/DS,null,No
-no,Microsoft.Network/dnszones/TLSA,null,No
-no,Microsoft.Network/dnszones/NAPTR,null,No
-no,Microsoft.Network/dnszones/recordsets,null,No
-no,Microsoft.Network/dnszones/all,null,No
-no,Microsoft.Network/dnszones/dnssecConfigs,null,No
-yes,Microsoft.Network/virtualNetworks,Virtual Network,Yes
-no,Microsoft.Network/virtualNetworks/taggedTrafficConsumers,null,No
-yes,Microsoft.Network/natGateways,NAT Gateways,Yes
-yes,Microsoft.Network/publicIPAddresses,Public IP address,Yes
-no,Microsoft.Network/internalPublicIpAddresses,null,No
-no,Microsoft.Network/customIpPrefixes,null,No
-no,Microsoft.Network/networkInterfaces,null,No
-no,Microsoft.Network/dscpConfigurations,null,No
-yes,Microsoft.Network/privateEndpoints,Private Endpoints,Yes
-no,Microsoft.Network/privateEndpoints/privateLinkServiceProxies,null,No
-no,Microsoft.Network/privateEndpointRedirectMaps,null,No
-yes,Microsoft.Network/loadBalancers,Load Balancer,Yes
-yes,Microsoft.Network/networkSecurityGroups,Network Security Group,Yes
-no,Microsoft.Network/applicationSecurityGroups,Application Security Group,No
-no,Microsoft.Network/serviceEndpointPolicies,null,No
-no,Microsoft.Network/networkIntentPolicies,null,No
-yes,Microsoft.Network/routeTables,Route Table,Yes
-no,Microsoft.Network/publicIPPrefixes,Public IP Prefixes,No
-yes,Microsoft.Network/networkWatchers,Network Watcher,Yes
-no,Microsoft.Network/networkWatchers/connectionMonitors,null,No
-yes,Microsoft.Network/networkWatchers/flowLogs,Flow Log,Yes
-no,Microsoft.Network/networkWatchers/pingMeshes,null,No
-no,Microsoft.Network/locations,null,No
-no,Microsoft.Network/locations/operations,null,No
-no,Microsoft.Network/locations/operationResults,null,No
-no,Microsoft.Network/locations/CheckDnsNameAvailability,null,No
-no,Microsoft.Network/locations/setLoadBalancerFrontendPublicIpAddresses,null,No
-no,Microsoft.Network/cloudServiceSlots,null,No
-no,Microsoft.Network/locations/usages,null,No
-no,Microsoft.Network/locations/virtualNetworkAvailableEndpointServices,null,No
-no,Microsoft.Network/locations/availableDelegations,null,No
-no,Microsoft.Network/locations/serviceTags,null,No
-no,Microsoft.Network/locations/availablePrivateEndpointTypes,null,No
-no,Microsoft.Network/locations/availableServiceAliases,null,No
-no,Microsoft.Network/locations/checkPrivateLinkServiceVisibility,null,No
-no,Microsoft.Network/locations/autoApprovedPrivateLinkServices,null,No
-no,Microsoft.Network/locations/batchValidatePrivateEndpointsForResourceMove,null,No
-no,Microsoft.Network/locations/batchNotifyPrivateEndpointsForResourceMove,null,No
-no,Microsoft.Network/locations/supportedVirtualMachineSizes,null,No
-no,Microsoft.Network/locations/setAzureNetworkManagerConfiguration,null,No
-no,Microsoft.Network/locations/publishResources,null,No
-no,Microsoft.Network/locations/getAzureNetworkManagerConfiguration,null,No
-no,Microsoft.Network/locations/checkAcceleratedNetworkingSupport,null,No
-no,Microsoft.Network/locations/validateResourceOwnership,null,No
-no,Microsoft.Network/locations/setResourceOwnership,null,No
-no,Microsoft.Network/locations/effectiveResourceOwnership,null,No
-no,Microsoft.Network/operations,null,No
-no,Microsoft.Network/virtualNetworkTaps,null,No
-yes,Microsoft.Network/privateLinkServices,Private Link Services,No
-no,Microsoft.Network/locations/privateLinkServices,null,No
-yes,Microsoft.Network/ddosProtectionPlans,Ddos Protection Plans,Yes
-no,Microsoft.Network/networkProfiles,null,No
-no,Microsoft.Network/locations/bareMetalTenants,null,No
-no,Microsoft.Network/ipAllocations,null,No
-no,Microsoft.Network/locations/serviceTagDetails,null,No
-no,Microsoft.Network/locations/dataTasks,null,No
-no,Microsoft.Network/locations/startPacketTagging,null,No
-no,Microsoft.Network/locations/deletePacketTagging,null,No
-no,Microsoft.Network/locations/getPacketTagging,null,No
-no,Microsoft.Network/locations/rnmEffectiveRouteTable,null,No
-no,Microsoft.Network/locations/rnmEffectiveNetworkSecurityGroups,null,No
-no,Microsoft.PolicyInsights/policyEvents,null,No
-no,Microsoft.PolicyInsights/policyStates,null,No
-no,Microsoft.PolicyInsights/componentPolicyStates,null,No
-no,Microsoft.PolicyInsights/operations,null,No
-no,Microsoft.PolicyInsights/asyncOperationResults,null,No
-no,Microsoft.PolicyInsights/remediations,null,No
-no,Microsoft.PolicyInsights/attestations,null,No
-no,Microsoft.PolicyInsights/eventGridFilters,null,No
-no,Microsoft.PolicyInsights/checkPolicyRestrictions,null,No
-no,Microsoft.PolicyInsights/policyTrackedResources,null,No
-no,Microsoft.PolicyInsights/policyMetadata,null,No
-no,Microsoft.Storage/storageAccounts/storageTaskAssignments,null,No
-no,Microsoft.Storage/storageAccounts/encryptionScopes,null,No
-no,Microsoft.Storage/deletedAccounts,null,No
-no,Microsoft.Storage/locations/deletedAccounts,null,No
-yes,Microsoft.Storage/storageAccounts,Storage Account,Yes
-no,Microsoft.Storage/storageTasks,null,No
-no,Microsoft.Storage/operations,null,No
-no,Microsoft.Storage/locations/asyncoperations,null,No
-no,Microsoft.Storage/storageAccounts/listAccountSas,null,No
-no,Microsoft.Storage/storageAccounts/listServiceSas,null,No
-no,Microsoft.Storage/storageAccounts/blobServices,null,No
-no,Microsoft.Storage/storageAccounts/tableServices,null,No
-no,Microsoft.Storage/storageAccounts/queueServices,null,No
-no,Microsoft.Storage/storageAccounts/fileServices,null,No
-no,Microsoft.Storage/locations,null,No
-no,Microsoft.Storage/locations/usages,null,No
-no,Microsoft.Storage/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.Storage/usages,null,No
-no,Microsoft.Storage/checkNameAvailability,null,No
-no,Microsoft.Storage/locations/checkNameAvailability,null,No
-no,Microsoft.Storage/storageAccounts/services,null,No
-no,Microsoft.Storage/storageAccounts/services/metricDefinitions,null,No
-no,Microsoft.Storage/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-yes,Microsoft.KeyVault/vaults,Key Vault,Yes
-no,Microsoft.KeyVault/vaults/secrets,null,No
-no,Microsoft.KeyVault/vaults/accessPolicies,null,No
-no,Microsoft.KeyVault/operations,null,No
-no,Microsoft.KeyVault/checkNameAvailability,null,No
-no,Microsoft.KeyVault/deletedVaults,null,No
-no,Microsoft.KeyVault/locations,null,No
-no,Microsoft.KeyVault/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.KeyVault/locations/deletedVaults,null,No
-no,Microsoft.KeyVault/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.KeyVault/locations/operationResults,null,No
-no,Microsoft.KeyVault/vaults/eventGridFilters,null,No
-yes,Microsoft.KeyVault/managedHSMs,Managed HSM Service,Yes
-no,Microsoft.KeyVault/deletedManagedHSMs,null,No
-no,Microsoft.KeyVault/locations/deletedManagedHSMs,null,No
-no,Microsoft.KeyVault/locations/managedHsmOperationResults,null,No
-no,Microsoft.KeyVault/managedHSMs/keys,null,No
-no,Microsoft.KeyVault/managedHSMs/keys/versions,null,No
-no,Microsoft.KeyVault/checkMhsmNameAvailability,null,No
-no,Microsoft.KeyVault/vaults/keys,null,No
-no,Microsoft.KeyVault/vaults/keys/versions,null,No
-no,Microsoft.Sql/operations,null,No
-no,Microsoft.Sql/locations,null,No
-no,Microsoft.Sql/locations/capabilities,null,No
-no,Microsoft.Sql/locations/databaseAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/databaseOperationResults,null,No
-no,Microsoft.Sql/locations/databaseEncryptionProtectorRevalidateAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/databaseEncryptionProtectorRevalidateOperationResults,null,No
-no,Microsoft.Sql/locations/databaseEncryptionProtectorRevertAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/databaseEncryptionProtectorRevertOperationResults,null,No
-no,Microsoft.Sql/locations/serverKeyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/serverKeyOperationResults,null,No
-no,Microsoft.Sql/servers/keys,null,No
-no,Microsoft.Sql/servers/encryptionProtector,null,No
-no,Microsoft.Sql/locations/encryptionProtectorOperationResults,null,No
-no,Microsoft.Sql/locations/encryptionProtectorAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/externalPolicyBasedAuthorizationsAzureAsycOperation,null,No
-no,Microsoft.Sql/locations/externalPolicyBasedAuthorizationsOperationResults,null,No
-no,Microsoft.Sql/locations/refreshExternalGovernanceStatusOperationResults,null,No
-no,Microsoft.Sql/locations/refreshExternalGovernanceStatusAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/refreshExternalGovernanceStatusMIOperationResults,null,No
-no,Microsoft.Sql/locations/refreshExternalGovernanceStatusMIAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedInstanceKeyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedInstanceKeyOperationResults,null,No
-no,Microsoft.Sql/locations/managedInstanceEncryptionProtectorOperationResults,null,No
-no,Microsoft.Sql/locations/managedInstanceEncryptionProtectorAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/transparentDataEncryptionAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/transparentDataEncryptionOperationResults,null,No
-no,Microsoft.Sql/locations/managedtransparentDataEncryptionAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedtransparentDataEncryptionOperationResults,null,No
-no,Microsoft.Sql/servers/tdeCertificates,null,No
-no,Microsoft.Sql/locations/tdeCertAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/tdeCertOperationResults,null,No
-no,Microsoft.Sql/locations/serverAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/serverOperationResults,null,No
-no,Microsoft.Sql/locations/usages,null,No
-no,Microsoft.Sql/checkNameAvailability,null,No
-yes,Microsoft.Sql/servers,Sqldb,Yes
-yes,Microsoft.Sql/servers/databases,SQL database,Yes
-no,Microsoft.Sql/servers/serviceObjectives,null,No
-no,Microsoft.Sql/servers/communicationLinks,null,No
-no,Microsoft.Sql/servers/administrators,null,No
-no,Microsoft.Sql/servers/administratorOperationResults,null,No
-no,Microsoft.Sql/locations/serverAdministratorAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/serverAdministratorOperationResults,null,No
-no,Microsoft.Sql/servers/restorableDroppedDatabases,null,No
-no,Microsoft.Sql/servers/recoverableDatabases,null,No
-no,Microsoft.Sql/servers/databases/geoBackupPolicies,null,No
-no,Microsoft.Sql/servers/import,null,No
-no,Microsoft.Sql/servers/importExportOperationResults,null,No
-no,Microsoft.Sql/servers/operationResults,null,No
-no,Microsoft.Sql/servers/databases/backupLongTermRetentionPolicies,null,No
-no,Microsoft.Sql/servers/databases/backupShortTermRetentionPolicies,null,No
-no,Microsoft.Sql/servers/databaseSecurityPolicies,null,No
-no,Microsoft.Sql/servers/automaticTuning,null,No
-no,Microsoft.Sql/servers/databases/automaticTuning,null,No
-no,Microsoft.Sql/servers/databases/transparentDataEncryption,null,No
-no,Microsoft.Sql/servers/databases/ledgerDigestUploads,null,No
-no,Microsoft.Sql/locations/ledgerDigestUploadsAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/ledgerDigestUploadsOperationResults,null,No
-no,Microsoft.Sql/servers/recommendedElasticPools,null,No
-no,Microsoft.Sql/servers/databases/dataMaskingPolicies,null,No
-no,Microsoft.Sql/servers/databases/dataMaskingPolicies/rules,null,No
-no,Microsoft.Sql/servers/databases/securityAlertPolicies,null,No
-no,Microsoft.Sql/servers/securityAlertPolicies,null,No
-no,Microsoft.Sql/servers/databases/advancedThreatProtectionSettings,null,No
-no,Microsoft.Sql/servers/advancedThreatProtectionSettings,null,No
-no,Microsoft.Sql/managedInstances/databases/advancedThreatProtectionSettings,null,No
-no,Microsoft.Sql/managedInstances/advancedThreatProtectionSettings,null,No
-no,Microsoft.Sql/servers/databases/auditingSettings,null,No
-no,Microsoft.Sql/servers/auditingSettings,null,No
-no,Microsoft.Sql/servers/extendedAuditingSettings,null,No
-no,Microsoft.Sql/servers/devOpsAuditingSettings,null,No
-no,Microsoft.Sql/locations/auditingSettingsAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/auditingSettingsOperationResults,null,No
-no,Microsoft.Sql/locations/extendedAuditingSettingsAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/extendedAuditingSettingsOperationResults,null,No
-no,Microsoft.Sql/locations/devOpsAuditingSettingsOperationResults,null,No
-no,Microsoft.Sql/locations/devOpsAuditingSettingsAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/elasticPoolAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/elasticPoolOperationResults,null,No
-no,Microsoft.Sql/servers/elasticpools,null,No
-no,Microsoft.Sql/servers/jobAccounts,null,No
-no,Microsoft.Sql/servers/jobAgents,null,No
-no,Microsoft.Sql/locations/jobAgentOperationResults,null,No
-no,Microsoft.Sql/locations/jobAgentAzureAsyncOperation,null,No
-no,Microsoft.Sql/servers/jobAgents/privateEndpoints,null,No
-no,Microsoft.Sql/locations/jobAgentPrivateEndpointOperationResults,null,No
-no,Microsoft.Sql/locations/jobAgentPrivateEndpointAzureAsyncOperation,null,No
-no,Microsoft.Sql/servers/jobAgents/jobs,null,No
-no,Microsoft.Sql/servers/jobAgents/jobs/steps,null,No
-no,Microsoft.Sql/servers/jobAgents/jobs/executions,null,No
-no,Microsoft.Sql/servers/disasterRecoveryConfiguration,null,No
-no,Microsoft.Sql/servers/dnsAliases,null,No
-no,Microsoft.Sql/locations/dnsAliasAsyncOperation,null,No
-no,Microsoft.Sql/locations/dnsAliasOperationResults,null,No
-no,Microsoft.Sql/servers/failoverGroups,null,No
-no,Microsoft.Sql/locations/failoverGroupAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/failoverGroupOperationResults,null,No
-no,Microsoft.Sql/locations/firewallRulesOperationResults,null,No
-no,Microsoft.Sql/locations/firewallRulesAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/ipv6FirewallRulesOperationResults,null,No
-no,Microsoft.Sql/locations/ipv6FirewallRulesAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.Sql/servers/virtualNetworkRules,null,No
-no,Microsoft.Sql/locations/virtualNetworkRulesOperationResults,null,No
-no,Microsoft.Sql/locations/virtualNetworkRulesAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/deleteVirtualNetworkOrSubnetsOperationResults,null,No
-no,Microsoft.Sql/locations/deleteVirtualNetworkOrSubnetsAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/databaseRestoreAzureAsyncOperation,null,No
-no,Microsoft.Sql/servers/usages,null,No
-no,Microsoft.Sql/servers/databases/metricDefinitions,null,No
-no,Microsoft.Sql/servers/databases/metrics,null,No
-no,Microsoft.Sql/servers/aggregatedDatabaseMetrics,null,No
-no,Microsoft.Sql/servers/elasticpools/metrics,null,No
-no,Microsoft.Sql/servers/elasticpools/metricdefinitions,null,No
-no,Microsoft.Sql/servers/databases/topQueries,null,No
-no,Microsoft.Sql/servers/databases/topQueries/queryText,null,No
-no,Microsoft.Sql/servers/advisors,null,No
-no,Microsoft.Sql/servers/elasticPools/advisors,null,No
-no,Microsoft.Sql/servers/databases/advisors,null,No
-no,Microsoft.Sql/servers/databases/extensions,null,No
-no,Microsoft.Sql/servers/elasticPoolEstimates,null,No
-no,Microsoft.Sql/servers/databases/auditRecords,null,No
-no,Microsoft.Sql/servers/databases/VulnerabilityAssessmentScans,null,No
-no,Microsoft.Sql/servers/databases/workloadGroups,null,No
-no,Microsoft.Sql/servers/databases/vulnerabilityAssessments,null,No
-no,Microsoft.Sql/servers/vulnerabilityAssessments,null,No
-no,Microsoft.Sql/managedInstances/databases/vulnerabilityAssessments,null,No
-no,Microsoft.Sql/managedInstances/vulnerabilityAssessments,null,No
-no,Microsoft.Sql/servers/databases/VulnerabilityAssessmentSettings,null,No
-no,Microsoft.Sql/servers/databases/VulnerabilityAssessment,null,No
-no,Microsoft.Sql/locations/vulnerabilityAssessmentScanAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/vulnerabilityAssessmentScanOperationResults,null,No
-no,Microsoft.Sql/servers/databases/sqlvulnerabilityassessments,null,No
-no,Microsoft.Sql/servers/sqlvulnerabilityassessments,null,No
-no,Microsoft.Sql/locations/sqlVulnerabilityAssessmentAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/sqlVulnerabilityAssessmentOperationResults,null,No
-no,Microsoft.Sql/servers/databases/recommendedSensitivityLabels,null,No
-no,Microsoft.Sql/servers/databases/syncGroups,null,No
-no,Microsoft.Sql/servers/databases/syncGroups/syncMembers,null,No
-no,Microsoft.Sql/servers/syncAgents,null,No
-yes,Microsoft.Sql/instancePools,SQL Instance Pools,No
-no,Microsoft.Sql/locations/importExportOperationResults,null,No
-no,Microsoft.Sql/locations/importExportAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/instancePoolOperationResults,null,No
-no,Microsoft.Sql/locations/instancePoolAzureAsyncOperation,null,No
-yes,Microsoft.Sql/managedInstances,SQL managed instance,Yes
-no,Microsoft.Sql/managedInstances/administrators,null,No
-no,Microsoft.Sql/managedInstances/databases,null,No
-no,Microsoft.Sql/managedInstances/recoverableDatabases,null,No
-no,Microsoft.Sql/managedInstances/metrics,null,No
-no,Microsoft.Sql/managedInstances/metricDefinitions,null,No
-no,Microsoft.Sql/managedInstances/databases/backupLongTermRetentionPolicies,null,No
-no,Microsoft.Sql/managedInstances/sqlAgent,null,No
-no,Microsoft.Sql/managedInstances/startStopSchedules,null,No
-no,Microsoft.Sql/locations/managedInstancePrivateEndpointConnectionProxyOperationResults,null,No
-no,Microsoft.Sql/locations/managedInstancePrivateEndpointConnectionProxyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedInstancePrivateEndpointConnectionOperationResults,null,No
-no,Microsoft.Sql/locations/managedInstancePrivateEndpointConnectionAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/longTermRetentionManagedInstances,null,No
-no,Microsoft.Sql/locations/longTermRetentionManagedInstanceBackups,null,No
-no,Microsoft.Sql/locations/managedInstanceLongTermRetentionPolicyOperationResults,null,No
-no,Microsoft.Sql/locations/managedInstanceLongTermRetentionPolicyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/longTermRetentionManagedInstanceBackupOperationResults,null,No
-no,Microsoft.Sql/locations/longTermRetentionManagedInstanceBackupAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedDatabaseAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedDatabaseOperationResults,null,No
-no,Microsoft.Sql/locations/managedDatabaseRestoreAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedDatabaseRestoreOperationResults,null,No
-no,Microsoft.Sql/locations/managedDatabaseCompleteRestoreAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedDatabaseCompleteRestoreOperationResults,null,No
-no,Microsoft.Sql/locations/managedServerSecurityAlertPoliciesAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/stopManagedInstanceAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/stopManagedInstanceOperationResults,null,No
-no,Microsoft.Sql/locations/startManagedInstanceAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/startManagedInstanceOperationResults,null,No
-no,Microsoft.Sql/managedInstances/tdeCertificates,null,No
-no,Microsoft.Sql/locations/managedInstanceTdeCertAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedInstanceTdeCertOperationResults,null,No
-no,Microsoft.Sql/locations/managedServerSecurityAlertPoliciesOperationResults,null,No
-no,Microsoft.Sql/locations/securityAlertPoliciesAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/securityAlertPoliciesOperationResults,null,No
-no,Microsoft.Sql/locations/advancedThreatProtectionAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/advancedThreatProtectionOperationResults,null,No
-no,Microsoft.Sql/locations/managedInstanceAdvancedThreatProtectionAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedInstanceAdvancedThreatProtectionOperationResults,null,No
-no,Microsoft.Sql/managedInstances/dnsAliases,null,No
-no,Microsoft.Sql/locations/managedDnsAliasAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedDnsAliasOperationResults,null,No
-yes,Microsoft.Sql/virtualClusters,SQL Virtual Clusters,No
-no,Microsoft.Sql/locations/virtualClusterAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/virtualClusterOperationResults,null,No
-no,Microsoft.Sql/locations/updateManagedInstanceDnsServersAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/updateManagedInstanceDnsServersOperationResults,null,No
-no,Microsoft.Sql/locations/managedInstanceAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedInstanceOperationResults,null,No
-no,Microsoft.Sql/locations/distributedAvailabilityGroupsOperationResults,null,No
-no,Microsoft.Sql/locations/distributedAvailabilityGroupsAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/serverTrustCertificatesOperationResults,null,No
-no,Microsoft.Sql/locations/serverTrustCertificatesAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/administratorAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/administratorOperationResults,null,No
-no,Microsoft.Sql/locations/syncGroupOperationResults,null,No
-no,Microsoft.Sql/locations/syncGroupAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/syncMemberOperationResults,null,No
-no,Microsoft.Sql/locations/syncAgentOperationResults,null,No
-no,Microsoft.Sql/locations/syncDatabaseIds,null,No
-no,Microsoft.Sql/locations/longTermRetentionServers,null,No
-no,Microsoft.Sql/locations/longTermRetentionBackups,null,No
-no,Microsoft.Sql/locations/longTermRetentionPolicyOperationResults,null,No
-no,Microsoft.Sql/locations/longTermRetentionPolicyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/longTermRetentionBackupOperationResults,null,No
-no,Microsoft.Sql/locations/longTermRetentionBackupAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/changeLongTermRetentionBackupAccessTierOperationResults,null,No
-no,Microsoft.Sql/locations/changeLongTermRetentionBackupAccessTierAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/shortTermRetentionPolicyOperationResults,null,No
-no,Microsoft.Sql/locations/shortTermRetentionPolicyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedShortTermRetentionPolicyOperationResults,null,No
-no,Microsoft.Sql/locations/managedShortTermRetentionPolicyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/instanceFailoverGroups,null,No
-no,Microsoft.Sql/locations/instanceFailoverGroupAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/instanceFailoverGroupOperationResults,null,No
-no,Microsoft.Sql/locations/privateEndpointConnectionProxyOperationResults,null,No
-no,Microsoft.Sql/locations/privateEndpointConnectionProxyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/privateEndpointConnectionOperationResults,null,No
-no,Microsoft.Sql/locations/outboundFirewallRulesAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/outboundFirewallRulesOperationResults,null,No
-no,Microsoft.Sql/locations/privateEndpointConnectionAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/notifyAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/serverTrustGroups,null,No
-no,Microsoft.Sql/locations/serverTrustGroupOperationResults,null,No
-no,Microsoft.Sql/locations/serverTrustGroupAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/managedDatabaseMoveOperationResults,null,No
-no,Microsoft.Sql/servers/connectionPolicies,null,No
-no,Microsoft.Sql/locations/connectionPoliciesAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/connectionPoliciesOperationResults,null,No
-no,Microsoft.Sql/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.Sql/locations/replicationLinksAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/replicationLinksOperationResults,null,No
-no,Microsoft.Sql/locations/managedInstanceDtcAzureAsyncOperation,null,No
-no,Microsoft.Sql/managedInstances/databases/ledgerDigestUploads,null,No
-no,Microsoft.Sql/locations/managedLedgerDigestUploadsOperationResults,null,No
-no,Microsoft.Sql/locations/managedLedgerDigestUploadsAzureAsyncOperation,null,No
-no,Microsoft.Sql/locations/serverConfigurationOptionAzureAsyncOperation,null,No
-no,Microsoft.Sql/servers/failoverGroups/tryPlannedBeforeForcedFailover,null,No
-no,Microsoft.Maintenance/maintenanceConfigurations,Maintenance Configurations,No
-no,Microsoft.Maintenance/updates,Maintenance Updates,No
-no,Microsoft.Maintenance/configurationAssignments,Maintenance Configuration Assignments,No
-no,Microsoft.Maintenance/applyUpdates,Maintenance Apply Updates,No
-no,Microsoft.Maintenance/publicMaintenanceConfigurations,Maintenance Oublic Maintenance Configurations,No
-no,Microsoft.Maintenance/operations,null,No
-yes,Microsoft.DataFactory/factories,Data Factory,Yes
-no,Microsoft.DataFactory/factories/integrationRuntimes,null,No
-no,Microsoft.DataFactory/factories/privateEndpointConnectionProxies,null,No
-no,Microsoft.DataFactory/CheckNameAvailability,null,No
-no,Microsoft.DataFactory/operations,null,No
-no,Microsoft.DataFactory/locations,null,No
-no,Microsoft.DataFactory/locations/configureFactoryRepo,null,No
-no,Microsoft.DataFactory/locations/getFeatureValue,null,No
-no,Microsoft.Security/operations,null,No
-no,Microsoft.Security/securityStatuses,null,No
-no,Microsoft.Security/tasks,null,No
-no,Microsoft.Security/secureScores,null,No
-no,Microsoft.Security/secureScores/secureScoreControls,null,No
-no,Microsoft.Security/secureScoreControls,null,No
-no,Microsoft.Security/secureScoreControlDefinitions,null,No
-no,Microsoft.Security/connectors,null,No
-no,Microsoft.Security/regulatoryComplianceStandards,null,No
-no,Microsoft.Security/regulatoryComplianceStandards/regulatoryComplianceControls,null,No
-no,Microsoft.Security/regulatoryComplianceStandards/regulatoryComplianceControls/regulatoryComplianceAssessments,null,No
-no,Microsoft.Security/alerts,null,No
-no,Microsoft.Security/alertsSuppressionRules,null,No
-no,Microsoft.Security/autoDismissAlertsRules,null,No
-no,Microsoft.Security/dataCollectionAgents,null,No
-no,Microsoft.Security/pricings,null,No
-no,Microsoft.Security/pricings/securityOperators,null,No
-no,Microsoft.Security/AutoProvisioningSettings,null,No
-no,Microsoft.Security/MdeOnboardings,null,No
-no,Microsoft.Security/vmScanners,null,No
-no,Microsoft.Security/Compliances,null,No
-no,Microsoft.Security/securityContacts,null,No
-no,Microsoft.Security/workspaceSettings,null,No
-no,Microsoft.Security/complianceResults,null,No
-no,Microsoft.Security/policies,null,No
-no,Microsoft.Security/assessments,null,No
-no,Microsoft.Security/governanceRules,null,No
-no,Microsoft.Security/assessments/governanceAssignments,null,No
-no,Microsoft.Security/assessmentMetadata,null,No
-no,Microsoft.Security/subAssessments,null,No
-no,Microsoft.Security/securitySolutions,null,No
-no,Microsoft.Security/locations/securitySolutions,null,No
-no,Microsoft.Security/discoveredSecuritySolutions,null,No
-no,Microsoft.Security/locations/discoveredSecuritySolutions,null,No
-no,Microsoft.Security/allowedConnections,null,No
-no,Microsoft.Security/locations/allowedConnections,null,No
-no,Microsoft.Security/topologies,null,No
-no,Microsoft.Security/locations/topologies,null,No
-no,Microsoft.Security/securitySolutionsReferenceData,null,No
-no,Microsoft.Security/locations/securitySolutionsReferenceData,null,No
-no,Microsoft.Security/jitPolicies,null,No
-no,Microsoft.Security/jitNetworkAccessPolicies,null,No
-no,Microsoft.Security/locations/jitNetworkAccessPolicies,null,No
-no,Microsoft.Security/locations,null,No
-no,Microsoft.Security/securityStatusesSummaries,null,No
-no,Microsoft.Security/applicationWhitelistings,null,No
-no,Microsoft.Security/locations/applicationWhitelistings,null,No
-no,Microsoft.Security/locations/alerts,null,No
-no,Microsoft.Security/locations/tasks,null,No
-no,Microsoft.Security/externalSecuritySolutions,null,No
-no,Microsoft.Security/locations/externalSecuritySolutions,null,No
-no,Microsoft.Security/InformationProtectionPolicies,null,No
-no,Microsoft.Security/advancedThreatProtectionSettings,null,No
-no,Microsoft.Security/sqlVulnerabilityAssessments,null,No
-no,Microsoft.Security/deviceSecurityGroups,null,No
-no,Microsoft.Security/iotSecuritySolutions,null,No
-no,Microsoft.Security/iotSecuritySolutions/analyticsModels,null,No
-no,Microsoft.Security/iotSecuritySolutions/iotAlertTypes,null,No
-no,Microsoft.Security/iotSecuritySolutions/iotAlerts,null,No
-no,Microsoft.Security/iotSecuritySolutions/iotRecommendationTypes,null,No
-no,Microsoft.Security/iotSecuritySolutions/iotRecommendations,null,No
-no,Microsoft.Security/iotSecuritySolutions/analyticsModels/aggregatedAlerts,null,No
-no,Microsoft.Security/iotSecuritySolutions/analyticsModels/aggregatedRecommendations,null,No
-no,Microsoft.Security/settings,null,No
-no,Microsoft.Security/serverVulnerabilityAssessments,null,No
-no,Microsoft.Security/serverVulnerabilityAssessmentsSettings,null,No
-no,Microsoft.Security/adaptiveNetworkHardenings,null,No
-no,Microsoft.Security/automations,null,No
-no,Microsoft.Security/defenderForStorageSettings,null,No
-no,Microsoft.Security/dataScanners,null,No
-no,Microsoft.Security/securityConnectors,null,No
-no,Microsoft.Security/securityConnectors/devops,null,No
-no,Microsoft.Security/customRecommendations,null,No
-no,Microsoft.Security/customAssessmentAutomations,null,No
-no,Microsoft.Security/securityStandards,null,No
-no,Microsoft.Security/standards,null,No
-no,Microsoft.Security/standardAssignments,null,No
-no,Microsoft.Security/assignments,null,No
-no,Microsoft.Security/sensitivitySettings,null,No
-no,Microsoft.Security/query,null,No
-no,Microsoft.Security/applications,null,No
-no,Microsoft.Security/apiCollections,null,No
-no,Microsoft.Security/healthReports,null,No
-no,Microsoft.Security/aggregations,null,No
-no,Microsoft.Security/integrations,null,No
-no,Microsoft.Diagnostics/operations,null,No
-no,Microsoft.Diagnostics/operationResults,null,No
-no,Microsoft.Diagnostics/discoverSolutions,null,No
-no,Microsoft.Diagnostics/azureKB,null,No
-no,Microsoft.Diagnostics/insights,null,No
-no,Microsoft.Diagnostics/checkNameAvailability,null,No
-no,Microsoft.Diagnostics/solutions,null,No
-no,Microsoft.Diagnostics/apollo,null,No
-yes,Microsoft.Logic/workflows,Logic Workflow,Yes
-no,Microsoft.Logic/locations/workflows,null,No
-no,Microsoft.Logic/locations/validateWorkflowExport,null,No
-no,Microsoft.Logic/locations/workflowExport,null,No
-no,Microsoft.Logic/locations,null,No
-no,Microsoft.Logic/operations,null,No
-yes,Microsoft.Logic/integrationAccounts,Logic Integration Accounts,No
-yes,Microsoft.Logic/integrationServiceEnvironments,Logic Integration Service Environments,No
-no,Microsoft.Logic/integrationServiceEnvironments/managedApis,null,No
-no,Microsoft.Logic/locations/generateCopilotResponse,null,No
-yes,Microsoft.Cdn/profiles,Front Door,Yes
-no,Microsoft.Cdn/profiles/endpoints,null,No
-no,Microsoft.Cdn/profiles/endpoints/origins,null,No
-no,Microsoft.Cdn/profiles/endpoints/origingroups,null,No
-no,Microsoft.Cdn/profiles/endpoints/customdomains,null,No
-no,Microsoft.Cdn/operationresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/endpointresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/endpointresults/originresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/endpointresults/origingroupresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/endpointresults/customdomainresults,null,No
-no,Microsoft.Cdn/checkNameAvailability,null,No
-no,Microsoft.Cdn/checkEndpointNameAvailability,null,No
-no,Microsoft.Cdn/checkResourceUsage,CDN Resource Usage,No
-no,Microsoft.Cdn/validateProbe,null,No
-no,Microsoft.Cdn/canMigrate,null,No
-no,Microsoft.Cdn/migrate,null,No
-no,Microsoft.Cdn/operations,null,No
-no,Microsoft.Cdn/edgenodes,null,No
-no,Microsoft.Cdn/CdnWebApplicationFirewallPolicies,CDN WAF Policies,No
-no,Microsoft.Cdn/operationresults/cdnwebapplicationfirewallpolicyresults,null,No
-no,Microsoft.Cdn/CdnWebApplicationFirewallManagedRuleSets,null,No
-no,Microsoft.Cdn/profiles/afdendpoints,null,No
-no,Microsoft.Cdn/profiles/afdendpoints/routes,null,No
-no,Microsoft.Cdn/profiles/customdomains,null,No
-no,Microsoft.Cdn/profiles/origingroups,null,No
-no,Microsoft.Cdn/profiles/origingroups/origins,null,No
-no,Microsoft.Cdn/profiles/rulesets,null,No
-no,Microsoft.Cdn/profiles/rulesets/rules,null,No
-no,Microsoft.Cdn/profiles/secrets,null,No
-no,Microsoft.Cdn/validateSecret,null,No
-no,Microsoft.Cdn/profiles/keygroups,null,No
-no,Microsoft.Cdn/profiles/securitypolicies,null,No
-no,Microsoft.Cdn/operationresults/profileresults/afdendpointresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/afdendpointresults/routeresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/customdomainresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/origingroupresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/origingroupresults/originresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/rulesetresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/rulesetresults/ruleresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/secretresults,null,No
-no,Microsoft.Cdn/operationresults/profileresults/securitypolicyresults,null,No
-no,Microsoft.Cdn/profiles/policies,null,No
-no,Microsoft.Cdn/profiles/networkpolicies,null,No
-no,Microsoft.Cdn/operationresults/profileresults/policyresults,null,No
-no,Microsoft.Chaos/operations,null,No
-no,Microsoft.Chaos/targets,null,No
-no,Microsoft.Chaos/locations,null,No
-no,Microsoft.Chaos/locations/targetTypes,null,No
-no,Microsoft.Chaos/experiments,null,No
-no,Microsoft.Chaos/locations/operationStatuses,null,No
-no,Microsoft.Chaos/locations/operationResults,null,No
-no,Microsoft.Chaos/privateAccesses,null,No
-no,Microsoft.Advisor/suppressions,null,No
-no,Microsoft.Advisor/configurations,Advisor Configurations,No
-no,Microsoft.Advisor/metadata,null,No
-yes,Microsoft.Advisor/recommendations,Advisor Recommendations,No
-no,Microsoft.Advisor/generateRecommendations,null,No
-no,Microsoft.Advisor/operations,null,No
-no,Microsoft.Advisor/advisorScore,Advisor Score,No
-no,Microsoft.Advisor/predict,null,No
-no,Microsoft.Advisor/resiliencyReviews,Advisor Resiliency Reviews,No
-no,Microsoft.Advisor/triageRecommendations,Advisor Triage Recommendations,No
-no,Microsoft.Advisor/assessments,Advisor Assessments,Yes
-no,Microsoft.Advisor/assessmentTypes,null,No
-no,Microsoft.Advisor/workloads,Advisor Workloads,No
-no,Microsoft.MarketplaceNotifications/reviewsnotifications,null,No
-no,Microsoft.MarketplaceNotifications/operations,null,No
-no,Microsoft.ChangeAnalysis/operations,null,No
-no,Microsoft.ChangeAnalysis/resourceChanges,null,No
-no,Microsoft.ChangeAnalysis/changes,null,No
-no,Microsoft.ChangeAnalysis/changeSnapshots,null,No
-no,Microsoft.ChangeAnalysis/computeChanges,null,No
-yes,Microsoft.EventHub/namespaces,Event Hub Namespaces,Yes
-yes,Microsoft.EventHub/clusters,Event Hub Clusters,No
-no,Microsoft.EventHub/namespaces/authorizationrules,null,No
-no,Microsoft.EventHub/namespaces/networkrulesets,null,No
-no,Microsoft.EventHub/namespaces/privateEndpointConnections,null,No
-no,Microsoft.EventHub/namespaces/privateEndpointConnectionProxies,null,No
-no,Microsoft.EventHub/namespaces/networkSecurityPerimeterConfigurations,null,No
-no,Microsoft.EventHub/namespaces/networkSecurityPerimeterAssociationProxies,null,No
-no,Microsoft.EventHub/namespaces/hoboConfigurations,null,No
-no,Microsoft.EventHub/namespaces/eventhubs,null,No
-no,Microsoft.EventHub/namespaces/eventhubs/authorizationrules,null,No
-no,Microsoft.EventHub/namespaces/eventhubs/consumergroups,null,No
-no,Microsoft.EventHub/namespaces/applicationGroups,null,No
-no,Microsoft.EventHub/checkNamespaceAvailability,null,No
-no,Microsoft.EventHub/checkNameAvailability,null,No
-no,Microsoft.EventHub/sku,null,No
-no,Microsoft.EventHub/operations,null,No
-no,Microsoft.EventHub/namespaces/disasterrecoveryconfigs,null,No
-no,Microsoft.EventHub/namespaces/disasterrecoveryconfigs/checkNameAvailability,null,No
-no,Microsoft.EventHub/locations,null,No
-no,Microsoft.EventHub/locations/operationStatus,null,No
-no,Microsoft.EventHub/locations/clusterOperationResults,null,No
-no,Microsoft.EventHub/locations/namespaceOperationResults,null,No
-no,Microsoft.EventHub/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.EventHub/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.EventHub/availableClusterRegions,null,No
-no,Microsoft.Dashboard/locations,null,No
-no,Microsoft.Dashboard/checkNameAvailability,null,No
-no,Microsoft.Dashboard/locations/operationStatuses,null,No
-yes,Microsoft.Dashboard/grafana,Grafana Dashboard,Yes
-no,Microsoft.Dashboard/operations,null,No
-no,Microsoft.Dashboard/grafana/privateEndpointConnections,null,No
-no,Microsoft.Dashboard/grafana/privateLinkResources,null,No
-no,Microsoft.Dashboard/locations/checkNameAvailability,null,No
-no,Microsoft.Dashboard/grafana/managedPrivateEndpoints,null,No
-no,Microsoft.ServiceLinker/locations,null,No
-no,Microsoft.ServiceLinker/locations/operationStatuses,null,No
-no,Microsoft.ServiceLinker/operations,null,No
-no,Microsoft.ServiceLinker/linkers,null,No
-no,Microsoft.ServiceLinker/dryruns,null,No
-no,Microsoft.ServiceLinker/locations/connectors,null,No
-no,Microsoft.ServiceLinker/locations/dryruns,null,No
-no,Microsoft.ServiceLinker/configurationNames,null,No
-no,Microsoft.ServiceLinker/daprConfigurations,null,No
-yes,Microsoft.ServiceBus/namespaces,Service Bus,Yes
-no,Microsoft.ServiceBus/namespaces/authorizationrules,null,No
-no,Microsoft.ServiceBus/namespaces/networkrulesets,null,No
-no,Microsoft.ServiceBus/namespaces/privateEndpointConnections,null,No
-no,Microsoft.ServiceBus/namespaces/privateEndpointConnectionProxies,null,No
-no,Microsoft.ServiceBus/namespaces/queues,null,No
-no,Microsoft.ServiceBus/namespaces/queues/authorizationrules,null,No
-no,Microsoft.ServiceBus/namespaces/topics,null,No
-no,Microsoft.ServiceBus/namespaces/topics/authorizationrules,null,No
-no,Microsoft.ServiceBus/namespaces/topics/subscriptions,null,No
-no,Microsoft.ServiceBus/namespaces/topics/subscriptions/rules,null,No
-no,Microsoft.ServiceBus/checkNamespaceAvailability,null,No
-no,Microsoft.ServiceBus/checkNameAvailability,null,No
-no,Microsoft.ServiceBus/sku,null,No
-no,Microsoft.ServiceBus/premiumMessagingRegions,null,No
-no,Microsoft.ServiceBus/operations,null,No
-no,Microsoft.ServiceBus/namespaces/eventgridfilters,null,No
-no,Microsoft.ServiceBus/namespaces/disasterrecoveryconfigs,null,No
-no,Microsoft.ServiceBus/namespaces/migrationConfigurations,null,No
-no,Microsoft.ServiceBus/namespaces/disasterrecoveryconfigs/checkNameAvailability,null,No
-no,Microsoft.ServiceBus/locations,null,No
-no,Microsoft.ServiceBus/locations/operationStatus,null,No
-no,Microsoft.ServiceBus/locations/namespaceOperationResults,null,No
-no,Microsoft.ServiceBus/locations/deleteVirtualNetworkOrSubnets,null,No
-yes,Microsoft.ApiManagement/service,Api Management,Yes
-no,Microsoft.ApiManagement/deletedServices,null,No
-no,Microsoft.ApiManagement/locations,null,No
-no,Microsoft.ApiManagement/locations/deletedServices,null,No
-no,Microsoft.ApiManagement/validateServiceName,null,No
-no,Microsoft.ApiManagement/checkServiceNameAvailability,null,No
-no,Microsoft.ApiManagement/checkNameAvailability,null,No
-no,Microsoft.ApiManagement/reportFeedback,null,No
-no,Microsoft.ApiManagement/checkFeedbackRequired,null,No
-no,Microsoft.ApiManagement/operations,null,No
-no,Microsoft.ApiManagement/getDomainOwnershipIdentifier,null,No
-no,Microsoft.ApiManagement/service/eventGridFilters,null,No
-no,Microsoft.DomainRegistration/domains,null,No
-no,Microsoft.DomainRegistration/domains/domainOwnershipIdentifiers,null,No
-no,Microsoft.DomainRegistration/topLevelDomains,null,No
-no,Microsoft.DomainRegistration/checkDomainAvailability,null,No
-no,Microsoft.DomainRegistration/listDomainRecommendations,null,No
-no,Microsoft.DomainRegistration/validateDomainRegistrationInformation,null,No
-no,Microsoft.DomainRegistration/generateSsoRequest,null,No
-no,Microsoft.DomainRegistration/operations,null,No
-no,Microsoft.EventGrid/locations,null,No
-no,Microsoft.EventGrid/locations/eventSubscriptions,null,No
-no,Microsoft.EventGrid/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-yes,Microsoft.EventGrid/eventSubscriptions,Event Grid Event Subscriptions,No
-yes,Microsoft.EventGrid/topics,Event Grid Topics,Yes
-yes,Microsoft.EventGrid/domains,Event Grid domain,Yes
-no,Microsoft.EventGrid/domains/topics,null,No
-no,Microsoft.EventGrid/topicTypes,null,No
-no,Microsoft.EventGrid/operations,null,No
-no,Microsoft.EventGrid/locations/operationsStatus,null,No
-no,Microsoft.EventGrid/locations/operationResults,null,No
-no,Microsoft.EventGrid/locations/topicTypes,null,No
-no,Microsoft.EventGrid/extensionTopics,null,No
-no,Microsoft.EventGrid/operationResults,null,No
-no,Microsoft.EventGrid/operationsStatus,null,No
-yes,Microsoft.EventGrid/systemTopics,Event Grid System Topics,No
-no,Microsoft.EventGrid/systemTopics/eventSubscriptions,null,No
-no,Microsoft.EventGrid/partnerRegistrations,null,No
-no,Microsoft.EventGrid/partnerConfigurations,null,No
-no,Microsoft.EventGrid/verifiedPartners,null,No
-yes,Microsoft.EventGrid/namespaces,Event Grid Namespaces,No
-yes,Microsoft.EventGrid/partnerNamespaces,Event Grid Partner Namespaces,No
-yes,Microsoft.EventGrid/partnerTopics,Event Grid Partner Topics,No
-no,Microsoft.EventGrid/partnerTopics/eventSubscriptions,null,No
-no,Microsoft.EventGrid/partnerNamespaces/eventChannels,null,No
-no,Microsoft.EventGrid/partnerNamespaces/channels,null,No
-no,Microsoft.EventGrid/partnerDestinations,null,No
-no,Microsoft.LoadTestService/operations,null,No
-no,Microsoft.LoadTestService/checkNameAvailability,null,No
-no,Microsoft.LoadTestService/loadtests,null,No
-no,Microsoft.LoadTestService/Locations,null,No
-no,Microsoft.LoadTestService/Locations/OperationStatuses,null,No
-no,Microsoft.LoadTestService/registeredSubscriptions,null,No
-no,Microsoft.LoadTestService/loadtests/outboundNetworkDependenciesEndpoints,null,No
-no,Microsoft.LoadTestService/Locations/Quotas,null,No
-no,Microsoft.LoadTestService/loadTestMappings,null,No
-yes,Microsoft.Kusto/clusters,Data explorer resource,Yes
-no,Microsoft.Kusto/clusters/databases,null,No
-no,Microsoft.Kusto/clusters/attacheddatabaseconfigurations,null,No
-no,Microsoft.Kusto/clusters/principalassignments,null,No
-no,Microsoft.Kusto/clusters/databases/eventhubconnections,null,No
-no,Microsoft.Kusto/clusters/databases/dataconnections,null,No
-no,Microsoft.Kusto/clusters/databases/principalassignments,null,No
-no,Microsoft.Kusto/locations/operationResults,null,No
-no,Microsoft.Kusto/locations,null,No
-no,Microsoft.Kusto/locations/checkNameAvailability,null,No
-no,Microsoft.Kusto/locations/skus,null,No
-no,Microsoft.Kusto/operations,null,No
-no,Microsoft.Kusto/clusters/databases/scripts,null,No
-no,Microsoft.Kusto/clusters/managedPrivateEndpoints,null,No
-no,Microsoft.Kusto/clusters/sandboxCustomImages,null,No
-no,Microsoft.CloudShell/operations,null,No
-no,Microsoft.IoTSecurity/Operations,null,No
-no,Microsoft.IoTSecurity/defenderSettings,null,No
-no,Microsoft.IoTSecurity/locations,null,No
-no,Microsoft.IoTSecurity/locations/deviceGroups,null,No
-no,Microsoft.IoTSecurity/locations/deviceGroups/devices,null,No
-no,Microsoft.IoTSecurity/locations/endpoints,null,No
-no,Microsoft.IoTSecurity/locations/deviceGroups/vulnerabilities,null,No
-no,Microsoft.IoTSecurity/locations/deviceGroups/alerts,null,No
-no,Microsoft.IoTSecurity/locations/deviceGroups/alerts/pcaps,null,No
-no,Microsoft.IoTSecurity/locations/deviceGroups/alerts/learn,null,No
-no,Microsoft.IoTSecurity/locations/deviceGroups/recommendations,null,No
-no,Microsoft.IoTSecurity/locations/sites,null,No
-no,Microsoft.IoTSecurity/locations/sites/sensors,null,No
-no,Microsoft.IoTSecurity/sites,null,No
-no,Microsoft.IoTSecurity/sensors,null,No
-no,Microsoft.IoTSecurity/onPremiseSensors,null,No
-no,Microsoft.IoTSecurity/alertTypes,null,No
-no,Microsoft.IoTSecurity/recommendationTypes,null,No
-no,Microsoft.IoTSecurity/licenseSkus,null,No
-yes,Microsoft.Quota/usages,Quota Usages,No
-yes,Microsoft.Quota/quotas,Quotas,No
-no,Microsoft.Quota/quotaRequests,null,No
-no,Microsoft.Quota/operationsStatus,null,No
-no,Microsoft.Quota/operations,null,No
-no,Microsoft.Quota/groupQuotas,null,No
-no,Microsoft.Quota/groupQuotas/groupQuotaLimits,null,No
-no,Microsoft.Quota/groupQuotas/subscriptions,null,No
-no,Microsoft.Quota/groupQuotas/groupQuotaRequests,null,No
-no,Microsoft.Quota/groupQuotas/quotaAllocations,null,No
-no,Microsoft.Quota/groupQuotas/quotaAllocationRequests,null,No
-no,Microsoft.Quota/groupQuotas/groupQuotaOperationsStatus,null,No
-no,Microsoft.Quota/groupQuotas/subscriptionRequests,null,No
-no,Microsoft.Quota/groupQuotas/quotaAllocationOperationsStatus,null,No
-no,Microsoft.ResourceHealth/availabilityStatuses,null,No
-no,Microsoft.ResourceHealth/childAvailabilityStatuses,null,No
-no,Microsoft.ResourceHealth/childResources,null,No
-no,Microsoft.ResourceHealth/events,null,No
-no,Microsoft.ResourceHealth/metadata,null,No
-no,Microsoft.ResourceHealth/emergingissues,null,No
-no,Microsoft.ResourceHealth/operations,null,No
-no,Microsoft.Web/publishingUsers,null,No
-no,Microsoft.Web/ishostnameavailable,null,No
-no,Microsoft.Web/validate,null,No
-no,Microsoft.Web/isusernameavailable,null,No
-no,Microsoft.Web/generateGithubAccessTokenForAppserviceCLI,null,No
-no,Microsoft.Web/sourceControls,null,No
-no,Microsoft.Web/availableStacks,null,No
-no,Microsoft.Web/webAppStacks,null,No
-no,Microsoft.Web/locations/webAppStacks,null,No
-no,Microsoft.Web/functionAppStacks,null,No
-no,Microsoft.Web/locations/functionAppStacks,null,No
-yes,Microsoft.Web/staticSites,Static Web App,Yes
-no,Microsoft.Web/locations/previewStaticSiteWorkflowFile,null,No
-no,Microsoft.Web/staticSites/userProvidedFunctionApps,null,No
-no,Microsoft.Web/staticSites/linkedBackends,null,No
-no,Microsoft.Web/staticSites/builds/linkedBackends,null,No
-no,Microsoft.Web/staticSites/databaseConnections,null,No
-no,Microsoft.Web/staticSites/builds/databaseConnections,null,No
-no,Microsoft.Web/staticSites/builds,null,No
-no,Microsoft.Web/staticSites/builds/userProvidedFunctionApps,null,No
-no,Microsoft.Web/listSitesAssignedToHostName,null,No
-no,Microsoft.Web/locations/getNetworkPolicies,null,No
-no,Microsoft.Web/locations/operations,null,No
-no,Microsoft.Web/locations/operationResults,null,No
-no,Microsoft.Web/sites/networkConfig,null,No
-no,Microsoft.Web/sites/slots/networkConfig,null,No
-no,Microsoft.Web/sites/hostNameBindings,null,No
-no,Microsoft.Web/sites/slots/hostNameBindings,null,No
-no,Microsoft.Web/operations,null,No
-no,Microsoft.Web/certificates,null,No
-yes,Microsoft.Web/serverFarms,App Service Plan,Yes
-yes,Microsoft.Web/sites,App Service,Yes
-no,Microsoft.Web/sites/slots,null,No
-no,Microsoft.Web/runtimes,null,No
-no,Microsoft.Web/recommendations,null,No
-no,Microsoft.Web/resourceHealthMetadata,null,No
-no,Microsoft.Web/aseregions,null,No
-no,Microsoft.Web/georegions,null,No
-no,Microsoft.Web/sites/premieraddons,null,No
-yes,Microsoft.Web/hostingEnvironments,Web Hosting Environments,No
-no,Microsoft.Web/hostingEnvironments/multiRolePools,null,No
-no,Microsoft.Web/hostingEnvironments/workerPools,null,No
-no,Microsoft.Web/kubeEnvironments,null,No
-no,Microsoft.Web/deploymentLocations,null,No
-no,Microsoft.Web/deletedSites,null,No
-no,Microsoft.Web/locations/deletedSites,null,No
-no,Microsoft.Web/ishostingenvironmentnameavailable,null,No
-no,Microsoft.Web/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.Web/locations/validateDeleteVirtualNetworkOrSubnets,null,No
-yes,Microsoft.Web/connections,Web Connections,No
-yes,Microsoft.Web/customApis,Web Custom APIs,No
-no,Microsoft.Web/locations,null,No
-no,Microsoft.Web/locations/listWsdlInterfaces,null,No
-no,Microsoft.Web/locations/extractApiDefinitionFromWsdl,null,No
-no,Microsoft.Web/locations/managedApis,null,No
-no,Microsoft.Web/locations/runtimes,null,No
-no,Microsoft.Web/locations/apiOperations,null,No
-no,Microsoft.Web/connectionGateways,null,No
-no,Microsoft.Web/locations/connectionGatewayInstallations,null,No
-no,Microsoft.Web/checkNameAvailability,null,No
-no,Microsoft.Web/billingMeters,null,No
-no,Microsoft.Web/verifyHostingEnvironmentVnet,null,No
-no,Microsoft.Web/serverFarms/eventGridFilters,null,No
-no,Microsoft.Web/sites/eventGridFilters,null,No
-no,Microsoft.Web/sites/slots/eventGridFilters,null,No
-no,Microsoft.Web/hostingEnvironments/eventGridFilters,null,No
-no,Microsoft.Web/serverFarms/firstPartyApps,null,No
-no,Microsoft.Web/serverFarms/firstPartyApps/keyVaultSettings,null,No
-yes,Microsoft.Web/containerApps,Web Container Apps,No
-no,Microsoft.Web/customhostnameSites,null,No
-no,Microsoft.Web/locations/usages,null,No
-yes,Microsoft.DocumentDB/databaseAccounts,Cosmosdb,Yes
-no,Microsoft.DocumentDB/databaseAccountNames,null,No
-no,Microsoft.DocumentDB/operations,null,No
-no,Microsoft.DocumentDB/operationResults,null,No
-no,Microsoft.DocumentDB/operationsStatus,null,No
-no,Microsoft.DocumentDB/locations/operationsStatus,null,No
-no,Microsoft.DocumentDB/locations/operationResults,null,No
-no,Microsoft.DocumentDB/locations,null,No
-no,Microsoft.DocumentDB/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.DocumentDB/locations/restorableDatabaseAccounts,null,No
-no,Microsoft.DocumentDB/restorableDatabaseAccounts,null,No
-yes,Microsoft.DocumentDB/cassandraClusters,Cassandra Clusters,No
-no,Microsoft.DocumentDB/databaseAccounts/encryptionScopes,null,No
-yes,Microsoft.DocumentDB/mongoClusters,MongoDB Clusters,No
-no,Microsoft.DocumentDB/locations/mongoClusterOperationResults,null,No
-no,Microsoft.DocumentDB/locations/mongoClusterAzureAsyncOperation,null,No
-no,Microsoft.DocumentDB/locations/checkMongoClusterNameAvailability,null,No
-no,Microsoft.DocumentDB/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.DocumentDB/throughputPools,null,No
-no,Microsoft.DocumentDB/throughputPools/throughputPoolAccounts,null,No
-no,Microsoft.GuestConfiguration/guestConfigurationAssignments,null,No
-no,Microsoft.GuestConfiguration/operations,null,No
-no,Astronomer.Astro/locations,null,No
-no,Astronomer.Astro/operations,null,No
-no,Astronomer.Astro/organizations,null,No
-no,Astronomer.Astro/locations/operationStatuses,null,No
-no,Dynatrace.Observability/operations,null,No
-no,Dynatrace.Observability/registeredSubscriptions,null,No
-no,Dynatrace.Observability/locations,null,No
-no,Dynatrace.Observability/locations/operationStatuses,null,No
-no,Dynatrace.Observability/monitors,null,No
-no,Dynatrace.Observability/monitors/tagRules,null,No
-no,Dynatrace.Observability/monitors/singleSignOnConfigurations,null,No
-no,Dynatrace.Observability/checkNameAvailability,null,No
-no,Dynatrace.Observability/getMarketplaceSaaSResourceDetails,null,No
-no,Dynatrace.Observability/monitors/listHosts,null,No
-no,Dynatrace.Observability/monitors/listMonitoredResources,null,No
-no,Dynatrace.Observability/monitors/listAppServices,null,No
-no,GitHub.Network/Operations,null,No
-no,GitHub.Network/networkSettings,null,No
-no,GitHub.Network/registeredSubscriptions,null,No
-no,Informatica.DataManagement/registeredSubscriptions,null,No
-no,Informatica.DataManagement/locations,null,No
-no,Informatica.DataManagement/locations/operationStatuses,null,No
-no,Informatica.DataManagement/checkNameAvailability,null,No
-no,Informatica.DataManagement/organizations,null,No
-no,Informatica.DataManagement/organizations/singleSignOnConfigurations,null,No
-no,Informatica.DataManagement/operations,null,No
-no,Informatica.DataManagement/organizations/serverlessRuntimes,null,No
-yes,Microsoft.AAD/DomainServices,Azure Active Directory Domain Services,Yes
-no,Microsoft.AAD/DomainServices/oucontainer,null,No
-no,Microsoft.AAD/locations,null,No
-no,Microsoft.AAD/locations/operationresults,null,No
-no,Microsoft.AAD/operations,null,No
-no,Microsoft.AadCustomSecurityAttributesDiagnosticSettings/operations,null,No
-no,Microsoft.AadCustomSecurityAttributesDiagnosticSettings/diagnosticSettings,null,No
-no,Microsoft.AadCustomSecurityAttributesDiagnosticSettings/diagnosticSettingsCategories,null,No
-no,microsoft.aadiam/azureADMetrics,null,No
-no,microsoft.aadiam/privateLinkForAzureAD,null,No
-no,microsoft.aadiam/tenants,null,No
-no,microsoft.aadiam/operations,null,No
-no,microsoft.aadiam/diagnosticSettings,null,No
-no,microsoft.aadiam/diagnosticSettingsCategories,null,No
-no,Microsoft.Addons/supportProviders,null,No
-no,Microsoft.Addons/operations,null,No
-no,Microsoft.Addons/operationResults,null,No
-no,Microsoft.ADHybridHealthService/services,null,No
-no,Microsoft.ADHybridHealthService/addsservices,null,No
-no,Microsoft.ADHybridHealthService/configuration,null,No
-no,Microsoft.ADHybridHealthService/operations,null,No
-no,Microsoft.ADHybridHealthService/agents,null,No
-no,Microsoft.ADHybridHealthService/aadsupportcases,null,No
-no,Microsoft.ADHybridHealthService/reports,null,No
-no,Microsoft.ADHybridHealthService/servicehealthmetrics,null,No
-no,Microsoft.ADHybridHealthService/logs,null,No
-no,Microsoft.ADHybridHealthService/anonymousapiusers,null,No
-no,Microsoft.AgFoodPlatform/operations,null,No
-no,Microsoft.AgFoodPlatform/farmBeatsExtensionDefinitions,null,No
-no,Microsoft.AgFoodPlatform/farmBeatsSolutionDefinitions,null,No
-no,Microsoft.AgFoodPlatform/checkNameAvailability,null,No
-no,Microsoft.AgFoodPlatform/locations,null,No
-no,Microsoft.AksHybrid/locations,null,No
-yes,Microsoft.AnalysisServices/servers,Analysis Services,No
-no,Microsoft.AnalysisServices/locations,null,No
-no,Microsoft.AnalysisServices/locations/checkNameAvailability,null,No
-no,Microsoft.AnalysisServices/locations/operationresults,null,No
-no,Microsoft.AnalysisServices/locations/operationstatuses,null,No
-no,Microsoft.AnalysisServices/operations,null,No
-no,Microsoft.AnyBuild/Locations,null,No
-no,Microsoft.AnyBuild/Locations/OperationStatuses,null,No
-no,Microsoft.AnyBuild/clusters,null,No
-no,Microsoft.AnyBuild/Operations,null,No
-yes,Microsoft.ApiCenter/services,null,Yes
-no,Microsoft.ApiCenter/operations,null,No
-no,Microsoft.ApiCenter/services/eventGridFilters,null,No
-no,Microsoft.ApiSecurity/Locations,null,No
-no,Microsoft.ApiSecurity/Locations/OperationStatuses,null,No
-no,Microsoft.ApiSecurity/Operations,null,No
-yes,Microsoft.ApiSecurity/apiCollections,API Collection,Yes
-no,Microsoft.ApiSecurity/apiCollections/apiCollectionDetails,API Collection Detail,Yes
-no,Microsoft.ApiSecurity/apiCollectionsMeta,null,No
-no,Microsoft.ApiSecurity/apiCollectionsMeta/apiCollectionMetaDetails,null,No
-yes,Microsoft.App/managedEnvironments,Managed Environment,Yes
-no,Microsoft.App/managedEnvironments/certificates,null,No
-no,Microsoft.App/managedEnvironments/managedCertificates,null,No
-yes,Microsoft.App/containerApps,Microsoft App Container App,Yes
-no,Microsoft.App/containerApps/privateEndpointConnectionProxies,null,No
-no,Microsoft.App/managedEnvironments/privateEndpointConnectionProxies,null,No
-no,Microsoft.App/jobs,null,No
-no,Microsoft.App/locations,null,No
-no,Microsoft.App/locations/managedEnvironmentOperationResults,null,No
-no,Microsoft.App/locations/managedEnvironmentOperationStatuses,null,No
-no,Microsoft.App/locations/containerappOperationResults,null,No
-no,Microsoft.App/locations/containerappOperationStatuses,null,No
-no,Microsoft.App/locations/containerappsjobOperationResults,null,No
-no,Microsoft.App/locations/containerappsjobOperationStatuses,null,No
-no,Microsoft.App/locations/sourceControlOperationResults,null,No
-no,Microsoft.App/locations/sourceControlOperationStatuses,null,No
-no,Microsoft.App/locations/usages,null,No
-no,Microsoft.App/operations,null,No
-no,Microsoft.App/connectedEnvironments,null,No
-no,Microsoft.App/connectedEnvironments/certificates,null,No
-no,Microsoft.App/locations/connectedEnvironmentOperationResults,null,No
-no,Microsoft.App/locations/connectedEnvironmentOperationStatuses,null,No
-no,Microsoft.App/locations/managedCertificateOperationStatuses,null,No
-no,Microsoft.App/locations/billingMeters,null,No
-no,Microsoft.App/locations/availableManagedEnvironmentsWorkloadProfileTypes,null,No
-no,Microsoft.App/getCustomDomainVerificationId,null,No
-no,Microsoft.App/builders,null,No
-no,Microsoft.App/builders/builds,null,No
-no,Microsoft.App/locations/OperationResults,null,No
-no,Microsoft.App/locations/OperationStatuses,null,No
-no,Microsoft.App/managedEnvironments/dotNetComponents,null,No
-no,Microsoft.App/managedEnvironments/javaComponents,null,No
-no,Microsoft.App/managedEnvironments/daprComponents,null,No
-no,Microsoft.AppAssessment/Locations,null,No
-no,Microsoft.AppAssessment/operations,null,No
-no,Microsoft.AppAssessment/Locations/OperationStatuses,null,No
-no,Microsoft.AppAssessment/Locations/osVersions,null,No
-no,Microsoft.AppComplianceAutomation/operations,null,No
-no,Microsoft.AppComplianceAutomation/locations,null,No
-no,Microsoft.AppComplianceAutomation/locations/operationStatuses,null,No
-no,Microsoft.AppComplianceAutomation/reports,null,No
-no,Microsoft.AppComplianceAutomation/reports/snapshots,null,No
-no,Microsoft.AppComplianceAutomation/onboard,null,No
-no,Microsoft.AppComplianceAutomation/triggerEvaluation,null,No
-no,Microsoft.AppComplianceAutomation/reports/webhooks,null,No
-no,Microsoft.AppComplianceAutomation/reports/evidences,null,No
-no,Microsoft.AppComplianceAutomation/listInUseStorageAccounts,null,No
-no,Microsoft.AppComplianceAutomation/checkNameAvailability,null,No
-no,Microsoft.AppComplianceAutomation/getCollectionCount,null,No
-no,Microsoft.AppComplianceAutomation/getOverviewStatus,null,No
-no,Microsoft.AppComplianceAutomation/reports/scopingConfigurations,null,No
-yes,Microsoft.AppConfiguration/configurationStores,Configuration store,Yes
-no,Microsoft.AppConfiguration/configurationStores/keyValues,null,No
-no,Microsoft.AppConfiguration/configurationStores/eventGridFilters,null,No
-no,Microsoft.AppConfiguration/checkNameAvailability,null,No
-no,Microsoft.AppConfiguration/locations/checkNameAvailability,null,No
-no,Microsoft.AppConfiguration/locations,null,No
-no,Microsoft.AppConfiguration/locations/operationsStatus,null,No
-no,Microsoft.AppConfiguration/operations,null,No
-no,Microsoft.AppConfiguration/deletedConfigurationStores,null,No
-no,Microsoft.AppConfiguration/locations/deletedConfigurationStores,null,No
-no,Microsoft.AppConfiguration/configurationStores/replicas,null,No
-no,Microsoft.AppConfiguration/configurationStores/snapshots,null,No
-no,Microsoft.AppConfiguration/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-yes,Microsoft.AppPlatform/Spring,Spring Cloud Service,Yes
-no,Microsoft.AppPlatform/Spring/operationResults,null,No
-no,Microsoft.AppPlatform/Spring/operationStatuses,null,No
-no,Microsoft.AppPlatform/Spring/apps,null,No
-no,Microsoft.AppPlatform/Spring/apps/operationResults,null,No
-no,Microsoft.AppPlatform/Spring/apps/operationStatuses,null,No
-no,Microsoft.AppPlatform/Spring/apps/deployments,null,No
-no,Microsoft.AppPlatform/Spring/apps/deployments/operationResults,null,No
-no,Microsoft.AppPlatform/Spring/apps/deployments/operationStatuses,null,No
-no,Microsoft.AppPlatform/Spring/configServers,null,No
-no,Microsoft.AppPlatform/Spring/configServers/operationResults,null,No
-no,Microsoft.AppPlatform/Spring/configServers/operationStatuses,null,No
-no,Microsoft.AppPlatform/Spring/eurekaServers,null,No
-no,Microsoft.AppPlatform/Spring/eurekaServers/operationResults,null,No
-no,Microsoft.AppPlatform/Spring/eurekaServers/operationStatuses,null,No
-no,Microsoft.AppPlatform/Spring/apps/domains,null,No
-no,Microsoft.AppPlatform/Spring/apps/domains/operationResults,null,No
-no,Microsoft.AppPlatform/Spring/apps/domains/operationStatuses,null,No
-no,Microsoft.AppPlatform/locations/checkNameAvailability,null,No
-no,Microsoft.AppPlatform/operations,null,No
-no,Microsoft.AppPlatform/locations,null,No
-no,Microsoft.AppPlatform/runtimeVersions,null,No
-no,Microsoft.AppPlatform/locations/operationResults,null,No
-no,Microsoft.AppPlatform/locations/operationStatus,null,No
-no,Microsoft.AppSecurity/operationStatuses,null,No
-no,Microsoft.AppSecurity/Operations,null,No
-no,Microsoft.ArcNetworking/locations,null,No
-no,Microsoft.ArcNetworking/locations/operationStatuses,null,No
-no,Microsoft.ArcNetworking/arcNwLoadBalancers,null,No
-no,Microsoft.Attestation/attestationProviders,Attestation provider,Yes
-no,Microsoft.Attestation/defaultProviders,null,No
-no,Microsoft.Attestation/locations,null,No
-no,Microsoft.Attestation/locations/defaultProvider,null,No
-no,Microsoft.Attestation/operations,null,No
-no,Microsoft.Authorization/roleAssignmentScheduleRequests,null,No
-no,Microsoft.Authorization/roleEligibilityScheduleRequests,null,No
-no,Microsoft.Authorization/roleAssignmentSchedules,null,No
-no,Microsoft.Authorization/roleEligibilitySchedules,null,No
-no,Microsoft.Authorization/roleAssignmentScheduleInstances,null,No
-no,Microsoft.Authorization/roleEligibilityScheduleInstances,null,No
-no,Microsoft.Authorization/roleManagementPolicies,null,No
-no,Microsoft.Authorization/roleManagementPolicyAssignments,null,No
-no,Microsoft.Authorization/eligibleChildResources,null,No
-no,Microsoft.Authorization/roleManagementAlerts,null,No
-no,Microsoft.Authorization/roleManagementAlertConfigurations,null,No
-no,Microsoft.Authorization/roleManagementAlertDefinitions,null,No
-no,Microsoft.Authorization/roleManagementAlertOperations,null,No
-no,Microsoft.Authorization/roleAssignments,null,No
-no,Microsoft.Authorization/roleDefinitions,null,No
-no,Microsoft.Authorization/classicAdministrators,null,No
-no,Microsoft.Authorization/permissions,null,No
-no,Microsoft.Authorization/denyAssignments,null,No
-no,Microsoft.Authorization/locks,Locks,No
-no,Microsoft.Authorization/operations,null,No
-no,Microsoft.Authorization/policyDefinitions,Policy Definitions,No
-no,Microsoft.Authorization/policyDefinitions/versions,null,No
-no,Microsoft.Authorization/policySetDefinitions,null,No
-no,Microsoft.Authorization/policySetDefinitions/versions,null,No
-no,Microsoft.Authorization/policyAssignments,null,No
-no,Microsoft.Authorization/policyExemptions,null,No
-no,Microsoft.Authorization/listPolicyDefinitionVersions,null,No
-no,Microsoft.Authorization/listPolicySetDefinitionVersions,null,No
-no,Microsoft.Authorization/dataAliases,null,No
-no,Microsoft.Authorization/dataPolicyManifests,null,No
-no,Microsoft.Authorization/providerOperations,null,No
-no,Microsoft.Authorization/elevateAccess,null,No
-no,Microsoft.Authorization/checkAccess,null,No
-no,Microsoft.Authorization/batchResourceCheckAccess,null,No
-no,Microsoft.Authorization/findOrphanRoleAssignments,null,No
-no,Microsoft.Authorization/roleAssignmentsUsageMetrics,null,No
-no,Microsoft.Authorization/accessReviewScheduleDefinitions,null,No
-no,Microsoft.Authorization/accessReviewScheduleSettings,null,No
-no,Microsoft.Authorization/accessReviewHistoryDefinitions,null,No
-no,Microsoft.Authorization/roleAssignmentApprovals,null,No
-no,Microsoft.Authorization/privateLinkAssociations,null,No
-no,Microsoft.Authorization/resourceManagementPrivateLinks,null,No
-no,Microsoft.Authorization/EnablePrivateLinkNetworkAccess,null,No
-no,Microsoft.Authorization/operationStatus,null,No
-no,Microsoft.Authorization/diagnosticSettings,null,No
-no,Microsoft.Authorization/diagnosticSettingsCategories,null,No
-no,Microsoft.Automanage/configurationProfileAssignments,null,No
-no,Microsoft.Automanage/configurationProfiles,null,No
-no,Microsoft.Automanage/configurationProfiles/versions,null,No
-no,Microsoft.Automanage/bestPractices,null,No
-no,Microsoft.Automanage/bestPractices/versions,null,No
-no,Microsoft.Automanage/operations,null,No
-no,Microsoft.Automanage/servicePrincipals,null,No
-yes,Microsoft.Automation/automationAccounts,Automation,Yes
-no,Microsoft.Automation/deletedAutomationAccounts,null,No
-no,Microsoft.Automation/automationAccounts/runbooks,null,No
-no,Microsoft.Automation/automationAccounts/configurations,null,No
-no,Microsoft.Automation/automationAccounts/webhooks,null,No
-no,Microsoft.Automation/operations,null,No
-no,Microsoft.Automation/automationAccounts/softwareUpdateConfigurations,null,No
-no,Microsoft.Automation/automationAccounts/softwareUpdateConfigurationRuns,null,No
-no,Microsoft.Automation/automationAccounts/softwareUpdateConfigurationMachineRuns,null,No
-no,Microsoft.Automation/automationAccounts/jobs,null,No
-no,Microsoft.Automation/automationAccounts/privateLinkResources,null,No
-no,Microsoft.Automation/automationAccounts/privateEndpointConnections,null,No
-no,Microsoft.Automation/automationAccounts/privateEndpointConnectionProxies,null,No
-no,Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups,null,No
-no,Microsoft.Automation/automationAccounts/hybridRunbookWorkerGroups/hybridRunbookWorkers,null,No
-no,Microsoft.Automation/automationAccounts/agentRegistrationInformation,null,No
-no,Microsoft.AutonomousDevelopmentPlatform/operations,null,No
-no,Microsoft.AutonomousDevelopmentPlatform/locations,null,No
-no,Microsoft.AutonomousDevelopmentPlatform/locations/operationstatuses,null,No
-no,Microsoft.AutonomousDevelopmentPlatform/checknameavailability,null,No
-no,Microsoft.AutonomousDevelopmentPlatform/workspaces/eventgridfilters,null,No
-no,Microsoft.AVS/locations,null,No
-no,Microsoft.AVS/locations/checkQuotaAvailability,null,No
-no,Microsoft.AVS/locations/checkTrialAvailability,null,No
-no,Microsoft.AVS/locations/usages,null,No
-no,Microsoft.AVS/operations,null,No
-yes,Microsoft.AVS/privateClouds,Azure Vmware Solution,Yes
-no,Microsoft.AVS/privateClouds/addons,null,No
-no,Microsoft.AVS/privateClouds/authorizations,null,No
-no,Microsoft.AVS/privateClouds/cloudLinks,null,No
-no,Microsoft.AVS/privateClouds/clusters,null,No
-no,Microsoft.AVS/privateClouds/clusters/datastores,null,No
-no,Microsoft.AVS/privateClouds/clusters/placementPolicies,null,No
-no,Microsoft.AVS/privateClouds/clusters/virtualMachines,null,No
-no,Microsoft.AVS/privateClouds/eventGridFilters,null,No
-no,Microsoft.AVS/privateClouds/globalReachConnections,null,No
-no,Microsoft.AVS/privateClouds/hcxEnterpriseSites,null,No
-no,Microsoft.AVS/privateClouds/scriptExecutions,null,No
-no,Microsoft.AVS/privateClouds/scriptPackages,null,No
-no,Microsoft.AVS/privateClouds/scriptPackages/scriptCmdlets,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/dhcpConfigurations,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/dnsServices,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/dnsZones,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/gateways,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/portMirroringProfiles,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/publicIPs,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/segments,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/virtualMachines,null,No
-no,Microsoft.AVS/privateClouds/workloadNetworks/vmGroups,null,No
-no,Microsoft.AwsConnector/Locations,null,No
-no,Microsoft.AwsConnector/Operations,null,No
-no,Microsoft.AzureActiveDirectory/ciamDirectories,null,No
-no,Microsoft.AzureActiveDirectory/guestUsages,null,No
-no,Microsoft.AzureActiveDirectory/b2cDirectories,null,No
-no,Microsoft.AzureActiveDirectory/checkNameAvailability,null,No
-no,Microsoft.AzureActiveDirectory/operations,null,No
-no,Microsoft.AzureActiveDirectory/b2ctenants,null,No
-no,Microsoft.AzureActiveDirectory/operationStatuses,null,No
-no,Microsoft.AzureArcData/Locations,null,No
-no,Microsoft.AzureArcData/Locations/OperationStatuses,null,No
-no,Microsoft.AzureArcData/DataControllers,null,No
-no,Microsoft.AzureArcData/SqlManagedInstances,null,No
-no,Microsoft.AzureArcData/PostgresInstances,null,No
-yes,Microsoft.AzureArcData/SqlServerInstances,Sql Server Instance,Yes
-no,Microsoft.AzureArcData/Operations,null,No
-no,Microsoft.AzureArcData/DataControllers/ActiveDirectoryConnectors,null,No
-no,Microsoft.AzureArcData/SqlServerInstances/Databases,null,No
-no,Microsoft.AzureArcData/SqlManagedInstances/FailoverGroups,null,No
-no,Microsoft.AzureArcData/SqlServerInstances/AvailabilityGroups,null,No
-no,Microsoft.AzureArcData/SqlServerLicenses,null,No
-no,Microsoft.AzureFleet/locations,null,No
-no,Microsoft.AzureLargeInstance/azureLargeInstances,Azure Large Instances,No
-no,Microsoft.AzureLargeInstance/azureLargeStorageInstances,Azure Large Storage Instances,No
-no,Microsoft.AzureLargeInstance/locations,null,No
-no,Microsoft.AzureLargeInstance/locations/operationsStatus,null,No
-no,Microsoft.AzureLargeInstance/operations,null,No
-no,Microsoft.AzurePercept/checkNameAvailability,null,No
-no,Microsoft.AzurePercept/operations,null,No
-no,Microsoft.AzurePlaywrightService/operations,null,No
-no,Microsoft.AzurePlaywrightService/checkNameAvailability,null,No
-no,Microsoft.AzurePlaywrightService/Locations,null,No
-no,Microsoft.AzurePlaywrightService/Locations/OperationStatuses,null,No
-no,Microsoft.AzurePlaywrightService/accounts,null,No
-no,Microsoft.AzurePlaywrightService/registeredSubscriptions,null,No
-no,Microsoft.AzurePlaywrightService/Locations/Quotas,null,No
-no,Microsoft.AzureScan/scanningAccounts,null,No
-no,Microsoft.AzureScan/locations,null,No
-no,Microsoft.AzureScan/locations/OperationStatuses,null,No
-no,Microsoft.AzureScan/Operations,null,No
-no,Microsoft.AzureScan/checkNameAvailability,null,No
-no,Microsoft.AzureSphere/catalogs,null,No
-no,Microsoft.AzureSphere/catalogs/products,null,No
-no,Microsoft.AzureSphere/catalogs/products/devicegroups,null,No
-no,Microsoft.AzureSphere/locations,null,No
-no,Microsoft.AzureSphere/catalogs/certificates,null,No
-no,Microsoft.AzureSphere/catalogs/images,null,No
-no,Microsoft.AzureSphere/operations,null,No
-no,Microsoft.AzureSphere/locations/operationStatuses,null,No
-no,Microsoft.AzureSphere/catalogs/products/devicegroups/devices,null,No
-no,Microsoft.AzureSphere/catalogs/products/devicegroups/deployments,null,No
-no,Microsoft.AzureStack/operations,null,No
-no,Microsoft.AzureStack/registrations,null,No
-no,Microsoft.AzureStack/registrations/products,null,No
-no,Microsoft.AzureStack/registrations/customerSubscriptions,null,No
-no,Microsoft.AzureStack/cloudManifestFiles,null,No
-no,Microsoft.AzureStack/linkedSubscriptions,null,No
-no,Microsoft.AzureStack/generateDeploymentLicense,null,No
-no,Microsoft.AzureStackHCI/operations,null,No
-no,Microsoft.AzureStackHCI/locations,null,No
-no,Microsoft.AzureStackHCI/locations/operationstatuses,null,No
-no,Microsoft.AzureStackHCI/galleryImages,null,No
-no,Microsoft.AzureStackHCI/networkInterfaces,null,No
-no,Microsoft.AzureStackHCI/virtualMachines,Azure Stack HCI Virtual Machines,No
-no,Microsoft.AzureStackHCI/virtualNetworks,null,No
-no,Microsoft.AzureStackHCI/virtualHardDisks,null,No
-yes,Microsoft.AzureStackHCI/clusters,Azure Stack HCI,Yes
-no,Microsoft.AzureStackHCI/clusters/arcSettings,null,No
-no,Microsoft.AzureStackHCI/clusters/arcSettings/extensions,null,No
-no,Microsoft.AzureStackHCI/virtualMachines/extensions,null,No
-no,Microsoft.AzureStackHCI/virtualMachines/hybrididentitymetadata,null,No
-no,Microsoft.AzureStackHCI/clusters/publishers,null,No
-no,Microsoft.AzureStackHCI/clusters/offers,null,No
-no,Microsoft.AzureStackHCI/clusters/publishers/offers,null,No
-no,Microsoft.AzureStackHCI/clusters/publishers/offers/skus,null,No
-no,Microsoft.AzureStackHCI/marketplaceGalleryImages,null,No
-no,Microsoft.AzureStackHCI/storageContainers,null,No
-no,Microsoft.AzureStackHCI/clusters/updates,null,No
-no,Microsoft.AzureStackHCI/clusters/updates/updateRuns,null,No
-no,Microsoft.AzureStackHCI/clusters/updateSummaries,null,No
-no,Microsoft.AzureStackHCI/registeredSubscriptions,null,No
-no,Microsoft.AzureStackHCI/virtualMachineInstances,Azure Stack HCI Virtual Machine Instances,No
-no,Microsoft.AzureStackHCI/clusters/deploymentSettings,null,No
-no,Microsoft.AzureStackHCI/edgeDevices,null,No
-no,Microsoft.AzureStackHCI/logicalNetworks,null,No
-no,Microsoft.AzureStackHCI/clusters/securitySettings,null,No
-no,Microsoft.BackupSolutions/VMwareApplications,null,No
-no,Microsoft.BackupSolutions/locations,null,No
-no,Microsoft.BackupSolutions/locations/operationstatuses,null,No
-no,Microsoft.BackupSolutions/operations,null,No
-no,Microsoft.BareMetal/bareMetalConnections,null,No
-no,Microsoft.BareMetal/operations,null,No
-no,Microsoft.BareMetal/locations,null,No
-no,Microsoft.BareMetal/locations/operationResults,null,No
-no,Microsoft.BareMetal/utilization,null,No
-no,Microsoft.BareMetalInfrastructure/bareMetalInstances,Baremetal Instances,No
-no,Microsoft.BareMetalInfrastructure/bareMetalStorageInstances,Baremetal Storage Instances,No
-no,Microsoft.BareMetalInfrastructure/locations,null,No
-no,Microsoft.BareMetalInfrastructure/locations/operationsStatus,null,No
-no,Microsoft.BareMetalInfrastructure/operations,null,No
-yes,Microsoft.Batch/batchAccounts,Batch Accounts,Yes
-no,Microsoft.Batch/batchAccounts/pools,null,No
-no,Microsoft.Batch/batchAccounts/detectors,null,No
-no,Microsoft.Batch/batchAccounts/certificates,null,No
-no,Microsoft.Batch/batchAccounts/operationResults,null,No
-no,Microsoft.Batch/batchAccounts/poolOperationResults,null,No
-no,Microsoft.Batch/batchAccounts/certificateOperationResults,null,No
-no,Microsoft.Batch/batchAccounts/privateEndpointConnectionProxyResults,null,No
-no,Microsoft.Batch/batchAccounts/privateEndpointConnectionResults,null,No
-no,Microsoft.Batch/operations,null,No
-no,Microsoft.Batch/locations,null,No
-no,Microsoft.Batch/locations/quotas,null,No
-no,Microsoft.Batch/locations/checkNameAvailability,null,No
-no,Microsoft.Batch/locations/accountOperationResults,null,No
-no,Microsoft.Batch/locations/virtualMachineSkus,null,No
-no,Microsoft.Batch/locations/cloudServiceSkus,null,No
-no,Microsoft.Billing/billingPeriods,null,No
-no,Microsoft.Billing/invoices,null,No
-no,Microsoft.Billing/enrollmentAccounts,null,No
-no,Microsoft.Billing/permissionRequests,null,No
-no,Microsoft.Billing/billingAccounts/permissionRequests,null,No
-no,Microsoft.Billing/billingAccounts/associatedTenants,null,No
-no,Microsoft.Billing/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingRoleAssignments,null,No
-no,Microsoft.Billing/createBillingRoleAssignment,null,No
-no,Microsoft.Billing/billingAccounts/createBillingRoleAssignment,null,No
-no,Microsoft.Billing/billingAccounts/signAgreement,null,No
-no,Microsoft.Billing/billingAccounts/previewAgreements,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/createBillingRoleAssignment,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/createBillingRoleAssignment,null,No
-no,Microsoft.Billing/billingAccounts/customers/createBillingRoleAssignment,null,No
-no,Microsoft.Billing/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingAccounts/billingRoleAssignments,null,No
-no,Microsoft.Billing/billingAccounts/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts,null,No
-no,Microsoft.Billing/billingAccounts/billingProfilesSummaries,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/billingRoleAssignments,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/customers,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/customers,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/instructions,null,No
-no,Microsoft.Billing/billingAccounts/customers/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/customers/products,null,No
-no,Microsoft.Billing/billingAccounts/customers/transactions,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/billingRoleAssignments,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/customers/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/customers/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingAccounts/customers/billingRoleAssignments,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/customers/billingRoleAssignments,null,No
-no,Microsoft.Billing/billingAccounts/customers/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/customers/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/elevate,null,No
-no,Microsoft.Billing/billingAccounts/createInvoiceSectionOperations,null,No
-no,Microsoft.Billing/billingAccounts/patchOperations,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/patchOperations,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/productMoveOperations,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/billingSubscriptionMoveOperations,null,No
-no,Microsoft.Billing/billingAccounts/listInvoiceSectionsWithCreateSubscriptionPermission,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles,null,No
-no,Microsoft.Billing/billingAccounts/BillingProfiles/patchOperations,null,No
-no,Microsoft.Billing/departments,null,No
-no,Microsoft.Billing/billingAccounts/departments,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/departments,null,No
-no,Microsoft.Billing/billingAccounts/notificationContacts,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/notificationContacts,null,No
-no,Microsoft.Billing/billingAccounts/departments/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/departments/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingAccounts/departments/billingRoleAssignments,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/departments/billingRoleAssignments,null,No
-no,Microsoft.Billing/billingAccounts/departments/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/departments/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/enrollmentAccounts,null,No
-no,Microsoft.Billing/billingAccounts/departments/enrollmentAccounts,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/enrollmentAccounts,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/departments/enrollmentAccounts,null,No
-no,Microsoft.Billing/billingAccounts/enrollmentAccounts/billingRoleDefinitions,null,No
-no,Microsoft.Billing/billingAccounts/enrollmentAccounts/billingRoleAssignments,null,No
-no,Microsoft.Billing/billingAccounts/enrollmentAccounts/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/enrollmentAccounts/billingPermissions,null,No
-no,Microsoft.Billing/billingAccounts/enrollmentAccounts/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/departments/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/paymentMethods,null,No
-no,Microsoft.Billing/billingAccounts/availableBalance,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/availableBalance,null,No
-no,Microsoft.Billing/billingAccounts/invoices,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoices,null,No
-no,Microsoft.Billing/billingAccounts/transactions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/transactions,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/transactions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/transactions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoices/transactions,null,No
-no,Microsoft.Billing/billingAccounts/invoices/transactions,null,No
-no,Microsoft.Billing/billingAccounts/invoices/summary,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/validateDeleteBillingProfileEligibility,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/validateDeleteInvoiceSectionEligibility,null,No
-no,Microsoft.Billing/billingAccounts/invoices/transactionSummary,null,No
-no,Microsoft.Billing/billingAccounts/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/billingSubscriptionAliases,null,No
-no,Microsoft.Billing/billingAccounts/billingSubscriptions/invoices,null,No
-no,Microsoft.Billing/billingAccounts/billingSubscriptions/policies,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/departments/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/enrollmentAccounts/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/billingSubscriptions,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/products,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/products,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/products/updateAutoRenew,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/products/updateAutoRenew,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/products,null,No
-no,Microsoft.Billing/billingAccounts/products,null,No
-no,Microsoft.Billing/operations,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/initiateTransfer,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/initiateTransfer,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/transfers,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/transfers,null,No
-no,Microsoft.Billing/transfers/acceptTransfer,null,No
-no,Microsoft.Billing/transfers,null,No
-no,Microsoft.Billing/transfers/declineTransfer,null,No
-no,Microsoft.Billing/transfers/validateTransfer,null,No
-no,Microsoft.Billing/billingAccounts/customers/initiateTransfer,null,No
-no,Microsoft.Billing/billingAccounts/customers/transfers,null,No
-no,Microsoft.Billing/billingAccounts/customers/transferSupportedAccounts,null,No
-no,Microsoft.Billing/billingProperty,null,No
-no,Microsoft.Billing/policies,null,No
-no,Microsoft.Billing/billingAccounts/policies,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/policies,null,No
-no,Microsoft.Billing/billingAccounts/customers/policies,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoices/pricesheet,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/pricesheet,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/billingSubscriptions/transfer,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/products/transfer,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoiceSections/products/transfer,null,No
-no,Microsoft.Billing/billingAccounts/invoiceSections/productTransfersResults,null,No
-no,Microsoft.Billing/billingAccounts/agreements,null,No
-no,Microsoft.Billing/billingAccounts/lineOfCredit,null,No
-no,Microsoft.Billing/billingAccounts/paymentMethods,null,No
-no,Microsoft.Billing/paymentMethods,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/paymentMethodLinks,null,No
-no,Microsoft.Billing/billingAccounts/payableOverage,null,No
-no,Microsoft.Billing/billingAccounts/payNow,null,No
-no,Microsoft.Billing/billingAccounts/reservationOrders,null,No
-no,Microsoft.Billing/billingAccounts/reservationOrders/reservations,null,No
-no,Microsoft.Billing/billingAccounts/reservations,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/reservations,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/validateDetachPaymentMethodEligibility,null,No
-no,Microsoft.Billing/validateAddress,null,No
-no,Microsoft.Billing/promotions,null,No
-no,Microsoft.Billing/promotions/checkeligibility,null,No
-no,Microsoft.Billing/billingAccounts/billingSubscriptions/elevateRole,null,No
-no,Microsoft.Billing/billingAccounts/appliedReservationOrders,null,No
-no,Microsoft.Billing/promotionalCredits,null,No
-no,Microsoft.Billing/billingAccounts/promotionalCredits,null,No
-no,Microsoft.Billing/billingAccounts/savingsPlanOrders/savingsPlans,null,No
-no,Microsoft.Billing/billingAccounts/savingsPlanOrders,null,No
-no,Microsoft.Billing/billingAccounts/savingsPlans,null,No
-no,Microsoft.Billing/billingAccounts/alerts,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/alerts,null,No
-no,Microsoft.Billing/billingAccounts/listProductRecommendations,null,No
-no,Microsoft.Billing/billingAccounts/incentiveSchedules,null,No
-no,Microsoft.Billing/billingAccounts/incentiveSchedules/milestones,null,No
-no,Microsoft.Billing/operationStatus,null,No
-no,Microsoft.Billing/transfers/operationStatus,null,No
-no,Microsoft.Billing/operationResults,null,No
-no,Microsoft.Billing/billingAccounts/operationResults,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/invoices/operationResults,null,No
-no,Microsoft.Billing/billingAccounts/billingProfiles/pricesheetDownloadOperations,null,No
-no,Microsoft.Billing/billingAccounts/billingSubscriptions/operationResults,null,No
-no,Microsoft.Billing/billingAccounts/billingSubscriptions/invoices/operationResults,null,No
-no,Microsoft.Billing/billingAccounts/enrollmentAccounts/activationStatus,null,No
-no,Microsoft.Billing/billingAccounts/invoices/operationResults,null,No
-no,Microsoft.Billing/promotionalCredits/operationResults,null,No
-no,Microsoft.Billing/billingAccounts/addresses,null,No
-no,Microsoft.BillingBenefits/savingsPlanOrders,null,No
-no,Microsoft.BillingBenefits/savingsPlanOrders/savingsPlans,null,No
-no,Microsoft.BillingBenefits/savingsPlanOrders/return,null,No
-no,Microsoft.BillingBenefits/validate,null,No
-no,Microsoft.BillingBenefits/calculateMigrationCost,null,No
-no,Microsoft.BillingBenefits/operationResults,null,No
-no,Microsoft.BillingBenefits/operations,null,No
-no,Microsoft.BillingBenefits/savingsPlanOrderAliases,null,No
-no,Microsoft.BillingBenefits/reservationOrderAliases,null,No
-no,Microsoft.BillingBenefits/savingsPlans,null,No
-no,Microsoft.BillingBenefits/incentiveSchedules,null,No
-no,Microsoft.BillingBenefits/incentiveSchedules/milestones,null,No
-no,Microsoft.BillingBenefits/maccs,null,No
-no,Microsoft.BillingBenefits/maccs/contributors,null,No
-no,Microsoft.BillingBenefits/listSellerResources,null,No
-no,Microsoft.BillingBenefits/credits,null,No
-no,Microsoft.Bing/locations,null,No
-no,Microsoft.Bing/accounts/skus,null,No
-no,Microsoft.Bing/accounts/usages,null,No
-no,Microsoft.Bing/registeredSubscriptions,null,No
-no,Microsoft.Bing/operations,null,No
-no,Microsoft.Bing/locations/operationStatuses,null,No
-yes,Microsoft.Bing/accounts,Bing Accounts,No
-no,Microsoft.BlockchainTokens/Operations,null,No
-yes,Microsoft.BotService/botServices,Bot Services,No
-no,Microsoft.BotService/botServices/channels,null,No
-no,Microsoft.BotService/botServices/connections,null,No
-no,Microsoft.BotService/listAuthServiceProviders,null,No
-no,Microsoft.BotService/listQnAMakerEndpointKeys,null,No
-no,Microsoft.BotService/hostSettings,null,No
-no,Microsoft.BotService/checkNameAvailability,null,No
-no,Microsoft.BotService/locations,null,No
-no,Microsoft.BotService/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.BotService/operations,null,No
-no,Microsoft.BotService/botServices/privateEndpointConnectionProxies,null,No
-no,Microsoft.BotService/botServices/privateEndpointConnections,null,No
-no,Microsoft.BotService/botServices/privateLinkResources,null,No
-no,Microsoft.BotService/operationResults,null,No
-yes,Microsoft.Cache/Redis,Redis Cache,Yes
-no,Microsoft.Cache/Redis/privateEndpointConnectionProxies,null,No
-no,Microsoft.Cache/Redis/privateEndpointConnectionProxies/validate,null,No
-no,Microsoft.Cache/Redis/privateEndpointConnections,null,No
-no,Microsoft.Cache/Redis/privateLinkResources,null,No
-no,Microsoft.Cache/locations/asyncOperations,null,No
-no,Microsoft.Cache/locations,null,No
-no,Microsoft.Cache/locations/operationResults,null,No
-no,Microsoft.Cache/locations/operationsStatus,null,No
-no,Microsoft.Cache/checkNameAvailability,null,No
-no,Microsoft.Cache/operations,null,No
-yes,Microsoft.Cache/redisEnterprise,Redis Cache,No
-no,Microsoft.Cache/RedisEnterprise/privateEndpointConnectionProxies,null,No
-no,Microsoft.Cache/RedisEnterprise/privateEndpointConnectionProxies/validate,null,No
-no,Microsoft.Cache/RedisEnterprise/privateEndpointConnectionProxies/operationresults,null,No
-no,Microsoft.Cache/RedisEnterprise/privateEndpointConnections,null,No
-no,Microsoft.Cache/RedisEnterprise/privateEndpointConnections/operationresults,null,No
-no,Microsoft.Cache/RedisEnterprise/privateLinkResources,null,No
-no,Microsoft.Cache/redisEnterprise/databases,null,No
-no,Microsoft.Cache/locations/checkNameAvailability,null,No
-no,Microsoft.Cache/Redis/EventGridFilters,null,No
-no,Microsoft.Capacity/resourceProviders,null,No
-no,Microsoft.Capacity/resourceProviders/locations,null,No
-no,Microsoft.Capacity/resourceProviders/locations/serviceLimits,null,No
-no,Microsoft.Capacity/resourceProviders/locations/serviceLimitsRequests,null,No
-no,Microsoft.Capacity/resources,null,No
-no,Microsoft.Capacity/reservationOrders,null,No
-yes,Microsoft.Capacity/reservationOrders/reservations,Reservation,Yes
-no,Microsoft.Capacity/listbenefits,null,No
-yes,Microsoft.Capacity/reservations,Capacity Reservations,No
-no,Microsoft.Capacity/reservationOrders/reservations/revisions,null,No
-no,Microsoft.Capacity/operations,null,No
-no,Microsoft.Capacity/catalogs,null,No
-no,Microsoft.Capacity/appliedReservations,null,No
-no,Microsoft.Capacity/checkOffers,null,No
-no,Microsoft.Capacity/checkScopes,null,No
-no,Microsoft.Capacity/calculatePrice,null,No
-no,Microsoft.Capacity/calculateExchange,null,No
-no,Microsoft.Capacity/exchange,null,No
-no,Microsoft.Capacity/reservationOrders/calculateRefund,null,No
-no,Microsoft.Capacity/reservationOrders/return,null,No
-no,Microsoft.Capacity/reservationOrders/split,null,No
-no,Microsoft.Capacity/reservationOrders/merge,null,No
-no,Microsoft.Capacity/reservationOrders/swap,null,No
-no,Microsoft.Capacity/reservationOrders/changeDirectory,null,No
-no,Microsoft.Capacity/validateReservationOrder,null,No
-no,Microsoft.Capacity/reservationOrders/availableScopes,null,No
-no,Microsoft.Capacity/reservationOrders/reservations/availableScopes,null,No
-no,Microsoft.Capacity/commercialReservationOrders,null,No
-no,Microsoft.Capacity/calculatePurchasePrice,null,No
-no,Microsoft.Capacity/placePurchaseOrder,null,No
-no,Microsoft.Capacity/checkPurchaseStatus,null,No
-no,Microsoft.Capacity/ownReservations,null,No
-no,Microsoft.Capacity/operationResults,null,No
-no,Microsoft.Capacity/listSkus,null,No
-no,Microsoft.Capacity/checkBenefitScopes,null,No
-no,Microsoft.Carbon/carbonEmissionReports,null,No
-no,Microsoft.Carbon/queryCarbonEmissionDataAvailableDateRange,null,No
-no,Microsoft.Carbon/operations,null,No
-yes,Microsoft.CertificateRegistration/certificateOrders,App Service Certificate,Yes
-no,Microsoft.CertificateRegistration/certificateOrders/certificates,null,No
-no,Microsoft.CertificateRegistration/validateCertificateRegistrationInformation,null,No
-no,Microsoft.CertificateRegistration/operations,null,No
-no,Microsoft.Certify/operations,null,No
-yes,Microsoft.ClassicCompute/domainNames,Domain Name,Yes
-no,Microsoft.ClassicCompute/domainNames/internalLoadBalancers,null,No
-no,Microsoft.ClassicCompute/checkDomainNameAvailability,null,No
-no,Microsoft.ClassicCompute/domainNames/slots,null,No
-no,Microsoft.ClassicCompute/domainNames/slots/roles,null,No
-no,Microsoft.ClassicCompute/domainNames/slots/roles/metricDefinitions,null,No
-no,Microsoft.ClassicCompute/domainNames/slots/roles/metrics,null,No
-no,Microsoft.ClassicCompute/virtualMachines,null,No
-no,Microsoft.ClassicCompute/capabilities,null,No
-no,Microsoft.ClassicCompute/domainNames/capabilities,null,No
-no,Microsoft.ClassicCompute/domainNames/serviceCertificates,null,No
-no,Microsoft.ClassicCompute/quotas,null,No
-no,Microsoft.ClassicCompute/virtualMachines/diagnosticSettings,null,No
-no,Microsoft.ClassicCompute/virtualMachines/metricDefinitions,null,No
-no,Microsoft.ClassicCompute/virtualMachines/metrics,null,No
-no,Microsoft.ClassicCompute/operations,null,No
-no,Microsoft.ClassicCompute/resourceTypes,null,No
-no,Microsoft.ClassicCompute/moveSubscriptionResources,null,No
-no,Microsoft.ClassicCompute/validateSubscriptionMoveAvailability,null,No
-no,Microsoft.ClassicCompute/operationStatuses,null,No
-no,Microsoft.ClassicCompute/operatingSystems,null,No
-no,Microsoft.ClassicCompute/operatingSystemFamilies,null,No
-no,Microsoft.ClassicInfrastructureMigrate/classicInfrastructureResources,null,No
-no,Microsoft.ClassicNetwork/virtualNetworks,null,No
-no,Microsoft.ClassicNetwork/virtualNetworks/virtualNetworkPeerings,null,No
-no,Microsoft.ClassicNetwork/virtualNetworks/remoteVirtualNetworkPeeringProxies,null,No
-no,Microsoft.ClassicNetwork/reservedIps,null,No
-no,Microsoft.ClassicNetwork/quotas,null,No
-no,Microsoft.ClassicNetwork/gatewaySupportedDevices,null,No
-no,Microsoft.ClassicNetwork/operations,null,No
-no,Microsoft.ClassicNetwork/networkSecurityGroups,null,No
-no,Microsoft.ClassicNetwork/capabilities,null,No
-no,Microsoft.ClassicNetwork/expressRouteCrossConnections,null,No
-no,Microsoft.ClassicNetwork/expressRouteCrossConnections/peerings,null,No
-yes,Microsoft.ClassicStorage/storageAccounts,Classic Storage Accounts,Yes
-no,Microsoft.ClassicStorage/quotas,null,No
-no,Microsoft.ClassicStorage/checkStorageAccountAvailability,null,No
-no,Microsoft.ClassicStorage/storageAccounts/services,null,No
-no,Microsoft.ClassicStorage/storageAccounts/services/diagnosticSettings,null,No
-no,Microsoft.ClassicStorage/storageAccounts/services/metricDefinitions,null,No
-no,Microsoft.ClassicStorage/storageAccounts/services/metrics,null,No
-no,Microsoft.ClassicStorage/storageAccounts/metricDefinitions,null,No
-no,Microsoft.ClassicStorage/storageAccounts/metrics,null,No
-no,Microsoft.ClassicStorage/capabilities,null,No
-no,Microsoft.ClassicStorage/storageAccounts/blobServices,null,No
-no,Microsoft.ClassicStorage/storageAccounts/tableServices,null,No
-no,Microsoft.ClassicStorage/storageAccounts/fileServices,null,No
-no,Microsoft.ClassicStorage/storageAccounts/queueServices,null,No
-no,Microsoft.ClassicStorage/disks,null,No
-no,Microsoft.ClassicStorage/images,null,No
-no,Microsoft.ClassicStorage/vmImages,null,No
-no,Microsoft.ClassicStorage/storageAccounts/vmImages,null,No
-no,Microsoft.ClassicStorage/publicImages,null,No
-no,Microsoft.ClassicStorage/osImages,null,No
-no,Microsoft.ClassicStorage/osPlatformImages,null,No
-no,Microsoft.ClassicStorage/operations,null,No
-no,Microsoft.ClassicSubscription/operations,null,No
-no,Microsoft.CleanRoom/Locations,null,No
-no,Microsoft.CleanRoom/Operations,null,No
-no,Microsoft.CleanRoom/Locations/OperationStatuses,null,No
-no,Microsoft.CloudHealth/Locations,null,No
-no,Microsoft.CloudHealth/Locations/operationstatuses,null,No
-no,Microsoft.CloudHealth/Operations,null,No
-no,Microsoft.CloudTest/accounts,null,No
-no,Microsoft.CloudTest/pools,null,No
-no,Microsoft.CloudTest/hostedpools,null,No
-no,Microsoft.CloudTest/images,null,No
-no,Microsoft.CloudTest/operations,null,No
-no,Microsoft.CloudTest/locations,null,No
-no,Microsoft.CloudTest/locations/operations,null,No
-no,Microsoft.CodeSigning/Locations,null,No
-no,Microsoft.CodeSigning/Locations/OperationStatuses,null,No
-no,Microsoft.CodeSigning/codeSigningAccounts,null,No
-no,Microsoft.CodeSigning/codeSigningAccounts/certificateProfiles,null,No
-no,Microsoft.CodeSigning/Operations,null,No
-no,Microsoft.CodeSigning/checkNameAvailability,null,No
-no,Microsoft.Commerce/UsageAggregates,null,No
-no,Microsoft.Commerce/RateCard,null,No
-no,Microsoft.Commerce/operations,null,No
-no,Microsoft.Communication/Locations,null,No
-yes,Microsoft.Communication/CommunicationServices,Communication service,Yes
-no,Microsoft.Communication/CommunicationServices/eventGridFilters,null,No
-no,Microsoft.Communication/operations,null,No
-no,Microsoft.Communication/registeredSubscriptions,null,No
-no,Microsoft.Communication/locations/operationStatuses,null,No
-no,Microsoft.Communication/CheckNameAvailability,null,No
-no,Microsoft.Communication/EmailServices,null,No
-no,Microsoft.Communication/EmailServices/Domains,null,No
-no,Microsoft.Communication/EmailServices/Domains/SenderUsernames,null,No
-no,Microsoft.Communication/EmailServices/Domains/SuppressionLists,null,No
-no,Microsoft.Communication/EmailServices/Domains/SuppressionLists/SuppressionListAddresses,null,No
-no,Microsoft.Community/communityTrainings,null,No
-no,Microsoft.Community/Operations,null,No
-no,Microsoft.Community/Locations,null,No
-no,Microsoft.Community/Locations/OperationStatuses,null,No
-yes,Microsoft.Compute/availabilitySets,Availability set,Yes
-yes,Microsoft.Compute/virtualMachines,Virtual Machines,Yes
-yes,Microsoft.Compute/virtualMachines/extensions,Extension,Yes
-yes,Microsoft.Compute/virtualMachineScaleSets,Virtual Machine Scale Sets,Yes
-no,Microsoft.Compute/virtualMachineScaleSets/extensions,null,No
-no,Microsoft.Compute/virtualMachineScaleSets/virtualMachines,null,No
-no,Microsoft.Compute/virtualMachineScaleSets/virtualMachines/extensions,null,No
-no,Microsoft.Compute/virtualMachineScaleSets/networkInterfaces,null,No
-no,Microsoft.Compute/virtualMachineScaleSets/virtualMachines/networkInterfaces,null,No
-no,Microsoft.Compute/virtualMachineScaleSets/publicIPAddresses,null,No
-no,Microsoft.Compute/locations,null,No
-no,Microsoft.Compute/locations/operations,null,No
-no,Microsoft.Compute/locations/vmSizes,null,No
-no,Microsoft.Compute/locations/runCommands,null,No
-no,Microsoft.Compute/locations/virtualMachines,null,No
-no,Microsoft.Compute/locations/virtualMachineScaleSets,null,No
-no,Microsoft.Compute/locations/publishers,null,No
-no,Microsoft.Compute/operations,null,No
-no,Microsoft.Compute/virtualMachines/runCommands,null,No
-no,Microsoft.Compute/virtualMachineScaleSets/applications,null,No
-no,Microsoft.Compute/virtualMachines/VMApplications,null,No
-no,Microsoft.Compute/locations/edgeZones,null,No
-no,Microsoft.Compute/locations/edgeZones/vmimages,null,No
-no,Microsoft.Compute/locations/edgeZones/publishers,null,No
-no,Microsoft.Compute/restorePointCollections,null,No
-no,Microsoft.Compute/restorePointCollections/restorePoints,null,No
-yes,Microsoft.Compute/proximityPlacementGroups,Proximity Placement Groups,No
-no,Microsoft.Compute/sshPublicKeys,null,No
-no,Microsoft.Compute/capacityReservationGroups,null,No
-no,Microsoft.Compute/capacityReservationGroups/capacityReservations,null,No
-no,Microsoft.Compute/virtualMachines/metricDefinitions,null,No
-no,Microsoft.Compute/locations/spotEvictionRates,null,No
-no,Microsoft.Compute/locations/spotPriceHistory,null,No
-no,Microsoft.Compute/locations/recommendations,null,No
-no,Microsoft.Compute/locations/sharedGalleries,null,No
-no,Microsoft.Compute/locations/communityGalleries,null,No
-no,Microsoft.Compute/sharedVMImages,null,No
-no,Microsoft.Compute/sharedVMImages/versions,null,No
-no,Microsoft.Compute/locations/artifactPublishers,null,No
-no,Microsoft.Compute/locations/capsoperations,null,No
-yes,Microsoft.Compute/galleries,Compute Gallery,Yes
-no,Microsoft.Compute/galleries/images,null,No
-no,Microsoft.Compute/galleries/images/versions,null,No
-no,Microsoft.Compute/locations/galleries,null,No
-no,Microsoft.Compute/payloadGroups,null,No
-no,Microsoft.Compute/galleries/applications,null,No
-no,Microsoft.Compute/galleries/applications/versions,null,No
-yes,Microsoft.Compute/disks,Disks,Yes
-yes,Microsoft.Compute/snapshots,Managed Disk Snapshot,Yes
-no,Microsoft.Compute/locations/diskoperations,null,No
-no,Microsoft.Compute/diskEncryptionSets,null,No
-no,Microsoft.Compute/diskAccesses,null,No
-no,Microsoft.Compute/restorePointCollections/restorePoints/diskRestorePoints,null,No
-no,Microsoft.Compute/virtualMachineScaleSets/disks,null,No
-no,Microsoft.Compute/cloudServices,null,No
-no,Microsoft.Compute/cloudServices/roles,null,No
-no,Microsoft.Compute/cloudServices/roleInstances,null,No
-no,Microsoft.Compute/locations/csoperations,null,No
-no,Microsoft.Compute/locations/cloudServiceOsVersions,null,No
-no,Microsoft.Compute/locations/cloudServiceOsFamilies,null,No
-no,Microsoft.Compute/cloudServices/networkInterfaces,null,No
-no,Microsoft.Compute/cloudServices/roleInstances/networkInterfaces,null,No
-no,Microsoft.Compute/cloudServices/publicIPAddresses,null,No
-no,Microsoft.Compute/locations/usages,null,No
-yes,Microsoft.Compute/images,Compute Images,No
-no,Microsoft.Compute/locations/diagnostics,null,No
-no,Microsoft.Compute/locations/diagnosticOperations,null,No
-no,Microsoft.Compute/locations/logAnalytics,null,No
-yes,Microsoft.Compute/hostGroups,Compute Host Groups,No
-no,Microsoft.Compute/hostGroups/hosts,null,No
-no,Microsoft.ComputeSchedule/Locations,null,No
-no,Microsoft.ConfidentialLedger/Locations,null,No
-no,Microsoft.ConfidentialLedger/Ledgers,null,No
-no,Microsoft.ConfidentialLedger/checkNameAvailability,null,No
-no,Microsoft.ConfidentialLedger/Locations/operations,null,No
-no,Microsoft.ConfidentialLedger/Locations/operationstatuses,null,No
-no,Microsoft.ConfidentialLedger/ManagedCCFs,null,No
-no,Microsoft.ConfidentialLedger/operations,null,No
-no,Microsoft.Confluent/operations,null,No
-no,Microsoft.Confluent/locations,null,No
-no,Microsoft.Confluent/locations/OperationStatuses,null,No
-no,Microsoft.Confluent/organizations,null,No
-no,Microsoft.Confluent/checkNameAvailability,null,No
-no,Microsoft.Confluent/agreements,null,No
-no,Microsoft.Confluent/validations,null,No
-no,Microsoft.Confluent/organizations/access,null,No
-no,Microsoft.Confluent/organizations/access/deleteRoleBinding,null,No
-no,Microsoft.Confluent/organizations/environments,null,No
-no,Microsoft.Confluent/organizations/environments/clusters,null,No
-no,Microsoft.Confluent/organizations/environments/schemaRegistryClusters,null,No
-no,Microsoft.Confluent/organizations/environments/clusters/createAPIKey,null,No
-no,Microsoft.Confluent/organizations/apiKeys,null,No
-no,Microsoft.Confluent/organizations/listRegions,null,No
-no,Microsoft.ConnectedCache/cacheNodes,null,No
-no,Microsoft.ConnectedCache/enterpriseCustomers,null,No
-no,Microsoft.ConnectedCache/Operations,null,No
-no,Microsoft.ConnectedCache/locations,null,No
-no,Microsoft.ConnectedCache/locations/operationstatuses,null,No
-no,Microsoft.ConnectedCache/ispCustomers,null,No
-no,Microsoft.ConnectedCache/ispCustomers/ispCacheNodes,null,No
-no,Microsoft.ConnectedCache/enterpriseMccCustomers,null,No
-no,Microsoft.ConnectedCache/enterpriseMccCustomers/enterpriseMccCacheNodes,null,No
-no,Microsoft.ConnectedCache/registeredSubscriptions,null,No
-no,Microsoft.ConnectedCredentials/locations,null,No
-no,Microsoft.ConnectedCredentials/locations/operationstatuses,null,No
-no,Microsoft.ConnectedCredentials/credentials,null,No
-no,Microsoft.ConnectedCredentials/operations,null,No
-no,microsoft.connectedopenstack/operations,null,No
-no,microsoft.connectedopenstack/locations,null,No
-no,microsoft.connectedopenstack/locations/operationStatuses,null,No
-no,Microsoft.ConnectedVehicle/locations,null,No
-no,Microsoft.ConnectedVehicle/operations,null,No
-no,Microsoft.ConnectedVehicle/Locations/OperationStatuses,null,No
-no,Microsoft.ConnectedVehicle/checkNameAvailability,null,No
-no,Microsoft.ConnectedVehicle/registeredSubscriptions,null,No
-no,Microsoft.ConnectedVMwarevSphere/locations,null,No
-no,Microsoft.ConnectedVMwarevSphere/locations/operationstatuses,null,No
-no,Microsoft.ConnectedVMwarevSphere/VCenters,null,No
-no,Microsoft.ConnectedVMwarevSphere/resourcepools,null,No
-no,Microsoft.ConnectedVMwarevSphere/virtualnetworks,null,No
-no,Microsoft.ConnectedVMwarevSphere/virtualmachinetemplates,null,No
-no,Microsoft.ConnectedVMwarevSphere/operations,null,No
-no,Microsoft.ConnectedVMwarevSphere/virtualmachines,null,No
-no,Microsoft.ConnectedVMwarevSphere/vcenters/inventoryitems,null,No
-no,Microsoft.ConnectedVMwarevSphere/virtualmachines/hybrididentitymetadata,null,No
-no,Microsoft.ConnectedVMwarevSphere/virtualmachines/extensions,null,No
-no,Microsoft.ConnectedVMwarevSphere/virtualmachines/guestagents,null,No
-no,Microsoft.ConnectedVMwarevSphere/clusters,null,No
-no,Microsoft.ConnectedVMwarevSphere/datastores,null,No
-no,Microsoft.ConnectedVMwarevSphere/hosts,null,No
-no,Microsoft.ConnectedVMwarevSphere/virtualmachineinstances,null,No
-no,Microsoft.Consumption/Forecasts,null,No
-no,Microsoft.Consumption/AggregatedCost,null,No
-no,Microsoft.Consumption/tenants,null,No
-no,Microsoft.Consumption/ReservationRecommendations,null,No
-no,Microsoft.Consumption/ReservationRecommendationDetails,null,No
-no,Microsoft.Consumption/ReservationSummaries,null,No
-no,Microsoft.Consumption/ReservationTransactions,null,No
-no,Microsoft.Consumption/Balances,null,No
-no,Microsoft.Consumption/Marketplaces,null,No
-no,Microsoft.Consumption/Pricesheets,null,No
-no,Microsoft.Consumption/ReservationDetails,null,No
-no,Microsoft.Consumption/Budgets,null,No
-no,Microsoft.Consumption/CostTags,null,No
-no,Microsoft.Consumption/Tags,null,No
-no,Microsoft.Consumption/Terms,null,No
-no,Microsoft.Consumption/UsageDetails,null,No
-no,Microsoft.Consumption/Charges,null,No
-no,Microsoft.Consumption/credits,null,No
-no,Microsoft.Consumption/events,null,No
-no,Microsoft.Consumption/lots,null,No
-no,Microsoft.Consumption/products,null,No
-no,Microsoft.Consumption/OperationStatus,null,No
-no,Microsoft.Consumption/OperationResults,null,No
-no,Microsoft.Consumption/Operations,null,No
-yes,Microsoft.ContainerInstance/containerGroups,Container Instance Container Groups,No
-no,Microsoft.ContainerInstance/serviceAssociationLinks,null,No
-no,Microsoft.ContainerInstance/locations,null,No
-no,Microsoft.ContainerInstance/locations/capabilities,null,No
-no,Microsoft.ContainerInstance/locations/usages,null,No
-no,Microsoft.ContainerInstance/locations/operations,null,No
-no,Microsoft.ContainerInstance/locations/operationresults,null,No
-no,Microsoft.ContainerInstance/operations,null,No
-no,Microsoft.ContainerInstance/locations/cachedImages,null,No
-no,Microsoft.ContainerInstance/locations/validateDeleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.ContainerInstance/locations/deleteVirtualNetworkOrSubnets,null,No
-yes,Microsoft.ContainerRegistry/registries,Container Registry,Yes
-no,Microsoft.ContainerRegistry/registries/cacheRules,null,No
-no,Microsoft.ContainerRegistry/registries/credentialSets,null,No
-no,Microsoft.ContainerRegistry/registries/connectedRegistries,null,No
-no,Microsoft.ContainerRegistry/registries/connectedRegistries/deactivate,null,No
-no,Microsoft.ContainerRegistry/registries/scopeMaps,null,No
-no,Microsoft.ContainerRegistry/registries/tokens,null,No
-no,Microsoft.ContainerRegistry/registries/generateCredentials,null,No
-no,Microsoft.ContainerRegistry/registries/privateEndpointConnections,null,No
-no,Microsoft.ContainerRegistry/registries/privateEndpointConnectionProxies,null,No
-no,Microsoft.ContainerRegistry/registries/privateEndpointConnectionProxies/validate,null,No
-no,Microsoft.ContainerRegistry/registries/privateLinkResources,null,No
-no,Microsoft.ContainerRegistry/registries/importImage,null,No
-no,Microsoft.ContainerRegistry/registries/exportPipelines,null,No
-no,Microsoft.ContainerRegistry/registries/importPipelines,null,No
-no,Microsoft.ContainerRegistry/registries/pipelineRuns,null,No
-no,Microsoft.ContainerRegistry/registries/listBuildSourceUploadUrl,null,No
-no,Microsoft.ContainerRegistry/registries/scheduleRun,null,No
-no,Microsoft.ContainerRegistry/registries/runs,null,No
-no,Microsoft.ContainerRegistry/registries/taskRuns,null,No
-no,Microsoft.ContainerRegistry/registries/taskRuns/listDetails,null,No
-no,Microsoft.ContainerRegistry/registries/agentPools,null,No
-no,Microsoft.ContainerRegistry/registries/agentPoolsOperationResults,null,No
-no,Microsoft.ContainerRegistry/registries/agentPools/listQueueStatus,null,No
-no,Microsoft.ContainerRegistry/registries/runs/listLogSasUrl,null,No
-no,Microsoft.ContainerRegistry/registries/runs/cancel,null,No
-no,Microsoft.ContainerRegistry/registries/tasks,null,No
-no,Microsoft.ContainerRegistry/registries/tasks/listDetails,null,No
-no,Microsoft.ContainerRegistry/registries/replications,null,No
-no,Microsoft.ContainerRegistry/registries/webhooks,null,No
-no,Microsoft.ContainerRegistry/registries/webhooks/ping,null,No
-no,Microsoft.ContainerRegistry/registries/webhooks/getCallbackConfig,null,No
-no,Microsoft.ContainerRegistry/registries/webhooks/listEvents,null,No
-no,Microsoft.ContainerRegistry/locations/operationResults,null,No
-no,Microsoft.ContainerRegistry/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.ContainerRegistry/registries/listCredentials,null,No
-no,Microsoft.ContainerRegistry/registries/regenerateCredential,null,No
-no,Microsoft.ContainerRegistry/registries/listUsages,null,No
-no,Microsoft.ContainerRegistry/registries/listPolicies,null,No
-no,Microsoft.ContainerRegistry/registries/updatePolicies,null,No
-no,Microsoft.ContainerRegistry/registries/eventGridFilters,null,No
-no,Microsoft.ContainerRegistry/checkNameAvailability,null,No
-no,Microsoft.ContainerRegistry/operations,null,No
-no,Microsoft.ContainerRegistry/locations,null,No
-no,Microsoft.ContainerService/ManagedClusters/eventGridFilters,null,No
-no,Microsoft.ContainerService/fleetMemberships,null,No
-yes,Microsoft.ContainerService/fleets,Kubernetes fleet manager | PREVIEW,Yes
-no,Microsoft.ContainerService/fleets/members,null,No
-no,Microsoft.ContainerService/fleets/updateRuns,null,No
-no,Microsoft.ContainerService/fleets/updateStrategies,null,No
-no,Microsoft.ContainerService/locations,null,No
-no,Microsoft.ContainerService/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.ContainerService/locations/operationresults,null,No
-no,Microsoft.ContainerService/locations/operations,null,No
-no,Microsoft.ContainerService/locations/orchestrators,null,No
-no,Microsoft.ContainerService/locations/kubernetesVersions,null,No
-no,Microsoft.ContainerService/locations/nodeImageVersions,null,No
-no,Microsoft.ContainerService/locations/usages,null,No
-no,Microsoft.ContainerService/locations/osOptions,null,No
-no,Microsoft.ContainerService/locations/safeguardsVersions,null,No
-no,Microsoft.ContainerService/locations/guardrailsVersions,null,No
-no,Microsoft.ContainerService/locations/trustedAccessRoles,null,No
-no,Microsoft.ContainerService/locations/meshRevisionProfiles,null,No
-yes,Microsoft.ContainerService/managedClusters,Aks,Yes
-no,Microsoft.ContainerService/managedclustersnapshots,null,No
-no,Microsoft.ContainerService/operations,null,No
-no,Microsoft.ContainerService/snapshots,null,No
-no,Microsoft.CostManagement/Connectors,null,No
-no,Microsoft.CostManagement/CloudConnectors,null,No
-no,Microsoft.CostManagement/CheckConnectorEligibility,null,No
-no,Microsoft.CostManagement/ExternalBillingAccounts,null,No
-no,Microsoft.CostManagement/ExternalBillingAccounts/Dimensions,null,No
-no,Microsoft.CostManagement/ExternalBillingAccounts/Query,null,No
-no,Microsoft.CostManagement/ExternalSubscriptions/Dimensions,null,No
-no,Microsoft.CostManagement/ExternalSubscriptions/Query,null,No
-no,Microsoft.CostManagement/ExternalSubscriptions,null,No
-no,Microsoft.CostManagement/Forecast,null,No
-no,Microsoft.CostManagement/ExternalSubscriptions/Forecast,null,No
-no,Microsoft.CostManagement/ExternalBillingAccounts/Forecast,null,No
-no,Microsoft.CostManagement/Settings,null,No
-no,Microsoft.CostManagement/operations,null,No
-no,Microsoft.CostManagement/register,null,No
-no,Microsoft.CostManagement/Query,null,No
-no,Microsoft.CostManagement/Dimensions,null,No
-no,Microsoft.CostManagement/Budgets,null,No
-no,Microsoft.CostManagement/ExternalSubscriptions/Alerts,null,No
-no,Microsoft.CostManagement/ExternalBillingAccounts/Alerts,null,No
-no,Microsoft.CostManagement/Alerts,null,No
-no,Microsoft.CostManagement/showbackRules,null,No
-no,Microsoft.CostManagement/costAllocationRules,null,No
-no,Microsoft.CostManagement/Exports,null,No
-no,Microsoft.CostManagement/Reports,null,No
-no,Microsoft.CostManagement/Reportconfigs,null,No
-no,Microsoft.CostManagement/BillingAccounts,null,No
-no,Microsoft.CostManagement/Departments,null,No
-no,Microsoft.CostManagement/EnrollmentAccounts,null,No
-no,Microsoft.CostManagement/Views,null,No
-no,Microsoft.CostManagement/Publish,null,No
-no,Microsoft.CostManagement/ScheduledActions,null,No
-no,Microsoft.CostManagement/CheckNameAvailability,null,No
-no,Microsoft.CostManagement/BenefitUtilizationSummaries,null,No
-no,Microsoft.CostManagement/BenefitRecommendations,null,No
-no,Microsoft.CostManagement/Insights,null,No
-no,Microsoft.CostManagement/fetchPrices,null,No
-no,Microsoft.CostManagement/fetchMicrosoftPrices,null,No
-no,Microsoft.CostManagement/fetchMarketplacePrices,null,No
-no,Microsoft.CostManagement/calculatePrice,null,No
-no,Microsoft.CostManagement/CalculateCost,null,No
-no,Microsoft.CostManagement/GenerateBenefitUtilizationSummariesReport,null,No
-no,Microsoft.CostManagement/BenefitUtilizationSummariesOperationResults,null,No
-no,Microsoft.CostManagement/GenerateReservationDetailsReport,null,No
-no,Microsoft.CostManagement/ReservationDetailsOperationResults,null,No
-no,Microsoft.CostManagement/GenerateDetailedCostReport,null,No
-no,Microsoft.CostManagement/GenerateCostDetailsReport,null,No
-no,Microsoft.CostManagement/CostDetailsOperationResults,null,No
-no,Microsoft.CostManagement/OperationStatus,null,No
-no,Microsoft.CostManagement/OperationResults,null,No
-no,Microsoft.CostManagement/Pricesheets,null,No
-no,Microsoft.CostManagement/MarkupRules,null,No
-no,Microsoft.CostManagement/StartConversation,null,No
-no,Microsoft.CostManagement/SendMessage,null,No
-no,Microsoft.CostManagementExports/Operations,null,No
-no,Microsoft.CustomerLockbox/operations,null,No
-no,Microsoft.CustomerLockbox/TenantOptedIn,null,No
-no,Microsoft.CustomerLockbox/EnableLockbox,null,No
-no,Microsoft.CustomerLockbox/DisableLockbox,null,No
-no,Microsoft.CustomerLockbox/requests,null,No
-no,Microsoft.CustomProviders/resourceProviders,null,No
-no,Microsoft.CustomProviders/resourceProviders/operationResults,null,No
-no,Microsoft.CustomProviders/resourceProviders/operationStatuses,null,No
-no,Microsoft.CustomProviders/associations,null,No
-no,Microsoft.CustomProviders/operations,null,No
-no,Microsoft.CustomProviders/locations,null,No
-no,Microsoft.CustomProviders/locations/operationStatuses,null,No
-no,Microsoft.CustomProviders/locations/operationResults,null,No
-no,Microsoft.D365CustomerInsights/instances,null,No
-no,Microsoft.D365CustomerInsights/operations,null,No
-no,Microsoft.DatabaseWatcher/watchers,null,No
-no,Microsoft.DatabaseWatcher/watchers/targets,null,No
-no,Microsoft.DatabaseWatcher/locations,null,No
-no,Microsoft.DatabaseWatcher/locations/operationStatuses,null,No
-no,Microsoft.DatabaseWatcher/operations,null,No
-no,Microsoft.DatabaseWatcher/watchers/sharedPrivateLinkResources,null,No
-yes,Microsoft.DataBox/jobs,DataBox Jobs,No
-no,Microsoft.DataBox/locations,null,No
-no,Microsoft.DataBox/locations/validateAddress,null,No
-no,Microsoft.DataBox/locations/checkNameAvailability,null,No
-no,Microsoft.DataBox/locations/operationresults,null,No
-no,Microsoft.DataBox/operations,null,No
-no,Microsoft.DataBox/locations/availableSkus,null,No
-no,Microsoft.DataBox/locations/validateInputs,null,No
-no,Microsoft.DataBox/locations/regionConfiguration,null,No
-no,Microsoft.DataBox/jobs/eventGridFilters,null,No
-yes,Microsoft.DataBoxEdge/DataBoxEdgeDevices,DataBox Edge Devices,No
-no,Microsoft.DataBoxEdge/DataBoxEdgeDevices/checkNameAvailability,null,No
-no,Microsoft.DataBoxEdge/operations,null,No
-no,Microsoft.DataBoxEdge/availableSkus,null,No
-yes,Microsoft.Databricks/workspaces,Azure Databricks,Yes
-no,Microsoft.Databricks/accessConnectors,null,No
-no,Microsoft.Databricks/workspaces/virtualNetworkPeerings,null,No
-no,Microsoft.Databricks/workspaces/dbWorkspaces,null,No
-no,Microsoft.Databricks/operations,null,No
-no,Microsoft.Databricks/locations,null,No
-no,Microsoft.Databricks/locations/operationstatuses,null,No
-no,Microsoft.Databricks/locations/getNetworkPolicies,null,No
-no,Microsoft.DataCatalog/catalogs,null,No
-no,Microsoft.DataCatalog/checkNameAvailability,null,No
-no,Microsoft.DataCatalog/operations,null,No
-no,Microsoft.DataCatalog/locations,null,No
-no,Microsoft.DataCatalog/locations/jobs,null,No
-no,Microsoft.Datadog/registeredSubscriptions,null,No
-no,Microsoft.Datadog/locations,null,No
-no,Microsoft.Datadog/locations/operationStatuses,null,No
-no,Microsoft.Datadog/operations,null,No
-no,Microsoft.Datadog/monitors,null,No
-no,Microsoft.Datadog/monitors/tagRules,null,No
-no,Microsoft.Datadog/monitors/listMonitoredResources,null,No
-no,Microsoft.Datadog/monitors/listApiKeys,null,No
-no,Microsoft.Datadog/monitors/getDefaultKey,null,No
-no,Microsoft.Datadog/monitors/setDefaultKey,null,No
-no,Microsoft.Datadog/monitors/singleSignOnConfigurations,null,No
-no,Microsoft.Datadog/monitors/listHosts,null,No
-no,Microsoft.Datadog/monitors/listLinkedResources,null,No
-no,Microsoft.Datadog/monitors/refreshSetPasswordLink,null,No
-no,Microsoft.Datadog/agreements,null,No
-no,Microsoft.Datadog/monitors/monitoredSubscriptions,null,No
-no,Microsoft.Datadog/subscriptionStatuses,null,No
-yes,Microsoft.DataLakeAnalytics/accounts,Azure Data Lake Analytics,Yes
-no,Microsoft.DataLakeAnalytics/accounts/dataLakeStoreAccounts,null,No
-no,Microsoft.DataLakeAnalytics/accounts/storageAccounts,null,No
-no,Microsoft.DataLakeAnalytics/accounts/storageAccounts/containers,null,No
-no,Microsoft.DataLakeAnalytics/accounts/storageAccounts/containers/listSasTokens,null,No
-no,Microsoft.DataLakeAnalytics/locations,null,No
-no,Microsoft.DataLakeAnalytics/locations/operationresults,null,No
-no,Microsoft.DataLakeAnalytics/locations/checkNameAvailability,null,No
-no,Microsoft.DataLakeAnalytics/locations/capability,null,No
-no,Microsoft.DataLakeAnalytics/locations/usages,null,No
-no,Microsoft.DataLakeAnalytics/operations,null,No
-yes,Microsoft.DataLakeStore/accounts,Azure Data Lake Storage,Yes
-no,Microsoft.DataLakeStore/accounts/firewallRules,null,No
-no,Microsoft.DataLakeStore/accounts/eventGridFilters,null,No
-no,Microsoft.DataLakeStore/locations,null,No
-no,Microsoft.DataLakeStore/locations/operationresults,null,No
-no,Microsoft.DataLakeStore/locations/checkNameAvailability,null,No
-no,Microsoft.DataLakeStore/locations/capability,null,No
-no,Microsoft.DataLakeStore/locations/usages,null,No
-no,Microsoft.DataLakeStore/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.DataLakeStore/operations,null,No
-no,Microsoft.DataMigration/locations,null,No
-no,Microsoft.DataMigration/services,null,No
-no,Microsoft.DataMigration/services/projects,null,No
-no,Microsoft.DataMigration/locations/operationResults,null,No
-no,Microsoft.DataMigration/locations/operationStatuses,null,No
-no,Microsoft.DataMigration/locations/checkNameAvailability,null,No
-no,Microsoft.DataMigration/operations,null,No
-no,Microsoft.DataMigration/migrationServices,null,No
-no,Microsoft.DataMigration/SqlMigrationServices,null,No
-no,Microsoft.DataMigration/DatabaseMigrations,null,No
-no,Microsoft.DataMigration/Locations/OperationTypes,null,No
-no,Microsoft.DataMigration/locations/migrationServiceOperationResults,null,No
-no,Microsoft.DataMigration/Locations/sqlMigrationServiceOperationResults,null,No
-no,Microsoft.DataProtection/BackupVaults,null,No
-no,Microsoft.DataProtection/ResourceGuards,null,No
-no,Microsoft.DataProtection/operations,null,No
-no,Microsoft.DataProtection/locations,null,No
-no,Microsoft.DataProtection/locations/operationResults,null,No
-no,Microsoft.DataProtection/locations/operationStatus,null,No
-no,Microsoft.DataProtection/locations/checkNameAvailability,null,No
-no,Microsoft.DataProtection/locations/checkFeatureSupport,null,No
-no,Microsoft.DataProtection/backupInstances,null,No
-no,Microsoft.DataProtection/locations/fetchSecondaryRecoveryPoints,null,No
-no,Microsoft.DataProtection/locations/fetchCrossRegionRestoreJobs,null,No
-no,Microsoft.DataProtection/locations/fetchCrossRegionRestoreJob,null,No
-no,Microsoft.DataProtection/locations/validateCrossRegionRestore,null,No
-no,Microsoft.DataProtection/locations/crossRegionRestore,null,No
-no,Microsoft.DataReplication/replicationVaults,null,No
-no,Microsoft.DataReplication/replicationFabrics,null,No
-no,Microsoft.DataReplication/operations,null,No
-yes,Microsoft.DataShare/accounts,DataShare Accounts,No
-no,Microsoft.DataShare/accounts/shares,null,No
-no,Microsoft.DataShare/accounts/shares/datasets,null,No
-no,Microsoft.DataShare/accounts/shares/synchronizationSettings,null,No
-no,Microsoft.DataShare/accounts/shares/invitations,null,No
-no,Microsoft.DataShare/accounts/sharesubscriptions,null,No
-no,Microsoft.DataShare/accounts/shares/providersharesubscriptions,null,No
-no,Microsoft.DataShare/accounts/sharesubscriptions/datasetmappings,null,No
-no,Microsoft.DataShare/accounts/sharesubscriptions/triggers,null,No
-no,Microsoft.DataShare/accounts/sharesubscriptions/consumerSourceDataSets,null,No
-no,Microsoft.DataShare/listinvitations,null,No
-no,Microsoft.DataShare/locations,null,No
-no,Microsoft.DataShare/locations/operationResults,null,No
-no,Microsoft.DataShare/locations/registerEmail,null,No
-no,Microsoft.DataShare/locations/activateEmail,null,No
-no,Microsoft.DataShare/locations/rejectInvitation,null,No
-no,Microsoft.DataShare/locations/consumerInvitations,null,No
-no,Microsoft.DataShare/operations,null,No
-no,Microsoft.DBforMariaDB/operations,null,No
-yes,Microsoft.DBforMariaDB/servers,MariaDB server,Yes
-no,Microsoft.DBforMariaDB/servers/recoverableServers,null,No
-no,Microsoft.DBforMariaDB/servers/virtualNetworkRules,null,No
-no,Microsoft.DBforMariaDB/checkNameAvailability,null,No
-no,Microsoft.DBforMariaDB/locations,null,No
-no,Microsoft.DBforMariaDB/locations/operationResults,null,No
-no,Microsoft.DBforMariaDB/locations/azureAsyncOperation,null,No
-no,Microsoft.DBforMariaDB/locations/performanceTiers,null,No
-no,Microsoft.DBforMariaDB/locations/securityAlertPoliciesAzureAsyncOperation,null,No
-no,Microsoft.DBforMariaDB/locations/privateEndpointConnectionProxyOperationResults,null,No
-no,Microsoft.DBforMariaDB/locations/privateEndpointConnectionProxyAzureAsyncOperation,null,No
-no,Microsoft.DBforMariaDB/locations/privateEndpointConnectionOperationResults,null,No
-no,Microsoft.DBforMariaDB/locations/privateEndpointConnectionAzureAsyncOperation,null,No
-no,Microsoft.DBforMariaDB/locations/securityAlertPoliciesOperationResults,null,No
-no,Microsoft.DBforMariaDB/locations/recommendedActionSessionsAzureAsyncOperation,null,No
-no,Microsoft.DBforMariaDB/locations/recommendedActionSessionsOperationResults,null,No
-no,Microsoft.DBforMariaDB/servers/topQueryStatistics,null,No
-no,Microsoft.DBforMariaDB/servers/queryTexts,null,No
-no,Microsoft.DBforMariaDB/servers/waitStatistics,null,No
-no,Microsoft.DBforMariaDB/servers/resetQueryPerformanceInsightData,null,No
-no,Microsoft.DBforMariaDB/servers/advisors,null,No
-no,Microsoft.DBforMariaDB/servers/privateLinkResources,null,No
-no,Microsoft.DBforMariaDB/servers/privateEndpointConnections,null,No
-no,Microsoft.DBforMariaDB/servers/privateEndpointConnectionProxies,null,No
-no,Microsoft.DBforMariaDB/servers/keys,null,No
-no,Microsoft.DBforMariaDB/locations/serverKeyAzureAsyncOperation,null,No
-no,Microsoft.DBforMariaDB/locations/serverKeyOperationResults,null,No
-no,Microsoft.DBforMariaDB/servers/start,null,No
-no,Microsoft.DBforMariaDB/servers/stop,null,No
-no,Microsoft.DBforMySQL/operations,null,No
-yes,Microsoft.DBforMySQL/servers,Azure Database for MySQL,Yes
-yes,Microsoft.DBforMySQL/flexibleServers,Azure Database for MySQL Flexible,Yes
-no,Microsoft.DBforMySQL/servers/recoverableServers,null,No
-no,Microsoft.DBforMySQL/servers/virtualNetworkRules,null,No
-no,Microsoft.DBforMySQL/locations/capabilities,null,No
-no,Microsoft.DBforMySQL/locations/capabilitySets,null,No
-no,Microsoft.DBforMySQL/locations/checkNameAvailability,null,No
-no,Microsoft.DBforMySQL/checkNameAvailability,null,No
-no,Microsoft.DBforMySQL/assessForMigration,null,No
-no,Microsoft.DBforMySQL/getPrivateDnsZoneSuffix,null,No
-no,Microsoft.DBforMySQL/locations/checkVirtualNetworkSubnetUsage,null,No
-no,Microsoft.DBforMySQL/locations/listMigrations,null,No
-no,Microsoft.DBforMySQL/locations/updateMigration,null,No
-no,Microsoft.DBforMySQL/locations,null,No
-no,Microsoft.DBforMySQL/locations/operationResults,null,No
-no,Microsoft.DBforMySQL/locations/operationProgress,null,No
-no,Microsoft.DBforMySQL/locations/azureAsyncOperation,null,No
-no,Microsoft.DBforMySQL/locations/administratorOperationResults,null,No
-no,Microsoft.DBforMySQL/locations/administratorAzureAsyncOperation,null,No
-no,Microsoft.DBforMySQL/locations/privateEndpointConnectionProxyOperationResults,null,No
-no,Microsoft.DBforMySQL/locations/privateEndpointConnectionProxyAzureAsyncOperation,null,No
-no,Microsoft.DBforMySQL/locations/privateEndpointConnectionOperationResults,null,No
-no,Microsoft.DBforMySQL/locations/privateEndpointConnectionAzureAsyncOperation,null,No
-no,Microsoft.DBforMySQL/locations/performanceTiers,null,No
-no,Microsoft.DBforMySQL/locations/securityAlertPoliciesAzureAsyncOperation,null,No
-no,Microsoft.DBforMySQL/locations/securityAlertPoliciesOperationResults,null,No
-no,Microsoft.DBforMySQL/locations/recommendedActionSessionsAzureAsyncOperation,null,No
-no,Microsoft.DBforMySQL/locations/recommendedActionSessionsOperationResults,null,No
-no,Microsoft.DBforMySQL/servers/topQueryStatistics,null,No
-no,Microsoft.DBforMySQL/servers/queryTexts,null,No
-no,Microsoft.DBforMySQL/servers/waitStatistics,null,No
-no,Microsoft.DBforMySQL/servers/resetQueryPerformanceInsightData,null,No
-no,Microsoft.DBforMySQL/servers/advisors,null,No
-no,Microsoft.DBforMySQL/servers/privateLinkResources,null,No
-no,Microsoft.DBforMySQL/servers/privateEndpointConnections,null,No
-no,Microsoft.DBforMySQL/servers/privateEndpointConnectionProxies,null,No
-no,Microsoft.DBforMySQL/servers/keys,null,No
-no,Microsoft.DBforMySQL/locations/serverKeyAzureAsyncOperation,null,No
-no,Microsoft.DBforMySQL/locations/serverKeyOperationResults,null,No
-no,Microsoft.DBforMySQL/servers/upgrade,null,No
-no,Microsoft.DBforPostgreSQL/operations,null,No
-yes,Microsoft.DBforPostgreSQL/servers,Azure Database for PostgreSQL,Yes
-yes,Microsoft.DBforPostgreSQL/serverGroupsv2,Hyperscale (Citus) server group,Yes
-yes,Microsoft.DBforPostgreSQL/flexibleServers,Azure Database for PostgreSQL Flexible,Yes
-no,Microsoft.DBforPostgreSQL/locations/capabilities,null,No
-no,Microsoft.DBforPostgreSQL/locations/checkNameAvailability,null,No
-no,Microsoft.DBforPostgreSQL/servers/recoverableServers,null,No
-no,Microsoft.DBforPostgreSQL/servers/virtualNetworkRules,null,No
-no,Microsoft.DBforPostgreSQL/checkNameAvailability,null,No
-no,Microsoft.DBforPostgreSQL/availableEngineVersions,null,No
-no,Microsoft.DBforPostgreSQL/getPrivateDnsZoneSuffix,null,No
-no,Microsoft.DBforPostgreSQL/locations,null,No
-no,Microsoft.DBforPostgreSQL/locations/operationResults,null,No
-no,Microsoft.DBforPostgreSQL/locations/azureAsyncOperation,null,No
-no,Microsoft.DBforPostgreSQL/locations/administratorOperationResults,null,No
-no,Microsoft.DBforPostgreSQL/locations/administratorAzureAsyncOperation,null,No
-no,Microsoft.DBforPostgreSQL/locations/checkVirtualNetworkSubnetUsage,null,No
-no,Microsoft.DBforPostgreSQL/locations/privateEndpointConnectionProxyOperationResults,null,No
-no,Microsoft.DBforPostgreSQL/locations/privateEndpointConnectionProxyAzureAsyncOperation,null,No
-no,Microsoft.DBforPostgreSQL/locations/privateEndpointConnectionOperationResults,null,No
-no,Microsoft.DBforPostgreSQL/locations/privateEndpointConnectionAzureAsyncOperation,null,No
-no,Microsoft.DBforPostgreSQL/locations/performanceTiers,null,No
-no,Microsoft.DBforPostgreSQL/locations/securityAlertPoliciesAzureAsyncOperation,null,No
-no,Microsoft.DBforPostgreSQL/locations/securityAlertPoliciesOperationResults,null,No
-no,Microsoft.DBforPostgreSQL/locations/recommendedActionSessionsAzureAsyncOperation,null,No
-no,Microsoft.DBforPostgreSQL/locations/recommendedActionSessionsOperationResults,null,No
-no,Microsoft.DBforPostgreSQL/servers/topQueryStatistics,null,No
-no,Microsoft.DBforPostgreSQL/servers/queryTexts,null,No
-no,Microsoft.DBforPostgreSQL/servers/waitStatistics,null,No
-no,Microsoft.DBforPostgreSQL/servers/resetQueryPerformanceInsightData,null,No
-no,Microsoft.DBforPostgreSQL/servers/advisors,null,No
-no,Microsoft.DBforPostgreSQL/servers/privateLinkResources,null,No
-no,Microsoft.DBforPostgreSQL/servers/privateEndpointConnections,null,No
-no,Microsoft.DBforPostgreSQL/servers/privateEndpointConnectionProxies,null,No
-no,Microsoft.DBforPostgreSQL/servers/keys,null,No
-no,Microsoft.DBforPostgreSQL/locations/serverKeyAzureAsyncOperation,null,No
-no,Microsoft.DBforPostgreSQL/locations/serverKeyOperationResults,null,No
-no,Microsoft.DBforPostgreSQL/locations/getCachedServerName,null,No
-no,Microsoft.DelegatedNetwork/operations,null,No
-yes,Microsoft.DesktopVirtualization/workspaces,Desktop Virtualization Workspaces,No
-no,Microsoft.DesktopVirtualization/applicationgroups,null,No
-no,Microsoft.DesktopVirtualization/applicationgroups/applications,null,No
-no,Microsoft.DesktopVirtualization/applicationgroups/desktops,null,No
-no,Microsoft.DesktopVirtualization/applicationgroups/startmenuitems,null,No
-yes,Microsoft.DesktopVirtualization/hostpools,Windows Virtual Desktop,Yes
-no,Microsoft.DesktopVirtualization/hostpools/msixpackages,null,No
-no,Microsoft.DesktopVirtualization/hostpools/sessionhosts,null,No
-no,Microsoft.DesktopVirtualization/hostpools/sessionhosts/usersessions,null,No
-no,Microsoft.DesktopVirtualization/hostpools/usersessions,null,No
-yes,Microsoft.DesktopVirtualization/scalingplans,Desktop Virtualization Scaling Plans,Yes
-no,Microsoft.DesktopVirtualization/appattachpackages,null,No
-no,Microsoft.DesktopVirtualization/operations,null,No
-no,Microsoft.DevAI/Locations,null,No
-no,Microsoft.DevAI/Locations/operationstatuses,null,No
-no,Microsoft.DevAI/instances,null,No
-no,Microsoft.DevAI/instances/experiments,null,No
-no,Microsoft.DevAI/instances/sandboxes,null,No
-no,Microsoft.DevAI/instances/sandboxes/experiments,null,No
-no,Microsoft.DevAI/Operations,null,No
-no,Microsoft.DevAI/registeredSubscriptions,null,No
-no,Microsoft.DevCenter/operations,null,No
-no,Microsoft.DevCenter/Locations,null,No
-no,Microsoft.DevCenter/Locations/OperationStatuses,null,No
-no,Microsoft.DevCenter/devcenters,null,No
-no,Microsoft.DevCenter/devcenters/catalogs,null,No
-no,Microsoft.DevCenter/devcenters/attachednetworks,null,No
-no,Microsoft.DevCenter/devcenters/devboxdefinitions,null,No
-no,Microsoft.DevCenter/devcenters/environmentTypes,null,No
-no,Microsoft.DevCenter/devcenters/galleries,null,No
-no,Microsoft.DevCenter/devcenters/galleries/images/versions,null,No
-no,Microsoft.DevCenter/devcenters/galleries/images,null,No
-no,Microsoft.DevCenter/devcenters/images,null,No
-no,Microsoft.DevCenter/networkconnections,null,No
-no,Microsoft.DevCenter/networkconnections/healthchecks,null,No
-no,Microsoft.DevCenter/projects,null,No
-no,Microsoft.DevCenter/projects/attachednetworks,null,No
-no,Microsoft.DevCenter/projects/environmentTypes,null,No
-no,Microsoft.DevCenter/projects/pools,null,No
-no,Microsoft.DevCenter/projects/pools/schedules,null,No
-no,Microsoft.DevCenter/projects/devboxdefinitions,null,No
-no,Microsoft.DevCenter/projects/allowedEnvironmentTypes,null,No
-no,Microsoft.DevCenter/checkNameAvailability,null,No
-no,Microsoft.DevCenter/networkconnections/outboundNetworkDependenciesEndpoints,null,No
-no,Microsoft.DevCenter/Locations/usages,null,No
-no,Microsoft.DevCenter/devcenters/catalogs/devboxdefinitions,null,No
-no,Microsoft.DevCenter/devcenters/catalogs/environmentDefinitions,null,No
-no,Microsoft.DevCenter/devcenters/catalogs/tasks,null,No
-no,Microsoft.DevCenter/checkScopedNameAvailability,null,No
-no,Microsoft.DevCenter/projects/catalogs,null,No
-no,Microsoft.DevCenter/projects/catalogs/environmentDefinitions,null,No
-no,Microsoft.DevelopmentWindows365/DevelopmentCloudPcDelegatedMsis,null,No
-no,Microsoft.DevHub/operations,null,No
-no,Microsoft.DevHub/workflows,null,No
-no,Microsoft.DevHub/locations,null,No
-no,Microsoft.DevHub/locations/githuboauth,null,No
-no,Microsoft.DevHub/locations/generatePreviewArtifacts,null,No
-no,Microsoft.DeviceRegistry/locations,null,No
-no,Microsoft.DeviceRegistry/operations,null,No
-no,Microsoft.DeviceRegistry/operationStatuses,null,No
-no,Microsoft.DeviceRegistry/locations/operationStatuses,null,No
-no,Microsoft.DeviceRegistry/assets,null,No
-no,Microsoft.DeviceRegistry/assetEndpointProfiles,null,No
-no,Microsoft.Devices/checkNameAvailability,null,No
-no,Microsoft.Devices/checkProvisioningServiceNameAvailability,null,No
-no,Microsoft.Devices/usages,null,No
-no,Microsoft.Devices/operations,null,No
-no,Microsoft.Devices/operationResults,null,No
-no,Microsoft.Devices/provisioningServiceOperationResults,null,No
-no,Microsoft.Devices/locations/provisioningServiceOperationResults,null,No
-no,Microsoft.Devices/locations,null,No
-no,Microsoft.Devices/locations/operationResults,null,No
-yes,Microsoft.Devices/IotHubs,Iot Hub,Yes
-no,Microsoft.Devices/IotHubs/eventGridFilters,null,No
-no,Microsoft.Devices/IotHubs/failover,null,No
-no,Microsoft.Devices/ProvisioningServices,null,No
-no,Microsoft.Devices/IotHubs/securitySettings,null,No
-no,Microsoft.DeviceUpdate/locations,null,No
-no,Microsoft.DeviceUpdate/locations/operationStatuses,null,No
-no,Microsoft.DeviceUpdate/operations,null,No
-no,Microsoft.DeviceUpdate/accounts,null,No
-no,Microsoft.DeviceUpdate/accounts/instances,null,No
-no,Microsoft.DeviceUpdate/checkNameAvailability,null,No
-no,Microsoft.DeviceUpdate/registeredSubscriptions,null,No
-no,Microsoft.DeviceUpdate/accounts/privateLinkResources,null,No
-no,Microsoft.DeviceUpdate/accounts/privateEndpointConnections,null,No
-no,Microsoft.DeviceUpdate/accounts/privateEndpointConnectionProxies,null,No
-no,Microsoft.DevTestLab/labs/environments,null,No
-no,Microsoft.DevTestLab/labs,null,No
-no,Microsoft.DevTestLab/schedules,null,No
-no,Microsoft.DevTestLab/labs/virtualMachines,null,No
-no,Microsoft.DevTestLab/labs/serviceRunners,null,No
-no,Microsoft.DevTestLab/operations,null,No
-no,Microsoft.DevTestLab/locations,null,No
-no,Microsoft.DevTestLab/locations/operations,null,No
-no,Microsoft.DigitalTwins/locations,null,No
-no,Microsoft.DigitalTwins/locations/checkNameAvailability,null,No
-yes,Microsoft.DigitalTwins/digitalTwinsInstances,DigitalTwins Instances,No
-no,Microsoft.DigitalTwins/digitalTwinsInstances/operationResults,null,No
-no,Microsoft.DigitalTwins/locations/operationResults,null,No
-no,Microsoft.DigitalTwins/locations/operationsStatuses,null,No
-no,Microsoft.DigitalTwins/digitalTwinsInstances/endpoints,null,No
-no,Microsoft.DigitalTwins/digitalTwinsInstances/timeSeriesDatabaseConnections,null,No
-no,Microsoft.DigitalTwins/operations,null,No
-no,Microsoft.Easm/workspaces,null,No
-no,Microsoft.Easm/workspaces/labels,null,No
-no,Microsoft.Easm/operations,null,No
-no,Microsoft.Easm/workspaces/tasks,null,No
-no,Microsoft.EdgeManagement/locations,null,No
-no,Microsoft.EdgeManagement/operations,null,No
-no,Microsoft.EdgeMarketplace/operations,null,No
-no,Microsoft.EdgeMarketplace/locations,null,No
-no,Microsoft.EdgeMarketplace/locations/operationStatuses,null,No
-no,Microsoft.EdgeMarketplace/publishers,null,No
-no,Microsoft.EdgeMarketplace/offers,null,No
-no,Microsoft.EdgeOrder/addresses,null,No
-no,Microsoft.EdgeOrder/orderItems,null,No
-no,Microsoft.EdgeOrder/orders,null,No
-no,Microsoft.EdgeOrder/locations,null,No
-no,Microsoft.EdgeOrder/locations/orders,null,No
-no,Microsoft.EdgeOrder/listProductFamilies,null,No
-no,Microsoft.EdgeOrder/listConfigurations,null,No
-no,Microsoft.EdgeOrder/productFamiliesMetadata,null,No
-no,Microsoft.EdgeOrder/locations/hciCatalog,null,No
-no,Microsoft.EdgeOrder/locations/hciCatalog/vendors,null,No
-no,Microsoft.EdgeOrder/locations/hciCatalog/platforms,null,No
-no,Microsoft.EdgeOrder/locations/hciCatalog/projects,null,No
-no,Microsoft.EdgeOrder/locations/hciFlightCatalog,null,No
-no,Microsoft.EdgeOrder/locations/hciFlightCatalog/vendors,null,No
-no,Microsoft.EdgeOrder/locations/hciFlightCatalog/platforms,null,No
-no,Microsoft.EdgeOrder/locations/hciFlightCatalog/projects,null,No
-no,Microsoft.EdgeOrder/operations,null,No
-no,Microsoft.EdgeOrder/locations/operationresults,null,No
-no,Microsoft.EdgeOrderPartner/operations,null,No
-no,Microsoft.Elastic/operations,null,No
-no,Microsoft.Elastic/locations,null,No
-no,Microsoft.Elastic/locations/operationStatuses,null,No
-yes,Microsoft.Elastic/monitors,Elastic Monitors,No
-no,Microsoft.Elastic/monitors/tagRules,null,No
-no,Microsoft.Elastic/checkNameAvailability,null,No
-no,Microsoft.Elastic/elasticVersions,null,No
-no,Microsoft.Elastic/getOrganizationApiKey,null,No
-no,Microsoft.Elastic/getElasticOrganizationToAzureSubscriptionMapping,null,No
-no,Microsoft.Elastic/monitors/openAIIntegrations,null,No
-yes,Microsoft.ElasticSan/elasticSans,Elastic Sans,No
-no,Microsoft.ElasticSan/elasticSans/volumeGroups,null,No
-no,Microsoft.ElasticSan/operations,null,No
-no,Microsoft.ElasticSan/locations/asyncoperations,null,No
-no,Microsoft.ElasticSan/locations,null,No
-no,Microsoft.EnterpriseSupport/EnterpriseSupports,null,No
-no,Microsoft.EnterpriseSupport/operationStatuses,null,No
-no,Microsoft.EnterpriseSupport/validate,null,No
-no,Microsoft.EnterpriseSupport/Operations,null,No
-no,Microsoft.EntitlementManagement/Operations,null,No
-no,Microsoft.Experimentation/Operations,null,No
-no,Microsoft.ExtendedLocation/locations,null,No
-no,Microsoft.ExtendedLocation/customLocations,null,No
-no,Microsoft.ExtendedLocation/customLocations/enabledResourceTypes,null,No
-no,Microsoft.ExtendedLocation/customLocations/resourceSyncRules,null,No
-no,Microsoft.ExtendedLocation/locations/operationsstatus,null,No
-no,Microsoft.ExtendedLocation/locations/operationresults,null,No
-no,Microsoft.ExtendedLocation/operations,null,No
-no,Microsoft.Fabric/capacities,null,No
-no,Microsoft.Fabric/locations,null,No
-no,Microsoft.Fabric/locations/checkNameAvailability,null,No
-no,Microsoft.Fabric/locations/operationresults,null,No
-no,Microsoft.Fabric/locations/operationstatuses,null,No
-no,Microsoft.Fabric/operations,null,No
-no,Microsoft.Falcon/namespaces,null,No
-no,Microsoft.Features/features,null,No
-no,Microsoft.Features/providers,null,No
-no,Microsoft.Features/featureProviders,null,No
-no,Microsoft.Features/subscriptionFeatureRegistrations,null,No
-no,Microsoft.Features/featureProviderNamespaces,null,No
-no,Microsoft.Features/featureConfigurations,null,No
-no,Microsoft.Features/operations,null,No
-yes,Microsoft.FluidRelay/fluidRelayServers,FluidRelay Server,Yes
-no,Microsoft.FluidRelay/Operations,null,No
-no,Microsoft.FluidRelay/fluidRelayServers/fluidRelayContainers,null,No
-no,Microsoft.FluidRelay/Locations,null,No
-no,Microsoft.FluidRelay/Locations/OperationStatuses,null,No
-no,Microsoft.GraphServices/accounts,null,No
-no,Microsoft.GraphServices/Operations,null,No
-no,Microsoft.GraphServices/RegisteredSubscriptions,null,No
-no,Microsoft.GraphServices/Locations,null,No
-no,Microsoft.GraphServices/Locations/OperationStatuses,null,No
-yes,Microsoft.HanaOnAzure/hanaInstances,Hana On Azure Instances,No
-no,Microsoft.HanaOnAzure/locations/operationsStatus,null,No
-no,Microsoft.HanaOnAzure/locations,null,No
-no,Microsoft.HanaOnAzure/locations/operations,null,No
-no,Microsoft.HanaOnAzure/operations,null,No
-yes,Microsoft.HardwareSecurityModules/cloudHsmClusters,HSM Cluster,Yes
-no,Microsoft.HardwareSecurityModules/locations,null,No
-no,Microsoft.HardwareSecurityModules/operations,null,No
-no,Microsoft.HDInsight/Locations,null,No
-no,Microsoft.HDInsight/Locations/OperationStatuses,null,No
-yes,Microsoft.HDInsight/clusterpools,HDInsight Cluster Pool,No
-no,Microsoft.HDInsight/clusterpools/clusters,null,No
-no,Microsoft.HDInsight/Locations/clusterofferingversions,null,No
-no,Microsoft.HDInsight/locations/checkNameAvailability,null,No
-no,Microsoft.HDInsight/clusterpools/clusters/serviceConfigs,null,No
-no,Microsoft.HDInsight/clusterpools/clusters/instanceViews,null,No
-no,Microsoft.HDInsight/Locations/availableclusterversions,null,No
-no,Microsoft.HDInsight/Locations/availableclusterpoolversions,null,No
-no,Microsoft.HDInsight/operations,null,No
-no,Microsoft.HDInsight/clusterpools/clusters/jobs,null,No
-yes,Microsoft.HDInsight/clusters,HDInsight,Yes
-no,Microsoft.HDInsight/clusters/applications,null,No
-no,Microsoft.HDInsight/clusters/operationresults,null,No
-no,Microsoft.HDInsight/locations/capabilities,null,No
-no,Microsoft.HDInsight/locations/usages,null,No
-no,Microsoft.HDInsight/locations/billingSpecs,null,No
-no,Microsoft.HDInsight/locations/operationresults,null,No
-no,Microsoft.HDInsight/locations/azureasyncoperations,null,No
-no,Microsoft.HDInsight/locations/validateCreateRequest,null,No
-no,Microsoft.HealthBot/Operations,null,No
-no,Microsoft.HealthBot/Locations,null,No
-no,Microsoft.HealthBot/Locations/OperationStatuses,null,No
-yes,Microsoft.HealthBot/healthBots,Health Bot,No
-yes,Microsoft.HealthcareApis/services,Azure API for FHIR,Yes
-no,Microsoft.HealthcareApis/services/privateEndpointConnectionProxies,null,No
-no,Microsoft.HealthcareApis/services/privateEndpointConnections,null,No
-no,Microsoft.HealthcareApis/services/privateLinkResources,null,No
-no,Microsoft.HealthcareApis/services/iomtconnectors,null,No
-no,Microsoft.HealthcareApis/services/iomtconnectors/connections,null,No
-no,Microsoft.HealthcareApis/services/iomtconnectors/mappings,null,No
-yes,Microsoft.HealthcareApis/workspaces,Healthcare APIs Workspaces,No
-no,Microsoft.HealthcareApis/workspaces/privateEndpointConnectionProxies,null,No
-no,Microsoft.HealthcareApis/workspaces/privateEndpointConnections,null,No
-no,Microsoft.HealthcareApis/workspaces/privateLinkResources,null,No
-no,Microsoft.HealthcareApis/workspaces/dicomservices,null,No
-no,Microsoft.HealthcareApis/workspaces/iotconnectors,null,No
-no,Microsoft.HealthcareApis/workspaces/iotconnectors/fhirdestinations,null,No
-no,Microsoft.HealthcareApis/workspaces/fhirservices,null,No
-no,Microsoft.HealthcareApis/workspaces/eventGridFilters,null,No
-no,Microsoft.HealthcareApis/locations,null,No
-no,Microsoft.HealthcareApis/locations/operationresults,null,No
-no,Microsoft.HealthcareApis/checkNameAvailability,null,No
-no,Microsoft.HealthcareApis/operations,null,No
-no,Microsoft.HealthcareApis/validateMedtechMappings,null,No
-no,Microsoft.HealthDataAIServices/locations,null,No
-no,Microsoft.HealthDataAIServices/locations/operationStatuses,null,No
-no,Microsoft.HealthDataAIServices/Operations,null,No
-no,Microsoft.HealthModel/Operations,null,No
-no,Microsoft.Help/operations,null,No
-no,Microsoft.Help/operationResults,null,No
-no,Microsoft.Help/discoverySolutions,null,No
-no,Microsoft.Help/discoverSolutions,null,No
-no,Microsoft.Help/diagnostics,null,No
-no,Microsoft.Help/checkNameAvailability,null,No
-no,Microsoft.Help/solutions,null,No
-no,Microsoft.Help/simplifiedSolutions,null,No
-no,Microsoft.Help/troubleshooters,null,No
-no,Microsoft.Help/SelfHelp,null,No
-no,Microsoft.HybridCloud/cloudConnectors,null,No
-no,Microsoft.HybridCloud/cloudConnections,null,No
-yes,Microsoft.HybridCompute/machines,Machine,Yes
-no,Microsoft.HybridCompute/machines/hybridIdentityMetadata,null,No
-no,Microsoft.HybridCompute/machines/privateLinkScopes,null,No
-no,Microsoft.HybridCompute/machines/extensions,null,No
-no,Microsoft.HybridCompute/locations,null,No
-no,Microsoft.HybridCompute/locations/publishers,null,No
-no,Microsoft.HybridCompute/locations/publishers/extensionTypes,null,No
-no,Microsoft.HybridCompute/locations/publishers/extensionTypes/versions,null,No
-no,Microsoft.HybridCompute/locations/operationStatus,null,No
-no,Microsoft.HybridCompute/locations/operationResults,null,No
-no,Microsoft.HybridCompute/operations,null,No
-no,Microsoft.HybridCompute/machines/assessPatches,null,No
-no,Microsoft.HybridCompute/machines/installPatches,null,No
-no,Microsoft.HybridCompute/locations/updateCenterOperationResults,null,No
-no,Microsoft.HybridCompute/privateLinkScopes,null,No
-no,Microsoft.HybridCompute/privateLinkScopes/privateEndpointConnections,null,No
-no,Microsoft.HybridCompute/privateLinkScopes/privateEndpointConnectionProxies,null,No
-no,Microsoft.HybridCompute/locations/privateLinkScopes,null,No
-no,Microsoft.HybridCompute/osType,null,No
-no,Microsoft.HybridCompute/osType/agentVersions,null,No
-no,Microsoft.HybridCompute/osType/agentVersions/latest,null,No
-no,Microsoft.HybridCompute/machines/runcommands,null,No
-no,Microsoft.HybridCompute/machines/licenseProfiles,null,No
-no,Microsoft.HybridCompute/licenses,null,No
-no,Microsoft.HybridCompute/validateLicense,null,No
-no,Microsoft.HybridCompute/networkConfigurations,null,No
-no,Microsoft.HybridCompute/privateLinkScopes/networkSecurityPerimeterConfigurations,null,No
-no,Microsoft.HybridCompute/privateLinkScopes/networkSecurityPerimeterAssociationProxies,null,No
-no,Microsoft.HybridCompute/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.HybridCompute/locations/notifyExtension,null,No
-no,Microsoft.HybridConnectivity/endpoints,null,No
-no,Microsoft.HybridConnectivity/Operations,null,No
-no,Microsoft.HybridConnectivity/Locations,null,No
-no,Microsoft.HybridConnectivity/Locations/OperationStatuses,null,No
-no,Microsoft.HybridContainerService/Locations,null,No
-no,Microsoft.HybridContainerService/Locations/operationStatuses,null,No
-no,Microsoft.HybridContainerService/provisionedClusters,null,No
-no,Microsoft.HybridContainerService/provisionedClusters/hybridIdentityMetadata,null,No
-no,Microsoft.HybridContainerService/provisionedClusters/agentPools,null,No
-no,Microsoft.HybridContainerService/virtualNetworks,null,No
-no,Microsoft.HybridContainerService/Operations,null,No
-no,Microsoft.HybridContainerService/provisionedClusters/upgradeProfiles,null,No
-no,Microsoft.HybridContainerService/kubernetesVersions,null,No
-no,Microsoft.HybridContainerService/skus,null,No
-no,Microsoft.HybridContainerService/provisionedClusterInstances,null,No
-no,Microsoft.HybridNetwork/Operations,null,No
-no,Microsoft.HybridNetwork/Locations,null,No
-no,Microsoft.HybridNetwork/Locations/OperationStatuses,null,No
-no,Microsoft.HybridNetwork/devices,null,No
-no,Microsoft.HybridNetwork/networkfunctions,null,No
-no,Microsoft.HybridNetwork/networkFunctionVendors,null,No
-no,Microsoft.HybridNetwork/networkFunctions/components,null,No
-no,Microsoft.HybridNetwork/sites,null,No
-no,Microsoft.HybridNetwork/siteNetworkServices,null,No
-no,Microsoft.HybridNetwork/configurationGroupValues,null,No
-no,Microsoft.HybridNetwork/publishers,null,No
-no,Microsoft.HybridNetwork/publishers/networkFunctionDefinitionGroups,null,No
-no,Microsoft.HybridNetwork/publishers/networkFunctionDefinitionGroups/networkFunctionDefinitionVersions,null,No
-no,Microsoft.HybridNetwork/publishers/artifactStores,null,No
-no,Microsoft.HybridNetwork/publishers/artifactStores/artifactManifests,null,No
-no,Microsoft.HybridNetwork/publishers/artifactstores/artifacts,null,No
-no,Microsoft.HybridNetwork/publishers/artifactstores/artifactversions,null,No
-no,Microsoft.Impact/Operations,null,No
-yes,Microsoft.IntegrationSpaces/Spaces,Integration Spaces,No
-no,Microsoft.IntegrationSpaces/Spaces/InfrastructureResources,null,No
-no,Microsoft.IntegrationSpaces/Spaces/Applications,null,No
-no,Microsoft.IntegrationSpaces/Spaces/applications/resources,null,No
-no,Microsoft.IntegrationSpaces/Spaces/applications/BusinessProcesses,null,No
-no,Microsoft.IntegrationSpaces/Spaces/applications/BusinessProcesses/versions,null,No
-no,Microsoft.IntegrationSpaces/locations,null,No
-no,Microsoft.IntegrationSpaces/locations/OperationStatuses,null,No
-no,Microsoft.IntegrationSpaces/operations,null,No
-no,Microsoft.Inventory/subscriptionInternalProperties,null,No
-no,Microsoft.Inventory/operations,null,No
-no,Microsoft.IoTCentral/IoTApps,null,No
-no,Microsoft.IoTCentral/checkNameAvailability,null,No
-no,Microsoft.IoTCentral/checkSubdomainAvailability,null,No
-no,Microsoft.IoTCentral/operations,null,No
-no,Microsoft.IoTCentral/locations,null,No
-no,Microsoft.IoTCentral/locations/operationResults,null,No
-no,Microsoft.IoTCentral/appTemplates,null,No
-no,Microsoft.IoTFirmwareDefense/operations,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces/firmwares,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces/firmwares/sbomComponents,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces/firmwares/binaryHardeningResults,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces/firmwares/cryptoCertificates,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces/firmwares/cryptoKeys,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces/firmwares/passwordHashes,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces/firmwares/cves,null,No
-no,Microsoft.IoTFirmwareDefense/workspaces/firmwares/summaries,null,No
-no,Microsoft.IoTFirmwareDefense/locations,null,No
-no,Microsoft.IoTFirmwareDefense/locations/operationStatuses,null,No
-no,Microsoft.IoTOperationsDataProcessor/locations,null,No
-no,Microsoft.IoTOperationsDataProcessor/locations/operationStatuses,null,No
-no,Microsoft.IoTOperationsDataProcessor/instances,null,No
-no,Microsoft.IoTOperationsDataProcessor/instances/datasets,null,No
-no,Microsoft.IoTOperationsDataProcessor/instances/pipelines,null,No
-no,Microsoft.IoTOperationsDataProcessor/operations,null,No
-no,Microsoft.IoTOperationsMQ/Locations,null,No
-no,Microsoft.IoTOperationsMQ/Operations,null,No
-no,Microsoft.IoTOperationsMQ/Locations/OperationStatuses,null,No
-no,Microsoft.IoTOperationsMQ/mq,null,No
-no,Microsoft.IoTOperationsMQ/mq/broker,null,No
-no,Microsoft.IoTOperationsMQ/mq/broker/authentication,null,No
-no,Microsoft.IoTOperationsMQ/mq/broker/authorization,null,No
-no,Microsoft.IoTOperationsMQ/mq/broker/listener,null,No
-no,Microsoft.IoTOperationsMQ/mq/dataLakeConnector,null,No
-no,Microsoft.IoTOperationsMQ/mq/dataLakeConnector/topicMap,null,No
-no,Microsoft.IoTOperationsMQ/mq/diagnosticService,null,No
-no,Microsoft.IoTOperationsMQ/mq/kafkaConnector,null,No
-no,Microsoft.IoTOperationsMQ/mq/kafkaConnector/topicMap,null,No
-no,Microsoft.IoTOperationsMQ/mq/mqttBridgeConnector,null,No
-no,Microsoft.IoTOperationsMQ/mq/mqttBridgeConnector/topicMap,null,No
-no,Microsoft.IoTOperationsOrchestrator/locations,null,No
-no,Microsoft.IoTOperationsOrchestrator/locations/operationStatuses,null,No
-no,Microsoft.IoTOperationsOrchestrator/targets,null,No
-no,Microsoft.IoTOperationsOrchestrator/solutions,null,No
-no,Microsoft.IoTOperationsOrchestrator/instances,null,No
-no,Microsoft.IoTOperationsOrchestrator/operations,null,No
-no,Microsoft.Kubernetes/connectedClusters,Kubernetes,Yes
-no,Microsoft.Kubernetes/locations,null,No
-no,Microsoft.Kubernetes/locations/operationStatuses,null,No
-no,Microsoft.Kubernetes/registeredSubscriptions,null,No
-no,Microsoft.Kubernetes/Operations,null,No
-no,Microsoft.KubernetesConfiguration/sourceControlConfigurations,null,No
-no,Microsoft.KubernetesConfiguration/extensions,Kubernetes Configuration Extensions,Yes
-no,Microsoft.KubernetesConfiguration/fluxConfigurations,null,No
-no,Microsoft.KubernetesConfiguration/operations,null,No
-no,Microsoft.KubernetesConfiguration/extensionTypes,null,No
-no,Microsoft.KubernetesConfiguration/locations/extensionTypes,null,No
-no,Microsoft.KubernetesConfiguration/locations/extensionTypes/versions,null,No
-no,Microsoft.KubernetesConfiguration/privateLinkScopes,null,No
-no,Microsoft.KubernetesConfiguration/privateLinkScopes/privateEndpointConnections,null,No
-no,Microsoft.KubernetesConfiguration/privateLinkScopes/privateEndpointConnectionProxies,null,No
-no,Microsoft.KubernetesRuntime/storageClasses,null,No
-no,Microsoft.KubernetesRuntime/loadBalancers,null,No
-no,Microsoft.KubernetesRuntime/bgpPeers,null,No
-no,Microsoft.KubernetesRuntime/operations,null,No
-no,Microsoft.KubernetesRuntime/locations,null,No
-no,Microsoft.KubernetesRuntime/locations/operationStatuses,null,No
-no,Microsoft.KubernetesRuntime/services,null,No
-no,Microsoft.LabServices/labplans,null,No
-no,Microsoft.LabServices/labs,null,No
-no,Microsoft.LabServices/labaccounts,null,No
-no,Microsoft.LabServices/locations/operationResults,null,No
-no,Microsoft.LabServices/locations/operations,null,No
-no,Microsoft.LabServices/operations,null,No
-no,Microsoft.LabServices/users,null,No
-no,Microsoft.LabServices/locations,null,No
-no,Microsoft.LabServices/locations/usages,null,No
-no,Microsoft.Logz/operations,null,No
-no,Microsoft.Logz/locations,null,No
-no,Microsoft.Logz/registeredSubscriptions,null,No
-no,Microsoft.Logz/locations/operationStatuses,null,No
-no,Microsoft.Logz/monitors,null,No
-no,Microsoft.Logz/monitors/tagRules,null,No
-no,Microsoft.Logz/monitors/singleSignOnConfigurations,null,No
-no,Microsoft.Logz/monitors/accounts,null,No
-no,Microsoft.Logz/monitors/accounts/tagRules,null,No
-yes,Microsoft.MachineLearning/Workspaces,Machine Learning Workspaces,No
-yes,Microsoft.MachineLearning/webServices,Machine Learning Web Services,No
-no,Microsoft.MachineLearning/operations,null,No
-no,Microsoft.MachineLearning/locations,null,No
-no,Microsoft.MachineLearning/locations/operations,null,No
-no,Microsoft.MachineLearning/locations/operationsStatus,null,No
-no,Microsoft.MachineLearning/commitmentPlans,null,No
-no,Microsoft.MachineLearningServices/workspaces/batchEndpoints,null,No
-no,Microsoft.MachineLearningServices/workspaces/batchEndpoints/deployments,null,No
-yes,Microsoft.MachineLearningServices/workspaces,Machine Learning Services,Yes
-no,Microsoft.MachineLearningServices/registries,null,No
-no,Microsoft.MachineLearningServices/locations/registryOperationsStatus,null,No
-no,Microsoft.MachineLearningServices/workspaces/onlineEndpoints,null,No
-no,Microsoft.MachineLearningServices/workspaces/onlineEndpoints/deployments,null,No
-no,Microsoft.MachineLearningServices/workspaces/onlineEndpoints/deployments/skus,null,No
-no,Microsoft.MachineLearningServices/workspaces/computes,null,No
-no,Microsoft.MachineLearningServices/workspaces/jobs,null,No
-no,Microsoft.MachineLearningServices/workspaces/codes,null,No
-no,Microsoft.MachineLearningServices/workspaces/codes/versions,null,No
-no,Microsoft.MachineLearningServices/workspaces/components,null,No
-no,Microsoft.MachineLearningServices/workspaces/components/versions,null,No
-no,Microsoft.MachineLearningServices/workspaces/environments,null,No
-no,Microsoft.MachineLearningServices/workspaces/environments/versions,null,No
-no,Microsoft.MachineLearningServices/workspaces/data,null,No
-no,Microsoft.MachineLearningServices/workspaces/data/versions,null,No
-no,Microsoft.MachineLearningServices/workspaces/datasets,null,No
-no,Microsoft.MachineLearningServices/workspaces/services,null,No
-no,Microsoft.MachineLearningServices/workspaces/datastores,null,No
-no,Microsoft.MachineLearningServices/workspaces/eventGridFilters,null,No
-no,Microsoft.MachineLearningServices/workspaces/models,null,No
-no,Microsoft.MachineLearningServices/workspaces/models/versions,null,No
-no,Microsoft.MachineLearningServices/operations,null,No
-no,Microsoft.MachineLearningServices/locations,null,No
-no,Microsoft.MachineLearningServices/locations/computeOperationsStatus,null,No
-no,Microsoft.MachineLearningServices/locations/mfeOperationResults,null,No
-no,Microsoft.MachineLearningServices/locations/mfeOperationsStatus,null,No
-no,Microsoft.MachineLearningServices/locations/workspaceOperationsStatus,null,No
-no,Microsoft.MachineLearningServices/locations/usages,null,No
-no,Microsoft.MachineLearningServices/locations/vmsizes,null,No
-no,Microsoft.MachineLearningServices/locations/quotas,null,No
-no,Microsoft.MachineLearningServices/locations/updatequotas,null,No
-no,Microsoft.MachineLearningServices/workspaces/linkedServices,null,No
-no,Microsoft.MachineLearningServices/workspaces/labelingJobs,null,No
-no,Microsoft.MachineLearningServices/workspaces/schedules,null,No
-no,Microsoft.MachineLearningServices/workspaces/featuresets,null,No
-no,Microsoft.MachineLearningServices/workspaces/serverlessEndpoints,null,No
-no,Microsoft.MachineLearningServices/workspaces/marketplaceSubscriptions,null,No
-no,Microsoft.MachineLearningServices/workspaces/inferencePools,null,No
-no,Microsoft.MachineLearningServices/workspaces/inferencePools/groups,null,No
-no,Microsoft.MachineLearningServices/workspaces/inferencePools/endpoints,null,No
-no,Microsoft.MachineLearningServices/workspaces/featuresets/versions,null,No
-no,Microsoft.MachineLearningServices/workspaces/featurestoreEntities,null,No
-no,Microsoft.MachineLearningServices/workspaces/featurestoreEntities/versions,null,No
-no,Microsoft.MachineLearningServices/workspaces/endpoints,null,No
-no,Microsoft.MachineLearningServices/registries/codes,null,No
-no,Microsoft.MachineLearningServices/registries/codes/versions,null,No
-no,Microsoft.MachineLearningServices/registries/components,null,No
-no,Microsoft.MachineLearningServices/registries/components/versions,null,No
-no,Microsoft.MachineLearningServices/registries/data,null,No
-no,Microsoft.MachineLearningServices/registries/data/versions,null,No
-no,Microsoft.MachineLearningServices/registries/datareferences,null,No
-no,Microsoft.MachineLearningServices/registries/datareferences/versions,null,No
-no,Microsoft.MachineLearningServices/registries/environments,null,No
-no,Microsoft.MachineLearningServices/registries/environments/versions,null,No
-no,Microsoft.MachineLearningServices/registries/models,null,No
-no,Microsoft.MachineLearningServices/registries/models/versions,null,No
-yes,Microsoft.MachineLearningServices/capacityReservationGroups,Machine Learning Services Capacity Reservation Groups,No
-no,Microsoft.ManagedNetworkFabric/Operations,null,No
-no,Microsoft.ManagedNetworkFabric/NetworkFabricControllers,null,No
-no,Microsoft.ManagedNetworkFabric/Locations,null,No
-no,Microsoft.ManagedNetworkFabric/Locations/OperationStatuses,null,No
-no,Microsoft.ManagedNetworkFabric/NetworkFabrics,null,No
-no,Microsoft.ManagedNetworkFabric/NetworkRacks,null,No
-no,Microsoft.ManagedNetworkFabric/NetworkDevices,null,No
-no,Microsoft.ManagedNetworkFabric/NetworkDevices/NetworkInterfaces,null,No
-no,Microsoft.ManagedNetworkFabric/L2IsolationDomains,null,No
-no,Microsoft.ManagedNetworkFabric/L3IsolationDomains,null,No
-no,Microsoft.ManagedNetworkFabric/accesscontrollists,null,No
-no,Microsoft.ManagedNetworkFabric/RoutePolicies,null,No
-no,Microsoft.ManagedNetworkFabric/L3IsolationDomains/externalNetworks,null,No
-no,Microsoft.ManagedNetworkFabric/L3IsolationDomains/internalNetworks,null,No
-no,Microsoft.ManagedNetworkFabric/NetworkFabrics/NetworkToNetworkInterconnects,null,No
-no,Microsoft.ManagedNetworkFabric/IpExtendedCommunities,null,No
-no,Microsoft.ManagedNetworkFabric/IpCommunities,null,No
-no,Microsoft.ManagedNetworkFabric/ipprefixes,null,No
-no,Microsoft.ManagedNetworkFabric/InternetGateways,null,No
-no,Microsoft.ManagedNetworkFabric/internetgatewayrules,null,No
-no,Microsoft.ManagedNetworkFabric/networkpacketbrokers,null,No
-no,Microsoft.ManagedNetworkFabric/networktaps,null,No
-no,Microsoft.ManagedNetworkFabric/networktaprules,null,No
-no,Microsoft.ManagedNetworkFabric/neighborgroups,null,No
-no,Microsoft.ManagedServices/registrationDefinitions,null,No
-no,Microsoft.ManagedServices/registrationAssignments,null,No
-no,Microsoft.ManagedServices/operations,null,No
-no,Microsoft.ManagedServices/marketplaceRegistrationDefinitions,null,No
-no,Microsoft.ManagedServices/operationStatuses,null,No
-no,Microsoft.Management/resources,Resources,No
-no,Microsoft.Management/managementGroups,Management Group,No
-no,Microsoft.Management/getEntities,null,No
-no,Microsoft.Management/managementGroups/settings,null,No
-no,Microsoft.Management/checkNameAvailability,null,No
-no,Microsoft.Management/operationResults,null,No
-no,Microsoft.Management/operationResults/asyncOperation,null,No
-no,Microsoft.Management/operations,null,No
-no,Microsoft.Management/tenantBackfillStatus,null,No
-no,Microsoft.Management/startTenantBackfill,null,No
-no,Microsoft.ManufacturingPlatform/locations,null,No
-no,Microsoft.ManufacturingPlatform/operations,null,No
-yes,Microsoft.Maps/accounts,Maps Accounts,No
-no,Microsoft.Maps/accounts/creators,null,No
-no,Microsoft.Maps/accounts/eventGridFilters,null,No
-no,Microsoft.Maps/operations,null,No
-no,Microsoft.Marketplace/register,null,No
-no,Microsoft.Marketplace/privategalleryitems,null,No
-no,Microsoft.Marketplace/products,null,No
-no,Microsoft.Marketplace/offers,null,No
-no,Microsoft.Marketplace/macc,null,No
-no,Microsoft.Marketplace/offerTypes,null,No
-no,Microsoft.Marketplace/offerTypes/publishers,null,No
-no,Microsoft.Marketplace/offerTypes/publishers/offers,null,No
-no,Microsoft.Marketplace/offerTypes/publishers/offers/plans,null,No
-no,Microsoft.Marketplace/offerTypes/publishers/offers/plans/configs,null,No
-no,Microsoft.Marketplace/offerTypes/publishers/offers/plans/configs/importImage,null,No
-no,Microsoft.Marketplace/offerTypes/publishers/offers/plans/agreements,null,No
-no,Microsoft.Marketplace/operations,null,No
-no,Microsoft.Marketplace/listAvailableOffers,null,No
-no,Microsoft.Marketplace/publishers,null,No
-no,Microsoft.Marketplace/publishers/offers,null,No
-no,Microsoft.Marketplace/publishers/offers/amendments,null,No
-no,Microsoft.Marketplace/privateStoreClient,null,No
-no,Microsoft.Marketplace/privateStores,null,No
-no,Microsoft.Marketplace/privateStores/offers,null,No
-no,Microsoft.Marketplace/search,null,No
-no,Microsoft.Marketplace/privateStores/requestApprovals/query,null,No
-no,Microsoft.Marketplace/privateStores/requestApprovals/withdrawPlan,null,No
-no,Microsoft.Marketplace/privateStores/RequestApprovals,null,No
-no,Microsoft.Marketplace/privateStores/queryNotificationsState,null,No
-no,Microsoft.Marketplace/privateStores/fetchAllSubscriptionsInTenant,null,No
-no,Microsoft.Marketplace/privateStores/listNewPlansNotifications,null,No
-no,Microsoft.Marketplace/privateStores/listStopSellOffersPlansNotifications,null,No
-no,Microsoft.Marketplace/privateStores/listSubscriptionsContext,null,No
-no,Microsoft.Marketplace/privateStores/offers/acknowledgeNotification,null,No
-no,Microsoft.Marketplace/privateStores/AdminRequestApprovals,null,No
-no,Microsoft.Marketplace/privateStores/collections,null,No
-no,Microsoft.Marketplace/privateStores/collections/approveAllItems,null,No
-no,Microsoft.Marketplace/privateStores/collections/disableApproveAllItems,null,No
-no,Microsoft.Marketplace/privateStores/collections/offers,null,No
-no,Microsoft.Marketplace/privateStores/collections/mapOffersToContexts,null,No
-no,Microsoft.Marketplace/privateStores/collections/queryRules,null,No
-no,Microsoft.Marketplace/privateStores/collections/setRules,null,No
-no,Microsoft.Marketplace/privateStores/collections/offers/upsertOfferWithMultiContext,null,No
-no,Microsoft.Marketplace/privateStores/bulkCollectionsAction,null,No
-no,Microsoft.Marketplace/privateStores/collections/transferOffers,null,No
-no,Microsoft.Marketplace/privateStores/anyExistingOffersInTheCollections,null,No
-no,Microsoft.Marketplace/privateStores/queryOffers,null,No
-no,Microsoft.Marketplace/privateStores/queryUserOffers,null,No
-no,Microsoft.Marketplace/privateStores/queryUserRules,null,No
-no,Microsoft.Marketplace/privateStores/collectionsToSubscriptionsMapping,null,No
-no,Microsoft.Marketplace/privateStores/billingAccounts,null,No
-no,Microsoft.Marketplace/privateStores/queryApprovedPlans,null,No
-no,Microsoft.Marketplace/locations,null,No
-no,Microsoft.Marketplace/locations/edgeZones,null,No
-no,Microsoft.Marketplace/locations/edgeZones/products,null,No
-no,Microsoft.Marketplace/mysolutions,null,No
-no,Microsoft.Marketplace/products/reviews,null,No
-no,Microsoft.Marketplace/products/reviews/comments,null,No
-no,Microsoft.Marketplace/products/reviews/helpful,null,No
-no,Microsoft.Marketplace/products/usermetadata,null,No
-no,Microsoft.MarketplaceOrdering/agreements,null,No
-no,Microsoft.MarketplaceOrdering/operations,null,No
-no,Microsoft.MarketplaceOrdering/offertypes,null,No
-yes,Microsoft.Media/mediaservices,Media Service,Yes
-no,Microsoft.Media/mediaservices/assets,null,No
-no,Microsoft.Media/mediaservices/assets/tracks,null,No
-no,Microsoft.Media/mediaservices/assets/tracks/operationstatuses,null,No
-no,Microsoft.Media/mediaservices/assets/tracks/operationResults,null,No
-no,Microsoft.Media/mediaservices/contentKeyPolicies,null,No
-no,Microsoft.Media/mediaservices/streamingLocators,null,No
-no,Microsoft.Media/mediaservices/streamingPolicies,null,No
-no,Microsoft.Media/mediaservices/eventGridFilters,null,No
-no,Microsoft.Media/mediaservices/transforms,null,No
-no,Microsoft.Media/mediaservices/transforms/jobs,null,No
-no,Microsoft.Media/mediaservices/streamingEndpoints,null,No
-no,Microsoft.Media/mediaservices/liveEvents,null,No
-no,Microsoft.Media/mediaservices/liveEvents/liveOutputs,null,No
-no,Microsoft.Media/mediaservices/streamingEndpointOperations,null,No
-no,Microsoft.Media/mediaservices/liveEventOperations,null,No
-no,Microsoft.Media/mediaservices/liveOutputOperations,null,No
-no,Microsoft.Media/mediaservices/streamingendpoints/operationlocations,null,No
-no,Microsoft.Media/mediaservices/liveevents/operationlocations,null,No
-no,Microsoft.Media/mediaservices/liveevents/liveoutputs/operationlocations,null,No
-no,Microsoft.Media/mediaservices/privateEndpointConnectionProxies,null,No
-no,Microsoft.Media/mediaservices/privateEndpointConnections,null,No
-no,Microsoft.Media/mediaservices/privateEndpointConnectionOperations,null,No
-no,Microsoft.Media/locations/mediaServicesOperationStatuses,null,No
-no,Microsoft.Media/locations/mediaServicesOperationResults,null,No
-no,Microsoft.Media/mediaservices/assets/assetFilters,null,No
-no,Microsoft.Media/mediaservices/accountFilters,null,No
-no,Microsoft.Media/operations,null,No
-no,Microsoft.Media/checknameavailability,null,No
-no,Microsoft.Media/locations,null,No
-no,Microsoft.Media/locations/checkNameAvailability,null,No
-no,Microsoft.Migrate/migrateprojects,Azure Migrate,No
-no,Microsoft.Migrate/assessmentProjects,null,No
-no,Microsoft.Migrate/moveCollections,null,No
-no,Microsoft.Migrate/operations,null,No
-no,Microsoft.Migrate/locations,null,No
-no,Microsoft.Migrate/locations/rmsOperationResults,null,No
-no,Microsoft.Migrate/modernizeProjects,null,No
-no,Microsoft.Mission/Locations,null,No
-no,Microsoft.Mission/Locations/OperationStatuses,null,No
-no,Microsoft.Mission/Operations,null,No
-no,Microsoft.Mission/virtualEnclaves/endpoints,null,No
-no,Microsoft.Mission/checkNameAvailability,null,No
-no,Microsoft.MixedReality/locations,null,No
-no,Microsoft.MixedReality/locations/checkNameAvailability,null,No
-no,Microsoft.MixedReality/operations,null,No
-yes,Microsoft.MixedReality/spatialAnchorsAccounts,MixedReality Spatial Anchor Accounts,No
-yes,Microsoft.MixedReality/remoteRenderingAccounts,MixedReality Renite Rendering Accounts,No
-yes,Microsoft.MixedReality/objectAnchorsAccounts,MixedReality Object Anchor Accounts,No
-no,Microsoft.MobileNetwork/Locations,null,No
-no,Microsoft.MobileNetwork/Locations/OperationStatuses,null,No
-no,Microsoft.MobileNetwork/Operations,null,No
-no,Microsoft.MobileNetwork/packetCoreControlPlaneVersions,null,No
-no,Microsoft.MobilePacketCore/Locations,null,No
-no,Microsoft.MobilePacketCore/Locations/OperationStatuses,null,No
-no,Microsoft.MobilePacketCore/Operations,null,No
-no,Microsoft.ModSimWorkbench/Locations/operationStatuses,null,No
-no,Microsoft.ModSimWorkbench/Locations,null,No
-no,Microsoft.ModSimWorkbench/Operations,null,No
-no,Microsoft.Monitor/operations,null,No
-yes,Microsoft.Monitor/accounts,Monitor Accounts,No
-no,Microsoft.Monitor/locations/locationOperationStatuses,null,No
-no,Microsoft.Monitor/locations/operationResults,null,No
-no,Microsoft.Monitor/locations,null,No
-no,Microsoft.Monitor/locations/operationStatuses,null,No
-no,Microsoft.Monitor/investigations,null,No
-no,Microsoft.MySQLDiscovery/locations,null,No
-no,Microsoft.MySQLDiscovery/locations/operationStatuses,null,No
-no,Microsoft.MySQLDiscovery/MySQLSites,null,No
-no,Microsoft.MySQLDiscovery/MySQLSites/MySQLServers,null,No
-no,Microsoft.MySQLDiscovery/MySQLSites/Refresh,null,No
-no,Microsoft.MySQLDiscovery/MySQLSites/Summaries,null,No
-no,Microsoft.MySQLDiscovery/MySQLSites/ErrorSummaries,null,No
-no,Microsoft.MySQLDiscovery/operations,null,No
-yes,Microsoft.NetApp/netAppAccounts,Azure Netapp Files,Yes
-no,Microsoft.NetApp/netAppAccounts/snapshotPolicies,null,No
-no,Microsoft.NetApp/netAppAccounts/volumeGroups,null,No
-yes,Microsoft.NetApp/netAppAccounts/capacityPools,Capacity Pool,Yes
-yes,Microsoft.NetApp/netAppAccounts/capacityPools/volumes,Volume,Yes
-no,Microsoft.NetApp/netAppAccounts/capacityPools/volumes/mountTargets,null,No
-no,Microsoft.NetApp/netAppAccounts/capacityPools/volumes/snapshots,null,No
-no,Microsoft.NetApp/netAppAccounts/capacityPools/volumes/volumeQuotaRules,null,No
-no,Microsoft.NetApp/locations,null,No
-no,Microsoft.NetApp/locations/checkNameAvailability,null,No
-no,Microsoft.NetApp/locations/checkFilePathAvailability,null,No
-no,Microsoft.NetApp/operations,null,No
-no,Microsoft.NetApp/locations/checkQuotaAvailability,null,No
-no,Microsoft.NetApp/locations/queryNetworkSiblingSet,null,No
-no,Microsoft.NetApp/locations/updateNetworkSiblingSet,null,No
-no,Microsoft.NetApp/locations/regionInfo,null,No
-no,Microsoft.NetApp/locations/regionInfos,null,No
-no,Microsoft.NetApp/locations/QuotaLimits,null,No
-no,Microsoft.NetApp/locations/CheckInventory,null,No
-no,Microsoft.NetApp/locations/operationResults,null,No
-no,Microsoft.NetworkAnalytics/Locations,null,No
-no,Microsoft.NetworkAnalytics/Locations/OperationStatuses,null,No
-no,Microsoft.NetworkAnalytics/Operations,null,No
-no,Microsoft.NetworkAnalytics/registeredSubscriptions,null,No
-no,Microsoft.NetworkCloud/locations,null,No
-no,Microsoft.NetworkCloud/locations/operationStatuses,null,No
-no,Microsoft.NetworkCloud/clusterManagers,Network Cloud Cluster Managers,No
-no,Microsoft.NetworkCloud/racks,Network Cloud Racks,No
-no,Microsoft.NetworkCloud/clusters,Network Cloud Clusters,No
-no,Microsoft.NetworkCloud/bareMetalMachines,Network Cloud BareMetal Machines,No
-no,Microsoft.NetworkCloud/virtualMachines,Network Cloud Virtual Machines,No
-no,Microsoft.NetworkCloud/operations,null,No
-no,Microsoft.NetworkCloud/rackSkus,null,No
-no,Microsoft.NetworkCloud/cloudServicesNetworks,Network Cloud Cloud Services Networks,No
-no,Microsoft.NetworkCloud/l2Networks,null,No
-no,Microsoft.NetworkCloud/storageAppliances,Network Cloud Storage Appliances,No
-no,Microsoft.NetworkCloud/trunkedNetworks,Network Cloud Trunked Networks,No
-no,Microsoft.NetworkCloud/l3Networks,Network Cloud L3 Networks,No
-no,Microsoft.NetworkCloud/clusters/metricsConfigurations,null,No
-no,Microsoft.NetworkCloud/virtualMachines/consoles,null,No
-no,Microsoft.NetworkCloud/clusters/bareMetalMachineKeySets,null,No
-no,Microsoft.NetworkCloud/clusters/bmcKeySets,null,No
-no,Microsoft.NetworkCloud/volumes,Network Cloud Volumes,No
-no,Microsoft.NetworkCloud/registeredSubscriptions,null,No
-no,Microsoft.NetworkCloud/kubernetesClusters,Network Cloud Kubernetes Clusters,No
-no,Microsoft.NetworkCloud/kubernetesClusters/agentPools,null,No
-yes,Microsoft.NetworkFunction/azureTrafficCollectors,Expressroute Traffic Collector,Yes
-no,Microsoft.NetworkFunction/azureTrafficCollectors/collectorPolicies,null,No
-no,Microsoft.NetworkFunction/meshVpns,Network Function Mesh VPN,No
-no,Microsoft.NetworkFunction/meshVpns/connectionPolicies,null,No
-no,Microsoft.NetworkFunction/meshVpns/privateEndpointConnections,null,No
-no,Microsoft.NetworkFunction/meshVpns/privateEndpointConnectionProxies,null,No
-no,Microsoft.NetworkFunction/operations,null,No
-no,Microsoft.NetworkFunction/locations,null,No
-no,Microsoft.NetworkFunction/locations/nfvOperations,null,No
-no,Microsoft.NetworkFunction/locations/nfvOperationResults,null,No
-yes,Microsoft.NotificationHubs/namespaces,Notification Hubs,No
-no,Microsoft.NotificationHubs/namespaces/notificationHubs,null,No
-no,Microsoft.NotificationHubs/checkNamespaceAvailability,null,No
-no,Microsoft.NotificationHubs/checkNameAvailability,null,No
-no,Microsoft.NotificationHubs/operations,null,No
-no,Microsoft.Nutanix/operations,null,No
-no,Microsoft.Nutanix/locations,null,No
-no,Microsoft.ObjectStore/osNamespaces,null,No
-no,Microsoft.OffAzure/VMwareSites,null,No
-no,Microsoft.OffAzure/HyperVSites,null,No
-no,Microsoft.OffAzure/ServerSites,null,No
-no,Microsoft.OffAzure/ImportSites,null,No
-no,Microsoft.OffAzure/MasterSites,null,No
-no,Microsoft.OffAzure/locations,null,No
-no,Microsoft.OffAzure/locations/operationResults,null,No
-no,Microsoft.OffAzure/operations,null,No
-no,Microsoft.OffAzureSpringBoot/locations,null,No
-no,Microsoft.OffAzureSpringBoot/locations/operationStatuses,null,No
-no,Microsoft.OffAzureSpringBoot/springbootsites,null,No
-no,Microsoft.OffAzureSpringBoot/springbootsites/springbootservers,null,No
-no,Microsoft.OffAzureSpringBoot/springbootsites/springbootapps,null,No
-no,Microsoft.OffAzureSpringBoot/operations,null,No
-no,Microsoft.OffAzureSpringBoot/springbootsites/summaries,null,No
-no,Microsoft.OffAzureSpringBoot/springbootsites/errorsummaries,null,No
-no,Microsoft.OpenEnergyPlatform/Locations,null,No
-no,Microsoft.OpenEnergyPlatform/Locations/OperationStatuses,null,No
-no,Microsoft.OpenEnergyPlatform/energyServices,null,No
-no,Microsoft.OpenEnergyPlatform/checkNameAvailability,null,No
-no,Microsoft.OpenEnergyPlatform/Operations,null,No
-no,Microsoft.OpenEnergyPlatform/energyServices/privateEndpointConnections,null,No
-no,Microsoft.OpenEnergyPlatform/energyServices/privateLinkResources,null,No
-no,Microsoft.OpenEnergyPlatform/energyServices/privateEndpointConnectionProxies,null,No
-no,Microsoft.OperationsManagement/solutions,null,No
-no,Microsoft.OperationsManagement/managementassociations,null,No
-no,Microsoft.OperationsManagement/views,null,No
-no,Microsoft.OperationsManagement/operations,null,No
-no,Microsoft.OperatorVoicemail/Operations,null,No
-no,Microsoft.OperatorVoicemail/Locations,null,No
-no,Microsoft.OperatorVoicemail/Locations/OperationStatuses,null,No
-no,Microsoft.OperatorVoicemail/Locations/checkNameAvailability,null,No
-no,Microsoft.OracleDiscovery/locations,null,No
-no,Microsoft.OracleDiscovery/locations/operationStatuses,null,No
-no,Microsoft.OracleDiscovery/oraclesites,null,No
-no,Microsoft.OracleDiscovery/oraclesites/oracleservers,null,No
-no,Microsoft.OracleDiscovery/oraclesites/oracledatabases,null,No
-no,Microsoft.OracleDiscovery/oraclesites/summaries,null,No
-no,Microsoft.OracleDiscovery/oraclesites/errorSummaries,null,No
-no,Microsoft.OracleDiscovery/operations,null,No
-no,Microsoft.Orbital/availableGroundStations,null,No
-no,Microsoft.Orbital/contactProfiles,null,No
-no,Microsoft.Orbital/spacecrafts,Orbital Spacecrafts,No
-no,Microsoft.Orbital/spacecrafts/contacts,null,No
-no,Microsoft.Orbital/groundStations,Orbital Ground Stations,No
-no,Microsoft.Orbital/globalCommunicationsSites,Orbital Global Communication Sites,No
-no,Microsoft.Orbital/l2Connections,Orbital L2 Connections,No
-no,Microsoft.Orbital/edgeSites,Orbital Edge Sites,No
-no,Microsoft.Orbital/operations,null,No
-no,Microsoft.Orbital/locations,null,No
-no,Microsoft.Orbital/locations/operationResults,null,No
-no,Microsoft.Orbital/locations/operationStatuses,null,No
-no,Microsoft.PartnerManagedConsumerRecurrence/recurrences,null,No
-no,Microsoft.PartnerManagedConsumerRecurrence/operations,null,No
-no,Microsoft.PartnerManagedConsumerRecurrence/checkEligibility,null,No
-no,Microsoft.PartnerManagedConsumerRecurrence/operationStatuses,null,No
-no,Microsoft.Peering/peerings,Peerings,No
-no,Microsoft.Peering/peeringLocations,null,No
-no,Microsoft.Peering/legacyPeerings,null,No
-no,Microsoft.Peering/peerAsns,null,No
-no,Microsoft.Peering/peeringServices,null,No
-no,Microsoft.Peering/peeringServiceCountries,null,No
-no,Microsoft.Peering/peeringServiceLocations,null,No
-no,Microsoft.Peering/peeringServiceProviders,null,No
-no,Microsoft.Peering/checkServiceProviderAvailability,null,No
-no,Microsoft.Peering/lookingGlass,null,No
-no,Microsoft.Peering/cdnPeeringPrefixes,null,No
-no,Microsoft.Peering/operations,null,No
-no,Microsoft.Pki/Operations,null,No
-no,Microsoft.Portal/dashboards,null,No
-no,Microsoft.Portal/tenantconfigurations,null,No
-no,Microsoft.Portal/listTenantConfigurationViolations,null,No
-no,Microsoft.Portal/operations,null,No
-no,Microsoft.Portal/locations,null,No
-no,Microsoft.Portal/consoles,null,No
-no,Microsoft.Portal/locations/consoles,null,No
-no,Microsoft.Portal/userSettings,null,No
-no,Microsoft.Portal/locations/userSettings,null,No
-no,Microsoft.PowerBI/workspaceCollections,null,No
-no,Microsoft.PowerBI/locations,null,No
-no,Microsoft.PowerBI/locations/checkNameAvailability,null,No
-no,Microsoft.PowerBI/privateLinkServicesForPowerBI,null,No
-no,Microsoft.PowerBI/privateLinkServicesForPowerBI/operationResults,null,No
-no,Microsoft.PowerBI/operations,null,No
-no,Microsoft.PowerBIDedicated/capacities,null,No
-no,Microsoft.PowerBIDedicated/autoScaleVCores,null,No
-no,Microsoft.PowerBIDedicated/locations,null,No
-no,Microsoft.PowerBIDedicated/locations/checkNameAvailability,null,No
-no,Microsoft.PowerBIDedicated/locations/operationresults,null,No
-no,Microsoft.PowerBIDedicated/locations/operationstatuses,null,No
-no,Microsoft.PowerBIDedicated/operations,null,No
-no,Microsoft.PowerPlatform/operations,null,No
-no,Microsoft.PowerPlatform/enterprisePolicies,null,No
-no,Microsoft.PowerPlatform/accounts,null,No
-no,Microsoft.PowerPlatform/locations,null,No
-no,Microsoft.PowerPlatform/locations/deleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.PowerPlatform/locations/validateDeleteVirtualNetworkOrSubnets,null,No
-no,Microsoft.ProfessionalService/checkNameAvailability,null,No
-no,Microsoft.ProfessionalService/eligibilityCheck,null,No
-no,Microsoft.ProfessionalService/operationResults,null,No
-no,Microsoft.ProfessionalService/operations,null,No
-no,Microsoft.ProfessionalService/resources,null,No
-no,Microsoft.ProgrammableConnectivity/operations,null,No
-no,Microsoft.ProgrammableConnectivity/locations,null,No
-no,Microsoft.ProgrammableConnectivity/locations/operationStatuses,null,No
-no,Microsoft.ProgrammableConnectivity/gateways,null,No
-no,Microsoft.ProgrammableConnectivity/openApiGateways,null,No
-no,Microsoft.ProgrammableConnectivity/openApiGatewayOfferings,null,No
-no,Microsoft.ProgrammableConnectivity/OperatorOfferings,null,No
-no,Microsoft.ProgrammableConnectivity/OperatorConnections,null,No
-no,Microsoft.ProgrammableConnectivity/operatorApiPlans,null,No
-no,Microsoft.ProgrammableConnectivity/operatorApiConnections,null,No
-no,Microsoft.ProviderHub/providerRegistrations,null,No
-no,Microsoft.ProviderHub/operationStatuses,null,No
-no,Microsoft.ProviderHub/providerRegistrations/resourceTypeRegistrations,null,No
-no,Microsoft.ProviderHub/providerRegistrations/defaultRollouts,null,No
-no,Microsoft.ProviderHub/providerRegistrations/customRollouts,null,No
-no,Microsoft.ProviderHub/providerRegistrations/checkinmanifest,null,No
-no,Microsoft.ProviderHub/providerRegistrations/resourceActions,null,No
-no,Microsoft.ProviderHub/availableAccounts,null,No
-no,Microsoft.ProviderHub/providerRegistrations/authorizedApplications,null,No
-yes,Microsoft.Purview/accounts,Purview Accounts,No
-no,Microsoft.Purview/accounts/kafkaConfigurations,null,No
-no,Microsoft.Purview/operations,null,No
-no,Microsoft.Purview/setDefaultAccount,null,No
-no,Microsoft.Purview/removeDefaultAccount,null,No
-no,Microsoft.Purview/getDefaultAccount,null,No
-no,Microsoft.Purview/checkNameAvailability,null,No
-no,Microsoft.Purview/locations,null,No
-no,Microsoft.Purview/locations/operationResults,null,No
-no,Microsoft.Purview/locations/listFeatures,null,No
-no,Microsoft.Purview/locations/usages,null,No
-no,Microsoft.Purview/policies,null,No
-yes,Microsoft.Quantum/Workspaces,Quantum Workspaces,No
-no,Microsoft.Quantum/Operations,null,No
-no,Microsoft.Quantum/Locations,null,No
-no,Microsoft.Quantum/Locations/OperationStatuses,null,No
-no,Microsoft.Quantum/locations/offerings,null,No
-no,Microsoft.Quantum/Locations/CheckNameAvailability,null,No
-no,Microsoft.RecommendationsService/locations,null,No
-no,Microsoft.RecommendationsService/locations/operationStatuses,null,No
-no,Microsoft.RecommendationsService/accounts,null,No
-no,Microsoft.RecommendationsService/accounts/modeling,null,No
-no,Microsoft.RecommendationsService/accounts/serviceEndpoints,null,No
-no,Microsoft.RecommendationsService/operations,null,No
-no,Microsoft.RecommendationsService/checkNameAvailability,null,No
-yes,Microsoft.RecoveryServices/vaults,Recovery Services,Yes
-no,Microsoft.RecoveryServices/operations,null,No
-no,Microsoft.RecoveryServices/locations,null,No
-no,Microsoft.RecoveryServices/locations/backupStatus,null,No
-no,Microsoft.RecoveryServices/locations/checkNameAvailability,null,No
-no,Microsoft.RecoveryServices/locations/allocatedStamp,null,No
-no,Microsoft.RecoveryServices/locations/allocateStamp,null,No
-no,Microsoft.RecoveryServices/locations/backupValidateFeatures,null,No
-no,Microsoft.RecoveryServices/locations/backupPreValidateProtection,null,No
-no,Microsoft.RecoveryServices/locations/backupCrrJobs,null,No
-no,Microsoft.RecoveryServices/locations/backupCrrJob,null,No
-no,Microsoft.RecoveryServices/locations/backupAadProperties,null,No
-no,Microsoft.RecoveryServices/locations/backupCrossRegionRestore,null,No
-no,Microsoft.RecoveryServices/locations/backupCrrOperationResults,null,No
-no,Microsoft.RecoveryServices/locations/backupCrrOperationsStatus,null,No
-yes,Microsoft.RecoveryServices/backupProtectedItems,Recovery Services Backup Protected Items,No
-no,Microsoft.RecoveryServices/replicationEligibilityResults,null,No
-no,Microsoft.RecoveryServices/locations/capabilities,null,No
-no,Microsoft.RedHatOpenShift/locations,null,No
-no,Microsoft.RedHatOpenShift/locations/operationresults,null,No
-no,Microsoft.RedHatOpenShift/locations/operationsstatus,null,No
-yes,Microsoft.RedHatOpenShift/OpenShiftClusters,RedHat Open Shift Clusters,No
-no,Microsoft.RedHatOpenShift/operations,null,No
-no,Microsoft.RedHatOpenShift/locations/openshiftversions,null,No
-yes,Microsoft.Relay/namespaces,Relay,No
-no,Microsoft.Relay/namespaces/authorizationrules,null,No
-no,Microsoft.Relay/namespaces/privateEndpointConnections,null,No
-no,Microsoft.Relay/namespaces/privateEndpointConnectionProxies,null,No
-no,Microsoft.Relay/namespaces/hybridconnections,null,No
-no,Microsoft.Relay/namespaces/hybridconnections/authorizationrules,null,No
-no,Microsoft.Relay/namespaces/wcfrelays,null,No
-no,Microsoft.Relay/namespaces/wcfrelays/authorizationrules,null,No
-no,Microsoft.Relay/checkNameAvailability,null,No
-no,Microsoft.Relay/operations,null,No
-no,Microsoft.Relay/locations,null,No
-no,Microsoft.Relay/locations/namespaceOperationResults,null,No
-no,Microsoft.ResourceConnector/locations,null,No
-no,Microsoft.ResourceConnector/appliances,null,No
-no,Microsoft.ResourceConnector/locations/operationsstatus,null,No
-no,Microsoft.ResourceConnector/locations/operationresults,null,No
-no,Microsoft.ResourceConnector/operations,null,No
-no,Microsoft.ResourceConnector/telemetryconfig,null,No
-no,Microsoft.ResourceGraph/resources,null,No
-no,Microsoft.ResourceGraph/resourcesHistory,null,No
-no,Microsoft.ResourceGraph/resourceChanges,null,No
-no,Microsoft.ResourceGraph/resourceChangeDetails,null,No
-no,Microsoft.ResourceGraph/operations,null,No
-no,Microsoft.ResourceGraph/subscriptionsStatus,null,No
-no,Microsoft.ResourceGraph/queries,null,No
-no,Microsoft.ResourceGraph/generateQuery,null,No
-no,Microsoft.ResourceNotifications/eventGridFilters,null,No
-no,Microsoft.ResourceNotifications/operations,null,No
-no,Microsoft.Resources/moboBrokers,null,No
-no,Microsoft.Resources/locations/moboOperationStatuses,null,No
-no,Microsoft.Resources/deploymentScripts,null,No
-no,Microsoft.Resources/deploymentScripts/logs,null,No
-no,Microsoft.Resources/locations/deploymentScriptOperationResults,null,No
-no,Microsoft.Resources/decompileBicep,null,No
-no,Microsoft.Resources/templateSpecs,null,No
-no,Microsoft.Resources/templateSpecs/versions,null,No
-no,Microsoft.Resources/builtInTemplateSpecs,null,No
-no,Microsoft.Resources/builtInTemplateSpecs/versions,null,No
-no,Microsoft.Resources/deploymentStacks,null,No
-no,Microsoft.Resources/locations/deploymentStackOperationStatus,null,No
-no,Microsoft.Resources/tenants,null,No
-no,Microsoft.Resources/locations,null,No
-no,Microsoft.Resources/operationresults,null,No
-no,Microsoft.Resources/notifyResourceJobs,null,No
-no,Microsoft.Resources/tags,null,No
-no,Microsoft.Resources/checkPolicyCompliance,null,No
-no,Microsoft.Resources/providers,null,No
-no,Microsoft.Resources/checkresourcename,null,No
-no,Microsoft.Resources/calculateTemplateHash,null,No
-no,Microsoft.Resources/resources,null,No
-yes,Microsoft.Resources/subscriptions,Subscriptions,Yes
-no,Microsoft.Resources/subscriptions/resources,null,No
-no,Microsoft.Resources/subscriptions/providers,null,No
-no,Microsoft.Resources/subscriptions/operationresults,null,No
-no,Microsoft.Resources/resourceGroups,Resource Groups,No
-no,Microsoft.Resources/subscriptions/resourceGroups,Resource Groups,No
-no,Microsoft.Resources/subscriptions/resourcegroups/resources,null,No
-no,Microsoft.Resources/subscriptions/locations,null,No
-no,Microsoft.Resources/subscriptions/tagnames,null,No
-no,Microsoft.Resources/subscriptions/tagNames/tagValues,null,No
-yes,Microsoft.Resources/deployments,null,Yes
-no,Microsoft.Resources/deployments/operations,null,No
-no,Microsoft.Resources/validateResources,null,No
-no,Microsoft.Resources/links,null,No
-no,Microsoft.Resources/operations,null,No
-no,Microsoft.Resources/bulkDelete,null,No
-no,Microsoft.Resources/changes,null,No
-no,Microsoft.Resources/snapshots,null,No
-no,Microsoft.Resources/dataBoundaries,null,No
-no,Microsoft.SaaS/applications,null,No
-no,Microsoft.SaaS/checknameavailability,null,No
-no,Microsoft.SaaS/saasresources,null,No
-no,Microsoft.SaaS/operationResults,null,No
-no,Microsoft.SaaS/operations,null,No
-no,Microsoft.SaaS/resources,null,No
-no,Microsoft.SaaSHub/operationStatuses,null,No
-no,Microsoft.SaaSHub/cloudServices,null,No
-no,Microsoft.SaaSHub/operations,null,No
-no,Microsoft.SaaSHub/registeredSubscriptions,null,No
-no,Microsoft.SaaSHub/checkNameAvailability,null,No
-no,Microsoft.SaaSHub/canCreate,null,No
-no,Microsoft.SaaSHub/locations,null,No
-no,Microsoft.SaaSHub/locations/operationStatuses,null,No
-no,Microsoft.Scom/locations/operationStatuses,null,No
-no,Microsoft.Scom/operations,null,No
-no,Microsoft.Scom/locations,null,No
-no,Microsoft.Scom/managedInstances,null,No
-no,Microsoft.Scom/managedInstances/monitoredResources,null,No
-no,Microsoft.Scom/managedInstances/managedGateways,null,No
-no,Microsoft.ScVmm/locations,null,No
-no,Microsoft.ScVmm/Locations/OperationStatuses,null,No
-no,Microsoft.ScVmm/operations,null,No
-no,Microsoft.ScVmm/VMMServers,null,No
-no,Microsoft.ScVmm/Clouds,null,No
-no,Microsoft.ScVmm/VirtualNetworks,null,No
-no,Microsoft.ScVmm/VirtualMachineTemplates,null,No
-no,Microsoft.ScVmm/VirtualMachines,null,No
-no,Microsoft.ScVmm/AvailabilitySets,null,No
-no,Microsoft.ScVmm/VMMServers/InventoryItems,null,No
-no,Microsoft.ScVmm/VirtualMachines/HybridIdentityMetadata,null,No
-no,Microsoft.ScVmm/VirtualMachines/GuestAgents,null,No
-no,Microsoft.ScVmm/VirtualMachines/Extensions,null,No
-no,Microsoft.ScVmm/VirtualMachineInstances,null,No
-yes,Microsoft.Search/searchServices,Search service,Yes
-no,Microsoft.Search/checkServiceNameAvailability,null,No
-no,Microsoft.Search/checkNameAvailability,null,No
-no,Microsoft.Search/resourceHealthMetadata,null,No
-no,Microsoft.Search/operations,null,No
-no,Microsoft.Search/locations,null,No
-no,Microsoft.Search/locations/notifyNetworkSecurityPerimeterUpdatesAvailable,null,No
-no,Microsoft.Search/locations/usages,null,No
-no,Microsoft.Search/locations/operationResults,null,No
-no,Microsoft.SecurityCopilot/Operations,null,No
-no,Microsoft.SecurityCopilot/locations,null,No
-no,Microsoft.SecurityDetonation/chambers,null,No
-no,Microsoft.SecurityDetonation/operations,null,No
-no,Microsoft.SecurityDetonation/operationResults,null,No
-no,Microsoft.SecurityDetonation/checkNameAvailability,null,No
-no,Microsoft.SecurityDevOps/Locations,null,No
-no,Microsoft.SecurityDevOps/Locations/OperationStatuses,null,No
-no,Microsoft.SecurityDevOps/gitHubConnectors,null,No
-no,Microsoft.SecurityDevOps/azureDevOpsConnectors,null,No
-no,Microsoft.SecurityDevOps/azureDevOpsConnectors/orgs,DevOps Connectors Org,Yes
-no,Microsoft.SecurityDevOps/gitHubConnectors/owners,null,No
-no,Microsoft.SecurityDevOps/azureDevOpsConnectors/orgs/projects,null,No
-no,Microsoft.SecurityDevOps/gitHubConnectors/owners/repos,Github Owner Repository,Yes
-no,Microsoft.SecurityDevOps/azureDevOpsConnectors/orgs/projects/repos,null,No
-no,Microsoft.SecurityDevOps/Operations,null,No
-no,Microsoft.SecurityDevOps/gitHubConnectors/stats,null,No
-no,Microsoft.SecurityDevOps/gitHubConnectors/repos,Github Connectors Repo,Yes
-no,Microsoft.SecurityDevOps/azureDevOpsConnectors/stats,null,No
-no,Microsoft.SecurityDevOps/azureDevOpsConnectors/repos,null,No
-no,Microsoft.SecurityDevOps/gitLabConnectors,null,No
-no,Microsoft.SecurityDevOps/gitHubConnectors/gitHubInstallations,null,No
-no,Microsoft.SecurityDevOps/gitHubConnectors/gitHubInstallations/gitHubRepositories,null,No
-no,Microsoft.SecurityDevOps/gitLabConnectors/groups,null,No
-no,Microsoft.SecurityDevOps/gitLabConnectors/projects,null,No
-no,Microsoft.SecurityDevOps/gitLabConnectors/stats,null,No
-no,Microsoft.SecurityDevOps/gitLabConnectors/groups/projects,null,No
-no,Microsoft.SecurityInsights/operations,null,No
-no,Microsoft.SecurityInsights/alertRules,null,No
-no,Microsoft.SecurityInsights/alertRuleTemplates,null,No
-no,Microsoft.SecurityInsights/triggeredAnalyticsRuleRuns,null,No
-no,Microsoft.SecurityInsights/cases,null,No
-no,Microsoft.SecurityInsights/bookmarks,null,No
-no,Microsoft.SecurityInsights/dataConnectors,null,No
-no,Microsoft.SecurityInsights/dataConnectorDefinitions,null,No
-no,Microsoft.SecurityInsights/dataConnectorsCheckRequirements,null,No
-no,Microsoft.SecurityInsights/enrichment,null,No
-no,Microsoft.SecurityInsights/fileImports,null,No
-no,Microsoft.SecurityInsights/entities,null,No
-no,Microsoft.SecurityInsights/incidents,null,No
-no,Microsoft.SecurityInsights/officeConsents,null,No
-no,Microsoft.SecurityInsights/settings,null,No
-no,Microsoft.SecurityInsights/aggregations,null,No
-no,Microsoft.SecurityInsights/entityQueries,null,No
-no,Microsoft.SecurityInsights/entityQueryTemplates,null,No
-no,Microsoft.SecurityInsights/threatIntelligence,null,No
-no,Microsoft.SecurityInsights/automationRules,null,No
-no,Microsoft.SecurityInsights/businessApplicationAgents,null,No
-no,Microsoft.SecurityInsights/sourceControls,null,No
-no,Microsoft.SecurityInsights/exportConnections,null,No
-no,Microsoft.SecurityInsights/listrepositories,null,No
-no,Microsoft.SecurityInsights/watchlists,null,No
-no,Microsoft.SecurityInsights/confidentialWatchlists,null,No
-no,Microsoft.SecurityInsights/huntsessions,null,No
-no,Microsoft.SecurityInsights/hunts,null,No
-no,Microsoft.SecurityInsights/onboardingStates,null,No
-no,Microsoft.SecurityInsights/metadata,null,No
-no,Microsoft.SecurityInsights/contentPackages,null,No
-no,Microsoft.SecurityInsights/contentTemplates,null,No
-no,Microsoft.SecurityInsights/contentProductPackages,null,No
-no,Microsoft.SecurityInsights/contentProductTemplates,null,No
-no,Microsoft.SecurityInsights/MitreCoverageRecords,null,No
-no,Microsoft.SecurityInsights/overview,null,No
-no,Microsoft.SecurityInsights/recommendations,null,No
-no,Microsoft.SecurityInsights/billingStatistics,null,No
-no,Microsoft.SecurityInsights/workspaceManagerConfigurations,null,No
-no,Microsoft.SecurityInsights/workspaceManagerMembers,null,No
-no,Microsoft.SecurityInsights/workspaceManagerGroups,null,No
-no,Microsoft.SecurityInsights/workspaceManagerAssignments,null,No
-no,Microsoft.SecurityInsights/securityMLAnalyticsSettings,null,No
-no,Microsoft.SecurityInsights/contenttranslators,null,No
-no,Microsoft.SerialConsole/consoleServices,null,No
-no,Microsoft.SerialConsole/serialPorts,null,No
-no,Microsoft.SerialConsole/locations,null,No
-no,Microsoft.SerialConsole/locations/consoleServices,null,No
-no,Microsoft.SerialConsole/operations,null,No
-yes,Microsoft.ServiceFabric/clusters,Service fabric cluster,Yes
-no,Microsoft.ServiceFabric/clusters/applications,null,No
-no,Microsoft.ServiceFabric/clusters/applicationTypes,null,No
-no,Microsoft.ServiceFabric/clusters/applicationTypes/versions,null,No
-no,Microsoft.ServiceFabric/clusters/applications/services,null,No
-no,Microsoft.ServiceFabric/locations,null,No
-no,Microsoft.ServiceFabric/locations/clusterVersions,null,No
-no,Microsoft.ServiceFabric/locations/environments,null,No
-no,Microsoft.ServiceFabric/locations/operations,null,No
-no,Microsoft.ServiceFabric/locations/operationResults,null,No
-no,Microsoft.ServiceFabric/locations/unsupportedVMSizes,null,No
-no,Microsoft.ServiceFabric/operations,null,No
-yes,Microsoft.ServiceFabric/managedclusters,Service Fabric Managed Clusters,No
-no,Microsoft.ServiceFabric/managedclusters/nodetypes,null,No
-no,Microsoft.ServiceFabric/managedclusters/applicationTypes,null,No
-no,Microsoft.ServiceFabric/managedclusters/applicationTypes/versions,null,No
-no,Microsoft.ServiceFabric/managedclusters/applications,null,No
-no,Microsoft.ServiceFabric/managedclusters/applications/services,null,No
-no,Microsoft.ServiceFabric/locations/managedClusterOperations,null,No
-no,Microsoft.ServiceFabric/locations/managedClusterOperationResults,null,No
-no,Microsoft.ServiceFabric/locations/managedClusterVersions,null,No
-no,Microsoft.ServiceFabric/locations/environments/managedClusterVersions,null,No
-no,Microsoft.ServiceFabric/locations/managedUnsupportedVMSizes,null,No
-yes,Microsoft.ServiceFabricMesh/applications,Service Fabric Mesh Applications,No
-yes,Microsoft.ServiceFabricMesh/networks,Service Fabric Mesh Networks,No
-yes,Microsoft.ServiceFabricMesh/volumes,Service Fabric Mesh Volumes,No
-no,Microsoft.ServiceFabricMesh/secrets,Service Fabric Mesh Secrets,No
-yes,Microsoft.ServiceFabricMesh/gateways,Service Fabric Mesh Gateways,No
-no,Microsoft.ServiceFabricMesh/locations,null,No
-no,Microsoft.ServiceFabricMesh/locations/applicationOperations,null,No
-no,Microsoft.ServiceFabricMesh/locations/networkOperations,null,No
-no,Microsoft.ServiceFabricMesh/locations/volumeOperations,null,No
-no,Microsoft.ServiceFabricMesh/locations/gatewayOperations,null,No
-no,Microsoft.ServiceFabricMesh/locations/secretOperations,null,No
-no,Microsoft.ServiceFabricMesh/operations,null,No
-yes,Microsoft.ServiceNetworking/trafficControllers,Application Gateway for Containers,Yes
-no,Microsoft.ServiceNetworking/trafficControllers/frontends,null,No
-no,Microsoft.ServiceNetworking/trafficControllers/associations,null,No
-no,Microsoft.ServiceNetworking/operations,null,No
-no,Microsoft.ServiceNetworking/locations,null,No
-no,Microsoft.ServiceNetworking/locations/operations,null,No
-no,Microsoft.ServiceNetworking/locations/operationResults,null,No
-no,Microsoft.ServicesHub/connectors,null,No
-no,Microsoft.ServicesHub/workspaces,Services Hub Workspaces,No
-no,Microsoft.ServicesHub/supportOfferingEntitlement,null,No
-no,Microsoft.ServicesHub/operations,null,No
-no,Microsoft.ServicesHub/getRecommendationsContent,null,No
-no,Microsoft.ServicesHub/connectors/connectorSpaces,null,No
-yes,Microsoft.SignalRService/SignalR,SignalR Service,Yes
-yes,Microsoft.SignalRService/WebPubSub,SignalR Service WebPubSub,No
-no,Microsoft.SignalRService/SignalR/replicas,null,No
-no,Microsoft.SignalRService/WebPubSub/replicas,null,No
-no,Microsoft.SignalRService/locations,null,No
-no,Microsoft.SignalRService/locations/operationResults,null,No
-no,Microsoft.SignalRService/locations/operationStatuses,null,No
-no,Microsoft.SignalRService/operations,null,No
-no,Microsoft.SignalRService/locations/checkNameAvailability,null,No
-no,Microsoft.SignalRService/locations/usages,null,No
-no,Microsoft.SignalRService/SignalR/eventGridFilters,null,No
-no,Microsoft.SignalRService/SignalR/customDomains,null,No
-no,Microsoft.SignalRService/WebPubSub/customDomains,null,No
-yes,Microsoft.Singularity/accounts,Singularity Accounts,No
-no,Microsoft.Singularity/accounts/storageContainers,null,No
-no,Microsoft.Singularity/accounts/networks,null,No
-no,Microsoft.Singularity/accounts/secrets,null,No
-no,Microsoft.Singularity/accounts/accountQuotaPolicies,null,No
-no,Microsoft.Singularity/accounts/groupPolicies,null,No
-no,Microsoft.Singularity/accounts/jobs,null,No
-no,Microsoft.Singularity/accounts/models,null,No
-no,Microsoft.Singularity/locations,null,No
-no,Microsoft.Singularity/locations/instanceTypeSeries,null,No
-no,Microsoft.Singularity/locations/instanceTypeSeries/instanceTypes,null,No
-no,Microsoft.Singularity/locations/operationResults,null,No
-no,Microsoft.Singularity/locations/operationStatus,null,No
-no,Microsoft.Singularity/operations,null,No
-no,Microsoft.Singularity/images,null,No
-no,Microsoft.Singularity/quotas,null,No
-no,Microsoft.SoftwarePlan/hybridUseBenefits,null,No
-no,Microsoft.SoftwarePlan/operations,null,No
-no,Microsoft.Solutions/applications,null,No
-no,Microsoft.Solutions/applicationDefinitions,null,No
-no,Microsoft.Solutions/locations,null,No
-no,Microsoft.Solutions/jitRequests,null,No
-no,Microsoft.Solutions/locations/operationstatuses,null,No
-no,Microsoft.Solutions/Operations,null,No
-no,Microsoft.Sovereign/Locations,null,No
-no,Microsoft.Sovereign/Locations/OperationStatuses,null,No
-no,Microsoft.Sovereign/landingZoneConfigurations,null,No
-no,Microsoft.Sovereign/landingZoneRegistrations,null,No
-no,Microsoft.Sovereign/Operations,null,No
-no,Microsoft.Sovereign/checkNameAvailability,null,No
-yes,Microsoft.SqlVirtualMachine/SqlVirtualMachineGroups,SQL virtual machine SQL VM Group,No
-yes,Microsoft.SqlVirtualMachine/SqlVirtualMachines,SQL virtual machine,Yes
-no,Microsoft.SqlVirtualMachine/SqlVirtualMachineGroups/AvailabilityGroupListeners,null,No
-no,Microsoft.SqlVirtualMachine/operations,null,No
-no,Microsoft.SqlVirtualMachine/Locations,null,No
-no,Microsoft.SqlVirtualMachine/Locations/OperationTypes,null,No
-no,Microsoft.SqlVirtualMachine/Locations/sqlVirtualMachineOperationResults,null,No
-no,Microsoft.SqlVirtualMachine/Locations/sqlVirtualMachineGroupOperationResults,null,No
-no,Microsoft.SqlVirtualMachine/Locations/availabilityGroupListenerOperationResults,null,No
-no,Microsoft.SqlVirtualMachine/Locations/registerSqlVmCandidate,null,No
-no,Microsoft.StandbyPool/Locations,null,No
-no,Microsoft.StandbyPool/Locations/OperationStatuses,null,No
-no,Microsoft.StandbyPool/Operations,null,No
-no,Microsoft.StorageActions/storageTasks,null,No
-no,Microsoft.StorageActions/operations,null,No
-no,Microsoft.StorageActions/locations/asyncoperations,null,No
-no,Microsoft.StorageActions/locations/previewActions,null,No
-no,Microsoft.StorageActions/locations,null,No
-yes,Microsoft.StorageCache/caches,Storage Cache,No
-no,Microsoft.StorageCache/caches/storageTargets,null,No
-no,Microsoft.StorageCache/amlFilesystems,null,No
-no,Microsoft.StorageCache/operations,null,No
-no,Microsoft.StorageCache/usageModels,null,No
-no,Microsoft.StorageCache/checkAmlFSSubnets,null,No
-no,Microsoft.StorageCache/getRequiredAmlFSSubnetsSize,null,No
-no,Microsoft.StorageCache/locations,null,No
-no,Microsoft.StorageCache/locations/ascoperations,null,No
-no,Microsoft.StorageCache/locations/usages,null,No
-no,Microsoft.StorageMover/storageMovers,null,No
-no,Microsoft.StorageMover/storageMovers/projects,null,No
-no,Microsoft.StorageMover/storageMovers/agents,null,No
-no,Microsoft.StorageMover/storageMovers/endpoints,null,No
-no,Microsoft.StorageMover/storageMovers/projects/jobDefinitions,null,No
-no,Microsoft.StorageMover/operations,null,No
-no,Microsoft.StorageMover/storageMovers/projects/jobDefinitions/jobRuns,null,No
-no,Microsoft.StorageMover/locations,null,No
-no,Microsoft.StorageMover/locations/operationStatuses,null,No
-yes,Microsoft.StorageSync/storageSyncServices,Storage Sync Services,No
-no,Microsoft.StorageSync/storageSyncServices/syncGroups,null,No
-no,Microsoft.StorageSync/storageSyncServices/syncGroups/cloudEndpoints,null,No
-no,Microsoft.StorageSync/storageSyncServices/syncGroups/serverEndpoints,null,No
-no,Microsoft.StorageSync/storageSyncServices/registeredServers,null,No
-no,Microsoft.StorageSync/storageSyncServices/workflows,null,No
-no,Microsoft.StorageSync/operations,null,No
-no,Microsoft.StorageSync/locations,null,No
-no,Microsoft.StorageSync/locations/checkNameAvailability,null,No
-no,Microsoft.StorageSync/locations/workflows,null,No
-no,Microsoft.StorageSync/locations/operations,null,No
-no,Microsoft.StorageSync/locations/operationResults,null,No
-no,Microsoft.StorageTasks/locations,null,No
-yes,Microsoft.StreamAnalytics/streamingjobs,Stream Analytics Streaming job,Yes
-yes,Microsoft.StreamAnalytics/clusters,Stream Analytics Clusters,No
-no,Microsoft.StreamAnalytics/clusters/privateEndpoints,null,No
-no,Microsoft.StreamAnalytics/locations,null,No
-no,Microsoft.StreamAnalytics/locations/quotas,null,No
-no,Microsoft.StreamAnalytics/locations/testQuery,null,No
-no,Microsoft.StreamAnalytics/locations/compileQuery,null,No
-no,Microsoft.StreamAnalytics/locations/sampleInput,null,No
-no,Microsoft.StreamAnalytics/locations/testInput,null,No
-no,Microsoft.StreamAnalytics/locations/testOutput,null,No
-no,Microsoft.StreamAnalytics/locations/operationResults,null,No
-no,Microsoft.StreamAnalytics/operations,null,No
-no,Microsoft.Subscription/SubscriptionDefinitions,null,No
-no,Microsoft.Subscription/SubscriptionOperations,null,No
-no,Microsoft.Subscription/CreateSubscription,null,No
-no,Microsoft.Subscription/operations,null,No
-no,Microsoft.Subscription/cancel,null,No
-no,Microsoft.Subscription/validateCancel,null,No
-no,Microsoft.Subscription/rename,null,No
-no,Microsoft.Subscription/enable,null,No
-yes,Microsoft.Subscription/subscriptions,Subscriptions,Yes
-no,Microsoft.Subscription/aliases,null,No
-no,Microsoft.Subscription/operationResults,null,No
-no,Microsoft.Subscription/acceptChangeTenant,null,No
-no,Microsoft.Subscription/changeTenantStatus,null,No
-no,Microsoft.Subscription/changeTenantRequest,null,No
-no,Microsoft.Subscription/policies,Policies,No
-no,Microsoft.Subscription/acceptOwnership,null,No
-no,Microsoft.Subscription/acceptOwnershipStatus,null,No
-no,microsoft.support/operations,null,No
-no,microsoft.support/checkNameAvailability,null,No
-no,microsoft.support/classifyServices,null,No
-no,microsoft.support/services,null,No
-no,microsoft.support/services/problemclassifications,null,No
-no,microsoft.support/supporttickets,null,No
-no,microsoft.support/supporttickets/communications,null,No
-no,microsoft.support/operationresults,null,No
-no,microsoft.support/operationsstatus,null,No
-no,microsoft.support/lookUpResourceId,null,No
-no,microsoft.support/fileWorkspaces,null,No
-no,microsoft.support/fileWorkspaces/files,null,No
-yes,Microsoft.Synapse/workspaces,Azure Synapse,Yes
-no,Microsoft.Synapse/workspaces/bigDataPools,null,No
-no,Microsoft.Synapse/workspaces/sqlPools,null,No
-no,Microsoft.Synapse/workspaces/sqlDatabases,null,No
-no,Microsoft.Synapse/locations/sqlDatabaseAzureAsyncOperation,null,No
-no,Microsoft.Synapse/locations/sqlDatabaseOperationResults,null,No
-no,Microsoft.Synapse/workspaces/kustoPools,null,No
-no,Microsoft.Synapse/locations/kustoPoolOperationResults,null,No
-no,Microsoft.Synapse/locations/kustoPoolCheckNameAvailability,null,No
-no,Microsoft.Synapse/workspaces/kustoPools/databases,null,No
-no,Microsoft.Synapse/workspaces/kustoPools/attacheddatabaseconfigurations,null,No
-no,Microsoft.Synapse/workspaces/kustoPools/databases/dataconnections,null,No
-no,Microsoft.Synapse/locations/sqlPoolAzureAsyncOperation,null,No
-no,Microsoft.Synapse/locations/sqlPoolOperationResults,null,No
-no,Microsoft.Synapse/workspaces/operationStatuses,null,No
-no,Microsoft.Synapse/workspaces/operationResults,null,No
-no,Microsoft.Synapse/checkNameAvailability,null,No
-no,Microsoft.Synapse/operations,null,No
-no,Microsoft.Synapse/kustoOperations,null,No
-no,Microsoft.Synapse/privateLinkHubs,null,No
-no,Microsoft.Synapse/locations,null,No
-no,Microsoft.Synapse/locations/operationResults,null,No
-no,Microsoft.Synapse/locations/operationStatuses,null,No
-no,Microsoft.Synapse/locations/usages,null,No
-no,Microsoft.Synapse/workspaces/usages,null,No
-no,Microsoft.Syntex/documentProcessors,null,No
-no,Microsoft.Syntex/operations,null,No
-no,Microsoft.Syntex/accounts,null,No
-no,Microsoft.Syntex/Locations,null,No
-no,Microsoft.Syntex/Locations/OperationStatuses,null,No
-no,Microsoft.TestBase/locations,null,No
-no,Microsoft.TestBase/locations/operationstatuses,null,No
-no,Microsoft.TestBase/skus,null,No
-no,Microsoft.TestBase/operations,null,No
-yes,Microsoft.TestBase/testBaseAccounts,Test Base Accounts,No
-no,Microsoft.TestBase/testBaseAccounts/usages,null,No
-no,Microsoft.TestBase/testBaseAccounts/availableOSs,null,No
-no,Microsoft.TestBase/testBaseAccounts/testTypes,null,No
-no,Microsoft.TestBase/testBaseAccounts/flightingRings,null,No
-no,Microsoft.TestBase/testBaseAccounts/packages,null,No
-no,Microsoft.TestBase/testBaseAccounts/packages/osUpdates,null,No
-no,Microsoft.TestBase/testBaseAccounts/testSummaries,null,No
-no,Microsoft.TestBase/testBaseAccounts/packages/favoriteProcesses,null,No
-no,Microsoft.TestBase/testBaseAccounts/packages/testResults,null,No
-no,Microsoft.TestBase/testBaseAccounts/packages/testResults/analysisResults,null,No
-no,Microsoft.TestBase/testBaseAccounts/emailEvents,null,No
-no,Microsoft.TestBase/testBaseAccounts/customerEvents,null,No
-no,Microsoft.TestBase/testBaseAccounts/featureUpdateSupportedOses,null,No
-no,Microsoft.TestBase/testBaseAccounts/availableInplaceUpgradeOSs,null,No
-no,Microsoft.TestBase/testBaseAccounts/firstPartyApps,null,No
-no,Microsoft.TestBase/testBaseAccounts/draftPackages,null,No
-no,Microsoft.TestBase/testBaseAccounts/actionRequests,null,No
-no,Microsoft.TestBase/testBaseAccounts/testConfigurations,null,No
-no,Microsoft.TestBase/testBaseAccounts/availableVMConfigurationTypes,null,No
-no,Microsoft.TestBase/testBaseAccounts/customImages,null,No
-no,Microsoft.TestBase/testBaseAccounts/vhds,null,No
-no,Microsoft.TestBase/testBaseAccounts/imageDefinitions,null,No
-no,Microsoft.TestBase/testBaseAccounts/galleryApps,null,No
-no,Microsoft.TestBase/testBaseAccounts/galleryApps/galleryAppSkus,null,No
-no,Microsoft.TestBase/testBaseAccounts/chatSessions,null,No
-no,Microsoft.TestBase/testBaseAccounts/freeHourBalances,null,No
-no,Microsoft.TestBase/testBaseAccounts/credentials,null,No
-no,Microsoft.TestBase/testBaseAccounts/testConfigurations/testResults,null,No
-no,Microsoft.TimeSeriesInsights/environments,null,No
-no,Microsoft.TimeSeriesInsights/environments/eventsources,null,No
-no,Microsoft.TimeSeriesInsights/environments/referenceDataSets,null,No
-no,Microsoft.TimeSeriesInsights/environments/accessPolicies,null,No
-no,Microsoft.TimeSeriesInsights/environments/privateLinkResources,null,No
-no,Microsoft.TimeSeriesInsights/environments/privateEndpointConnectionProxies,null,No
-no,Microsoft.TimeSeriesInsights/environments/privateEndpointConnections,null,No
-no,Microsoft.TimeSeriesInsights/operations,null,No
-no,Microsoft.UsageBilling/operations,null,No
-no,Microsoft.VideoIndexer/operations,null,No
-no,Microsoft.VideoIndexer/locations,null,No
-no,Microsoft.VideoIndexer/locations/operationstatuses,null,No
-yes,Microsoft.VideoIndexer/accounts,Video Indexer accounts,No
-no,Microsoft.VideoIndexer/checknameavailability,null,No
-no,Microsoft.VideoIndexer/locations/userclassicaccounts,null,No
-no,Microsoft.VideoIndexer/locations/classicaccounts,null,No
-yes,Microsoft.VirtualMachineImages/imageTemplates,Image Templates,Yes
-no,Microsoft.VirtualMachineImages/imageTemplates/runOutputs,null,No
-no,Microsoft.VirtualMachineImages/imageTemplates/triggers,null,No
-no,Microsoft.VirtualMachineImages/locations,null,No
-no,Microsoft.VirtualMachineImages/locations/operations,null,No
-no,Microsoft.VirtualMachineImages/operations,null,No
-no,microsoft.visualstudio/account,null,No
-no,microsoft.visualstudio/operations,null,No
-no,microsoft.visualstudio/account/project,null,No
-no,microsoft.visualstudio/account/extension,null,No
-no,microsoft.visualstudio/checkNameAvailability,null,No
-no,Microsoft.VMware/Locations,null,No
-no,Microsoft.VMware/Locations/OperationStatuses,null,No
-no,Microsoft.VMware/Operations,null,No
-no,Microsoft.VMware/VCenters/InventoryItems,null,No
-no,Microsoft.VoiceServices/Operations,null,No
-no,Microsoft.VoiceServices/locations,null,No
-no,Microsoft.VoiceServices/locations/checkNameAvailability,null,No
-no,Microsoft.VoiceServices/registeredSubscriptions,null,No
-no,Microsoft.VSOnline/accounts,null,No
-no,Microsoft.VSOnline/plans,null,No
-no,Microsoft.VSOnline/operations,null,No
-no,Microsoft.VSOnline/registeredSubscriptions,null,No
-no,Microsoft.WindowsPushNotificationServices/checkNameAvailability,null,No
-no,Microsoft.WorkloadBuilder/Locations,null,No
-no,Microsoft.WorkloadBuilder/Locations/OperationStatuses,null,No
-no,Microsoft.WorkloadBuilder/Operations,null,No
-no,Microsoft.Workloads/Locations,null,No
-no,Microsoft.Workloads/Locations/OperationStatuses,null,No
-no,Microsoft.Workloads/sapVirtualInstances,null,No
-yes,Microsoft.Workloads/sapVirtualInstances/applicationInstances,App Server Instance,Yes
-yes,Microsoft.Workloads/sapVirtualInstances/centralInstances,Central Server Instance,Yes
-yes,Microsoft.Workloads/sapVirtualInstances/databaseInstances,Database Instance,Yes
-no,Microsoft.Workloads/Operations,null,No
-yes,Microsoft.Workloads/monitors,Workload Monitors,Yes
-no,Microsoft.Workloads/monitors/providerInstances,null,No
-no,Microsoft.Workloads/Locations/sapVirtualInstanceMetadata,null,No
-no,Microsoft.Workloads/connectors,null,No
-no,Microsoft.Workloads/connectors/acssBackups,null,No
-no,Microsoft.Workloads/monitors/sapLandscapeMonitor,null,No
-no,NewRelic.Observability/operations,null,No
-no,NewRelic.Observability/registeredSubscriptions,null,No
-no,NewRelic.Observability/locations,null,No
-no,NewRelic.Observability/locations/operationStatuses,null,No
-no,NewRelic.Observability/monitors,null,No
-no,NewRelic.Observability/monitors/tagRules,null,No
-no,NewRelic.Observability/checkNameAvailability,null,No
-no,NewRelic.Observability/accounts,null,No
-no,NewRelic.Observability/plans,null,No
-no,NewRelic.Observability/organizations,null,No
-no,NewRelic.Observability/monitors/monitoredSubscriptions,null,No
-no,NGINX.NGINXPLUS/operations,null,No
-no,NGINX.NGINXPLUS/locations,null,No
-no,NGINX.NGINXPLUS/locations/operationStatuses,null,No
-no,NGINX.NGINXPLUS/nginxDeployments/configurations,null,No
-no,NGINX.NGINXPLUS/nginxDeployments,null,No
-no,NGINX.NGINXPLUS/nginxDeployments/certificates,null,No
-no,Oracle.Database/Locations,null,No
-no,Oracle.Database/Locations/OperationStatuses,null,No
-no,Oracle.Database/Operations,null,No
-no,Oracle.Database/cloudExadataInfrastructures,null,No
-no,Oracle.Database/cloudVmClusters,null,No
-no,Oracle.Database/cloudVmClusters/dbNodes,null,No
-no,Oracle.Database/cloudVmClusters/virtualNetworkAddresses,null,No
-no,Oracle.Database/oracleSubscriptions,null,No
-no,Oracle.Database/Locations/giVersions,null,No
-no,Oracle.Database/Locations/dbSystemShapes,null,No
-no,Oracle.Database/cloudExadataInfrastructures/dbServers,null,No
-no,Oracle.Database/Locations/dnsPrivateViews,null,No
-no,Oracle.Database/Locations/dnsPrivateZones,null,No
-no,Oracle.Database/autonomousDatabases,null,No
-no,Oracle.Database/Locations/autonomousDatabaseCharacterSets,null,No
-no,Oracle.Database/Locations/autonomousDatabaseNationalCharacterSets,null,No
-no,Oracle.Database/Locations/autonomousDbVersions,null,No
-no,PaloAltoNetworks.Cloudngfw/operations,null,No
-no,PaloAltoNetworks.Cloudngfw/locations,null,No
-no,PaloAltoNetworks.Cloudngfw/registeredSubscriptions,null,No
-no,PaloAltoNetworks.Cloudngfw/checkNameAvailability,null,No
-no,PaloAltoNetworks.Cloudngfw/Locations/operationStatuses,null,No
-no,PaloAltoNetworks.Cloudngfw/firewalls,null,No
-no,PaloAltoNetworks.Cloudngfw/localRulestacks,null,No
-no,PaloAltoNetworks.Cloudngfw/globalRulestacks,null,No
-no,PaloAltoNetworks.Cloudngfw/localRulestacks/localRules,null,No
-no,PaloAltoNetworks.Cloudngfw/localRulestacks/fqdnlists,null,No
-no,PaloAltoNetworks.Cloudngfw/globalRulestacks/fqdnlists,null,No
-no,PaloAltoNetworks.Cloudngfw/globalRulestacks/preRules,null,No
-no,PaloAltoNetworks.Cloudngfw/globalRulestacks/postRules,null,No
-no,PaloAltoNetworks.Cloudngfw/globalRulestacks/prefixlists,null,No
-no,PaloAltoNetworks.Cloudngfw/localRulestacks/prefixlists,null,No
-no,PaloAltoNetworks.Cloudngfw/globalRulestacks/certificates,null,No
-no,PaloAltoNetworks.Cloudngfw/localRulestacks/certificates,null,No
-no,PaloAltoNetworks.Cloudngfw/firewalls/statuses,null,No
-no,Qumulo.Storage/registeredSubscriptions,null,No
-no,Qumulo.Storage/locations,null,No
-no,Qumulo.Storage/locations/operationStatuses,null,No
-no,Qumulo.Storage/checkNameAvailability,null,No
-no,Qumulo.Storage/operations,null,No
-no,Qumulo.Storage/fileSystems,null,No
-no,SolarWinds.Observability/operations,null,No
-no,SolarWinds.Observability/registeredSubscriptions,null,No
-no,SolarWinds.Observability/locations,null,No
-no,SolarWinds.Observability/locations/operationStatuses,null,No
-no,SolarWinds.Observability/checkNameAvailability,null,No
-no,SplitIO.Experimentation/operations,null,No
-no,SplitIO.Experimentation/locations,null,No
-no,SplitIO.Experimentation/locations/operationStatuses,null,No
-no,SplitIO.Experimentation/checkNameAvailability,null,No
-no,Wandisco.Fusion/Locations,null,No
-no,Wandisco.Fusion/Locations/operationStatuses,null,No
-no,Wandisco.Fusion/registeredSubscriptions,null,No
-no,Wandisco.Fusion/Operations,null,No
-no,Wandisco.Fusion/migrators,null,No
-no,Wandisco.Fusion/migrators/targets,null,No
-no,Wandisco.Fusion/migrators/liveDataMigrations,null,No
-no,Wandisco.Fusion/migrators/exclusionTemplates,null,No
-no,Wandisco.Fusion/migrators/metadataMigrations,null,No
-no,Wandisco.Fusion/migrators/metadataTargets,null,No
-no,Wandisco.Fusion/migrators/pathMappings,null,No
-no,Wandisco.Fusion/migrators/dataTransferAgents,null,No
-no,Wandisco.Fusion/migrators/verifications,null,No
-no,Oracle.Database,null,No
-yes,Microsoft.Network/expressRouteCrossConnections,ExpressRoute Cross Connections,No
-yes,Specialized.Workload/AVD,Specialized-AVD,Yes
-yes,Specialized.Workload/AVS,Specialized-AVS,Yes
-yes,Specialized.Workload/HPC,Specialized-HPC,Yes
-yes,Specialized.Workload/SAP,Specialized-SAP,Yes
-no,WellArchitected/Define,WellArchitected/Define,No
-no,WellArchitected/Deploy,WellArchitected/Deploy,No
-no,WellArchitected/Design,WellArchitected/Design,No
-no,WellArchitected/Respond,WellArchitected/Respond,No
-no,WellArchitected/Test,WellArchitected/Test,No
-no,WellArchitected/Monitor,WellArchitected/Monitor,No
-no,WellArchitected/Reliability,WellArchitected/Reliability,No
-no,WellArchitected/OperationalExcellence,WellArchitected/OperationalExcellence,No
-no,WellArchitected/Performance,WellArchitected/Performance,No
-no,WellArchitected/Security,WellArchitected/Security,No
diff --git a/tools/configfile.example b/tools/configfile.example
deleted file mode 100644
index b73f7a33d..000000000
--- a/tools/configfile.example
+++ /dev/null
@@ -1,12 +0,0 @@
-[tenantId]
-tenantid
-
-[subscriptionIds]
-/subscriptions/
-
-[resourcegroups]
-/subscriptions//resourceGroups/Demo1-RG
-
-[tags]
-env=~prod
-application=~demoapp1
diff --git a/tools/data/recommendations.json b/tools/data/recommendations.json
deleted file mode 100644
index d567bafc3..000000000
--- a/tools/data/recommendations.json
+++ /dev/null
@@ -1,9452 +0,0 @@
-[
- {
- "aprlGuid": "bb6deb9d-24fa-4ee8-bc23-ac3ebc7fdf8e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/entra/identity/domain-services/tutorial-create-replica-set",
- "name": "Create and use replica sets for resiliency or geolocation in Microsoft Entra Domain Services"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "You need to use a minimum of Enterprise SKU for your managed domain to support replica sets.\n",
- "pgVerified": false,
- "description": "Use at least the Enterprise SKU",
- "potentialBenefits": "The Enterprise SKU enables creation of replica sets.",
- "tags": null,
- "recommendationResourceType": "Microsoft.AAD/domainServices",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Gets Entry Domain Services that are using the Standard SKU\r\nresources\r\n| where type == \"microsoft.aad/domainservices\"\r\n| extend sku = properties.sku\r\n| where sku =~ 'Standard'\r\n| project recommendationId='bb6deb9d-24fa-4ee8-bc23-ac3ebc7fdf8e', name=name, id=id, tags=tags, param1=strcat('SKU:', sku)\r\n"
- },
- {
- "aprlGuid": "a3058909-fcf8-4450-88b5-499f57449178",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/entra/identity/domain-services/tutorial-create-replica-set",
- "name": "Create and use replica sets for resiliency or geolocation in Microsoft Entra Domain Services"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "To improve the resiliency of a Microsoft Entra Domain Services managed domain, or deploy to additional geographic locations close to your applications, you can use replica sets.\nYou can add a replica set to any peered virtual network in any Azure region that supports Domain Services.\n",
- "pgVerified": false,
- "description": "Use replica sets for resiliency or geolocation in Microsoft Entra Domain Services",
- "potentialBenefits": "The replica sets provide geographical resiliency.",
- "tags": null,
- "recommendationResourceType": "Microsoft.AAD/domainServices",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Gets Entry Domain Services that are using only one replicaSet\r\nresources\r\n| where type == \"microsoft.aad/domainservices\"\r\n| extend replicaSets = properties.replicaSets\r\n| where array_length(replicaSets) < 2\r\n| project recommendationId='a3058909-fcf8-4450-88b5-499f57449178', name=name, id=id, tags=tags, param1=strcat('replicaSetLocation:', replicaSets[0].location)\r\n"
- },
- {
- "aprlGuid": "baf3bfc0-32a2-4c0c-926d-c9bf0b49808e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/api-management/upgrade-and-scale#change-your-api-management-service-tier",
- "name": "Change your API Management service tier"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Upgrading the API Management instance to the Premium SKU adds support for Availability Zones, enhancing availability and resilience by distributing services across physically separate locations within Azure regions.\n",
- "pgVerified": true,
- "description": "Migrate API Management services to Premium SKU to support Availability Zones",
- "potentialBenefits": "Enhanced availability and resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.ApiManagement/service",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all API Management instances that aren't Premium\r\nresources\r\n| where type =~ 'Microsoft.ApiManagement/service'\r\n| extend skuName = sku.name\r\n| where tolower(skuName) != tolower('premium')\r\n| project recommendationId = \"baf3bfc0-32a2-4c0c-926d-c9bf0b49808e\", name, id, tags, param1=strcat(\"SKU: \", skuName)\r\n"
- },
- {
- "aprlGuid": "740f2c1c-8857-4648-80eb-47d2c56d5a50",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/api-management/high-availability#availability-zones",
- "name": "Ensure API Management availability and reliability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Zone redundancy for APIM instances ensures the gateway and control plane (Management API, developer portal, Git configuration) are replicated across datacenters in physically separated zones, boosting resilience to zone failures.\n",
- "pgVerified": true,
- "description": "Enable Availability Zones on Premium API Management instances",
- "potentialBenefits": "Improved resilience to zone failures",
- "tags": null,
- "recommendationResourceType": "Microsoft.ApiManagement/service",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Premium API Management instances that aren't zone redundant\r\nresources\r\n| where type =~ 'Microsoft.ApiManagement/service'\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| extend skuName = sku.name\r\n| where tolower(skuName) == tolower('premium')\r\n| where isnull(zones) or array_length(zones) < 2\r\n| extend zoneValue = iff((isnull(zones)), \"null\", zones)\r\n| project recommendationId = \"740f2c1c-8857-4648-80eb-47d2c56d5a50\", name, id, tags, param1=\"Zones: No Zone or Zonal\", param2=strcat(\"Zones value: \", zoneValue )\r\n\r\n"
- },
- {
- "aprlGuid": "e35cf148-8eee-49d1-a1c9-956160f99e0b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/api-management/breaking-changes/stv1-platform-retirement-august-2024",
- "name": "Azure API Management - stv1 platform retirement (August 2024)"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "stv1 instances were deprecated on August 31, 2024. If not migrated to stv2 by then, auto-migration will occur. In some cases, due to technical limitations, services may be shut down in March 2025.\n",
- "pgVerified": true,
- "description": "Azure API Management platform version should be stv2",
- "potentialBenefits": "Ensures service continuity",
- "tags": null,
- "recommendationResourceType": "Microsoft.ApiManagement/service",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all API Management instances that aren't upgraded to platform version stv2\r\nresources\r\n| where type =~ 'Microsoft.ApiManagement/service'\r\n| extend plat_version = properties.platformVersion\r\n| extend skuName = sku.name\r\n| where tolower(plat_version) != tolower('stv2')\r\n| project recommendationId = \"e35cf148-8eee-49d1-a1c9-956160f99e0b\", name, id, tags, param1=strcat(\"Platform Version: \", plat_version) , param2=strcat(\"SKU: \", skuName)\r\n\r\n"
- },
- {
- "aprlGuid": "c79680ea-de85-44fa-a596-f31fa17a952f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/api-management/api-management-howto-autoscale",
- "name": "Setting up auto-scale for Azure API Management"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use API Management with auto-scale for high availability in workloads that experience variable traffic patterns. There are several limitations with auto-scale, so review the documentation to ensure it meets your requirements.\n",
- "pgVerified": true,
- "description": "Enable auto-scale for production workloads on API Management services",
- "potentialBenefits": "Enhanced availability and resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.ApiManagement/service",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "af4f88cb-35e8-4371-b29e-3a32b1d2f40a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-deploy-multi-region",
- "name": "Deploy API Management instance to multiple Azure regions"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "API Management multi-region deployment will help to reduce request latency perceived by geographically distributed API consumers and improves service availability if one region goes offline.\n",
- "pgVerified": true,
- "description": "Configure API management service in multiple Azure regions",
- "potentialBenefits": "Improve latency and provides business continuity",
- "tags": null,
- "recommendationResourceType": "Microsoft.ApiManagement/service",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "badd9a1f-222a-498d-ab84-1f14892b1c1b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/api-management/api-management-howto-cache",
- "name": "Add caching to improve performance in Azure API Management"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Response caching can significantly reduce latency for API callers and backend load for API providers.\n",
- "pgVerified": false,
- "description": "Enable caching to improve performance in Azure API Management",
- "potentialBenefits": "Ensures service continuity and high availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.ApiManagement/service",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "8dbcd94b-0948-4df3-b608-1946726c3abf",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/container-apps/health-probes?tabs=arm-template",
- "name": "Health probes for Azure Container Apps"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Enable container health probes to monitor the health of your container apps and ensure that unhealthy containers are restarted automatically.\n",
- "pgVerified": false,
- "description": "Enable container health probes",
- "potentialBenefits": "Enhanced availability and resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.App/containerApps",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "f4201965-a88d-449d-b3b4-021394719eb2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/reliability/reliability-azure-container-apps",
- "name": "Reliability in Azure Container Apps"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "To take advantage of availability zones, you must enable zone redundancy when you create a Container Apps environment. The environment must include a virtual network with an available subnet. To ensure proper distribution of replicas, set your app's minimum replica count to three.\n",
- "pgVerified": false,
- "description": "Deploy zone redundant Container app environments",
- "potentialBenefits": "Enhances app resiliency and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.App/managedenvironments",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// The query filters the qualified Container app environments that do not have Zone Redundancy enabled.\r\nresources\r\n| where type =~ \"microsoft.app/managedenvironments\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where tobool(properties.zoneRedundant) == false\r\n| project recommendationId = \"f4201965-a88d-449d-b3b4-021394719eb2\", name, id, tags, param1 = \"AvailabilityZones: Single Zone\"\r\n| order by id asc\r\n"
- },
- {
- "aprlGuid": "bb4c8db4-f821-475b-b1ea-16e95358665e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-app-configuration/concept-soft-delete#purge-protection",
- "name": "Purge protection"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "With Purge protection enabled, soft deleted stores can't be purged in the retention period. If disabled, the soft deleted store can be purged before the retention period expires.\n",
- "pgVerified": false,
- "description": "Enable Purge protection for Azure App Configuration",
- "potentialBenefits": "Prevent accidental deletion of configuration stores.",
- "tags": null,
- "recommendationResourceType": "Microsoft.AppConfiguration/configurationStores",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Purge protection should be enabled for App Configuration stores to prevent accidental deletion of configuration data.\r\nresources\r\n| where type =~ \"Microsoft.AppConfiguration/configurationStores\"\r\n| where sku.name <> \"free\"\r\n| where (properties.enablePurgeProtection <> true) or isnull(properties.enablePurgeProtection )\r\n| project recommendationId = \"bb4c8db4-f821-475b-b1ea-16e95358665e\", name, id, tags, param1 = \"Enable purge protection\"\r\n"
- },
- {
- "aprlGuid": "2102a57a-a056-4d5e-afe5-9df9f92177ca",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-app-configuration/faq#which-app-configuration-tier-should-i-use",
- "name": "Choose App Configuration tier"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "SLA is not available for Free tier. Upgrade to the Standard tier to get an SLA of 99.9%\n",
- "pgVerified": false,
- "description": "Upgrade to App Configuration Standard tier",
- "potentialBenefits": "High availability, more storage, higher request quota.",
- "tags": null,
- "recommendationResourceType": "Microsoft.AppConfiguration/configurationStores",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Upgrade to App Configuration Standard tier\r\nresources\r\n| where type =~ \"Microsoft.AppConfiguration/configurationStores\"\r\n| where sku.name == \"free\"\r\n| project recommendationId = \"2102a57a-a056-4d5e-afe5-9df9f92177ca\", name, id, tags, param1 = \"Upgrade to Standard SKU\"\r\n"
- },
- {
- "aprlGuid": "67205887-0733-466e-b50e-b1cd7316c514",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/automation/automation-disaster-recovery?tabs=win-hrw%2Cps-script%2Coption-one",
- "name": "Disaster recovery for Automation accounts"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Set up disaster recovery for Automation accounts and resources like Modules, Connections, Credentials, Certificates, Variables, and Schedules to deal with region or zone failures. A replica Automation account should be ready in a secondary region for failover.\n",
- "pgVerified": false,
- "description": "Set up disaster recovery of Automation accounts and its dependent resources",
- "potentialBenefits": "Ensures continuity during outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Automation/automationAccounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "74fcb9f2-9a25-49a6-8c42-d32851c4afb7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/scenarios/azure-vmware/eslz-management-and-monitoring#design-recommendations",
- "name": "Configure Azure Service Health alerts"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Ensure Azure Service Health notifications are set for Azure VMware Solution across all used regions and subscriptions. This communicates service/security issues and maintenance activities like host replacements and upgrades, reducing service request submissions.\n",
- "pgVerified": true,
- "description": "Configure Azure Service Health notifications and alerts for Azure VMware Solution",
- "potentialBenefits": "Prompt mitigation of issues.",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure VMware Solution resources that don't have one or more service health alerts covering AVS private clouds in the deployed subscription and region pairs.\r\n//full list of private clouds\r\n(resources\r\n| where ['type'] == \"microsoft.avs/privateclouds\"\r\n| extend locale = tolower(location)\r\n| extend subscriptionId = tolower(subscriptionId)\r\n| project id, name, tags, subscriptionId, locale)\r\n| join kind=leftouter\r\n//Alert ID's that include all incident types filtered by AVS Service Health alerts\r\n((resources\r\n| where type == \"microsoft.insights/activitylogalerts\"\r\n| extend alertproperties = todynamic(properties)\r\n| where alertproperties.condition.allOf[0].field == \"category\" and alertproperties.condition.allOf[0].equals == \"ServiceHealth\"\r\n| where alertproperties.condition.allOf[1].field == \"properties.impactedServices[*].ServiceName\" and set_has_element(alertproperties.condition.allOf[1].containsAny, \"Azure VMware Solution\")\r\n| extend locale = strcat_array(split(tolower(alertproperties.condition.allOf[2].containsAny),' '), '')\r\n| mv-expand todynamic(locale)\r\n| where locale != \"global\"\r\n| project subscriptionId, tostring(locale) )\r\n| union\r\n//Alert ID's that include only some of the incident types after filtering by service health alerts covering AVS private clouds.\r\n(resources\r\n| where type == \"microsoft.insights/activitylogalerts\"\r\n| extend subscriptionId = tolower(subscriptionId)\r\n| extend alertproperties = todynamic(properties)\r\n| where alertproperties.condition.allOf[0].field == \"category\" and alertproperties.condition.allOf[0].equals == \"ServiceHealth\"\r\n| where alertproperties.condition.allOf[2].field == \"properties.impactedServices[*].ServiceName\" and set_has_element(alertproperties.condition.allOf[2].containsAny, \"Azure VMware Solution\")\r\n| extend locale = strcat_array(split(tolower(alertproperties.condition.allOf[3].containsAny),' '), '')\r\n| mv-expand todynamic(locale)\r\n| mv-expand alertproperties.condition.allOf[1].anyOf\r\n| extend incidentType = alertproperties_condition_allOf_1_anyOf.equals\r\n| where locale != \"global\"\r\n| project id, subscriptionId, locale, incidentType\r\n| distinct subscriptionId, tostring(locale), tostring(incidentType)\r\n| summarize incidentTypes=count() by subscriptionId, locale\r\n| where incidentTypes == 5 //only include this subscription, region pair if it includes all the incident types.\r\n| project subscriptionId, locale)) on subscriptionId, locale\r\n| where subscriptionId1 == \"\" or locale1 == \"\" or isnull(subscriptionId1) or isnull(locale1)\r\n| project recommendationId = \"74fcb9f2-9a25-49a6-8c42-d32851c4afb7\", name, id, tags, param1 = \"avsServiceHealthAlertsAllIncidentTypesConfigured: False\"\r\n\r\n"
- },
- {
- "aprlGuid": "29d7a115-dfb6-4df1-9205-04824109548f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/azure-vmware/monitoring#configure-and-streamline-alerts",
- "name": "Configure and streamline alerts"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Set an alert for when the node count in Azure VMware Solution Private Cloud hits or exceeds 90 hosts, enabling timely planning for a new private cloud.\n",
- "pgVerified": true,
- "description": "Monitor when Azure VMware Solution Private Cloud is reaching the capacity limit",
- "potentialBenefits": "Proactive capacity planning",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "f86355e3-de7c-4dad-8080-1b0b411e66c8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/azure-vmware/monitoring#configure-and-streamline-alerts",
- "name": "Configure and streamline alerts"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Alert when the cluster size reaches 14 hosts. Set up periodic alerts for planning new clusters or datastores due to growth, especially from storage needs. Beyond 14 hosts, trigger alerts for each new host addition for proactive resource monitoring.\n",
- "pgVerified": true,
- "description": "Monitor when Azure VMware Solution Cluster Size is approaching the host limit",
- "potentialBenefits": "Proactive resource management",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "9ec5b4c8-3dd8-473a-86ee-3273290331b9",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/deploy-vsan-stretched-clusters",
- "name": "Stretched Clusters"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For Azure VMware Solution, enabling Stretched Clusters offers 99.99% SLA, synchronous storage replication (RPO=0), and spreads vSAN datastore across two AZs. Must be done at initial setup, needing double quota due to extension across AZs.\n",
- "pgVerified": true,
- "description": "Enable Stretched Clusters for Multi-AZ Availability of the vSAN Datastore",
- "potentialBenefits": "99.99% SLA, 0 RPO, Multi-AZ",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure VMware Solution resources that aren't configured as stretched clusters and in supported regions.\r\nresources\r\n| where ['type'] == \"microsoft.avs/privateclouds\"\r\n| extend avsproperties = todynamic(properties)\r\n| where avsproperties.availability.strategy != \"DualZone\"\r\n| where location in (\"uksouth\", \"westeurope\", \"germanywestcentral\", \"australiaeast\")\r\n| project recommendationId = \"9ec5b4c8-3dd8-473a-86ee-3273290331b9\", name, id, tags, param1 = \"stretchClusters: Disabled\"\r\n\r\n"
- },
- {
- "aprlGuid": "4232eb32-3241-4049-9e14-9b8005817b56",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/configure-alerts-for-azure-vmware-solution#supported-metrics-and-activities",
- "name": "Supported metrics and activities"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Ensure VMware vSAN datastore slack space is maintained for SLA by monitoring storage utilization and setting alerts at 70% and 75% utilization to allow for capacity planning. To expand, add hosts or external storage like Azure Elastic SAN, Azure NetApp Files, if CPU and RAM requirements are met.\n",
- "pgVerified": true,
- "description": "Configure Azure Monitor Alert warning thresholds for vSAN datastore utilization",
- "potentialBenefits": "Optimized capacity planning for vSAN",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure VMware Solution resources that don't have a vSAN capacity critical alert with a threshold of 75% or a warning capacity of 70%.\r\n(\r\nresources\r\n| where ['type'] == \"microsoft.avs/privateclouds\"\r\n| extend scopeId = tolower(tostring(id))\r\n| project ['scopeId'], name, id, tags\r\n| join kind=leftouter (\r\nresources\r\n| where type == \"microsoft.insights/metricalerts\"\r\n| extend alertProperties = todynamic(properties)\r\n| mv-expand alertProperties.scopes\r\n| mv-expand alertProperties.criteria.allOf\r\n| extend scopeId = tolower(tostring(alertProperties_scopes))\r\n| extend metric = alertProperties_criteria_allOf.metricName\r\n| extend threshold = alertProperties_criteria_allOf.threshold\r\n| project scopeId, tostring(metric), toint(['threshold'])\r\n| where metric == \"DiskUsedPercentage\"\r\n| where threshold == 75\r\n) on scopeId\r\n| where isnull(['threshold'])\r\n| project recommendationId = \"4232eb32-3241-4049-9e14-9b8005817b56\", name, id, tags, param1 = \"vsanCapacityCriticalAlert: isNull or threshold != 75\"\r\n)\r\n| union (\r\nresources\r\n| where ['type'] == \"microsoft.avs/privateclouds\"\r\n| extend scopeId = tolower(tostring(id))\r\n| project ['scopeId'], name, id, tags\r\n| join kind=leftouter (\r\nresources\r\n| where type == \"microsoft.insights/metricalerts\"\r\n| extend alertProperties = todynamic(properties)\r\n| mv-expand alertProperties.scopes\r\n| mv-expand alertProperties.criteria.allOf\r\n| extend scopeId = tolower(tostring(alertProperties_scopes))\r\n| extend metric = alertProperties_criteria_allOf.metricName\r\n| extend threshold = alertProperties_criteria_allOf.threshold\r\n| project scopeId, tostring(metric), toint(['threshold'])\r\n| where metric == \"DiskUsedPercentage\"\r\n| where threshold == 70\r\n) on scopeId\r\n| where isnull(['threshold'])\r\n| project recommendationId = \"4232eb32-3241-4049-9e14-9b8005817b56\", name, id, tags, param1 = \"vsanCapacityWarningAlert: isNull or threshold != 70\"\r\n)\r\n\r\n"
- },
- {
- "aprlGuid": "fa4ab927-bced-429a-971a-53350de7f14b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/azure-vmware/monitoring#manage-logs-and-archives",
- "name": "Manage logs and archives"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Ensure Diagnostic Settings are configured for each private cloud to send syslogs to external sources for analysis and/or archiving. Azure VMware Solution Syslogs contain data for troubleshooting and performance, aiding quicker issue resolution and early detection of issues.\n",
- "pgVerified": true,
- "description": "Configure Syslog in Diagnostic Settings for Azure VMware Solution",
- "potentialBenefits": "Faster issue resolution, early detection",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "4ee5d535-c47b-470a-9557-4a3dd297d62f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/azure-vmware/monitoring#configure-and-streamline-alerts",
- "name": "Configure and streamline alerts"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Ensure sufficient compute resources to avoid host resource exhaustion in Azure VMware Solution, which utilizes vSphere DRS and HA for dynamic workload resource management. However, sustained CPU utilization over 95% may increase CPU Ready times, impacting workloads.\n",
- "pgVerified": true,
- "description": "Monitor CPU Utilization to ensure sufficient resources for workloads",
- "potentialBenefits": "Avoids resource exhaustion, optimizes performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure VMware Solution resources that don't have a Cluster CPU capacity critical alert with a threshold of 95%.\r\nresources\r\n| where ['type'] == \"microsoft.avs/privateclouds\"\r\n| extend scopeId = tolower(tostring(id))\r\n| project ['scopeId'], name, id, tags\r\n| join kind=leftouter (\r\nresources\r\n| where type == \"microsoft.insights/metricalerts\"\r\n| extend alertProperties = todynamic(properties)\r\n| mv-expand alertProperties.scopes\r\n| mv-expand alertProperties.criteria.allOf\r\n| extend scopeId = tolower(tostring(alertProperties_scopes))\r\n| extend metric = alertProperties_criteria_allOf.metricName\r\n| extend threshold = alertProperties_criteria_allOf.threshold\r\n| project scopeId, tostring(metric), toint(['threshold'])\r\n| where metric == \"EffectiveCpuAverage\"\r\n| where threshold == 95\r\n) on scopeId\r\n| where isnull(['threshold'])\r\n| project recommendationId = \"4ee5d535-c47b-470a-9557-4a3dd297d62f\", name, id, tags, param1 = \"hostCpuCriticalAlert: isNull or threshold != 95\"\r\n\r\n"
- },
- {
- "aprlGuid": "029208c8-5186-4a76-8ee8-6e3445fef4dd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/azure-vmware/monitoring#configure-and-streamline-alerts",
- "name": "Configure and streamline alerts"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Ensure sufficient memory resources to prevent host resource exhaustion in Azure VMware Solution. It uses vSphere DRS and vSphere HA for dynamic workload management. Yet, continuous memory use over 95% leads to disk swapping, affecting workloads.\n",
- "pgVerified": true,
- "description": "Monitor Memory Utilization to ensure sufficient resources for workloads",
- "potentialBenefits": "Avoids host exhaustion and swapping",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure VMware Solution resources that don't have a cluster host memory critical alert with a threshold of 95%.\r\nresources\r\n| where ['type'] == \"microsoft.avs/privateclouds\"\r\n| extend scopeId = tolower(tostring(id))\r\n| project ['scopeId'], name, id, tags\r\n| join kind=leftouter (\r\nresources\r\n| where type == \"microsoft.insights/metricalerts\"\r\n| extend alertProperties = todynamic(properties)\r\n| mv-expand alertProperties.scopes\r\n| mv-expand alertProperties.criteria.allOf\r\n| extend scopeId = tolower(tostring(alertProperties_scopes))\r\n| extend metric = alertProperties_criteria_allOf.metricName\r\n| extend threshold = alertProperties_criteria_allOf.threshold\r\n| project scopeId, tostring(metric), toint(['threshold'])\r\n| where metric == \"UsageAverage\"\r\n| where threshold == 95\r\n) on scopeId\r\n| where isnull(['threshold'])\r\n| project recommendationId = \"029208c8-5186-4a76-8ee8-6e3445fef4dd\", name, id, tags, param1 = \"hostMemoryCriticalAlert: isNull or threshold != 95\"\r\n\r\n"
- },
- {
- "aprlGuid": "a5ef7c05-c611-4842-9af5-11efdc99123a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/lock-resources",
- "name": "Lock your resources to protect your infrastructure"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Applying a resource delete lock to the Azure VMware Solution Private Cloud resource group prevents unauthorized or accidental deletion by anyone with contributor access, ensuring the protection and reliability of the Azure VMware Solution Private Cloud.\n",
- "pgVerified": true,
- "description": "Apply Resource delete lock on the resource group hosting the private cloud",
- "potentialBenefits": "Prevents accidental deletion",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "e0ac2f57-c8c0-4b8c-a7c8-19e5797828b5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/configure-customer-managed-keys?tabs=azure-portal",
- "name": "Configure Customer Managed Keys"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "When using customer-managed keys for encrypting vSAN datastores, leveraging Azure Key Vault for central management and accessing them via a managed identity linked to the private cloud is advised. The expiration of these keys can render the vSAN datastore and its associated workloads inaccessible.\n",
- "pgVerified": true,
- "description": "Use key autorotation for vSAN datastore customer-managed keys",
- "potentialBenefits": "Avoid outages with key auto-rotation",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "fcc2e257-23af-4c68-aac8-9cc03033c939",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/configure-dns-azure-vmware-solution#configure-dns-forwarder",
- "name": "Configure DNS forwarder"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure VMware Solution private clouds support up to three DNS servers for a single FQDN, preventing a single DNS server from becoming a point of failure. It's crucial to use multiple DNS servers for on-premises FQDN resolution from each private cloud.\n",
- "pgVerified": true,
- "description": "Use multiple DNS servers per private FQDN zone",
- "potentialBenefits": "Enhances reliability and avoids failure",
- "tags": null,
- "recommendationResourceType": "Microsoft.AVS/privateClouds",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "3464854d-6f75-4922-95e4-a2a308b53ce6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/reliability/reliability-batch#cross-region-disaster-recovery-and-business-continuity",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "To ensure cross-region disaster recovery and business continuity, set the right quotas for all Batch accounts to allocate necessary core numbers upfront, preventing execution interruptions from reaching quota limits.\n",
- "pgVerified": false,
- "description": "Monitor Batch Account quota",
- "potentialBenefits": "Ensures business continuity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Batch/batchAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "71cfab8f-d588-4742-b175-b6e07ae48dbd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/batch/create-pool-availability-zones",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "When using Virtual Machine Configuration for Azure Batch pools, opting to distribute your pool across Availability Zones bolsters your compute nodes against Azure datacenter failures.\n",
- "pgVerified": false,
- "description": "Create an Azure Batch pool across Availability Zones",
- "potentialBenefits": "Enhanced reliability and failure protection",
- "tags": null,
- "recommendationResourceType": "Microsoft.Batch/batchAccounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "5a44bd30-ae6a-4b81-9b68-dc3a8ffca4d8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-cache-for-redis/cache-how-to-zone-redundancy",
- "name": "Enable zone redundancy for Azure Cache for Redis"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Cache for Redis offers zone redundancy in Premium and Enterprise tiers, using VMs across multiple Availability Zones to ensure greater resilience and availability.\n",
- "pgVerified": false,
- "description": "Enable zone redundancy for Azure Cache for Redis",
- "potentialBenefits": "Higher resilience and availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cache/Redis",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Cache for Redis instances with one or no Zones selected\r\nresources\r\n| where type =~ \"microsoft.cache/redis\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where array_length(zones) <= 1 or isnull(zones)\r\n| project recommendationId = \"5a44bd30-ae6a-4b81-9b68-dc3a8ffca4d8\", name, id, tags, param1 = \"AvailabilityZones: Single Zone\"\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "cabc1f98-c8a7-44f7-ab24-977982ef3f70",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-administration#update-channel-and-schedule-updates",
- "name": "Schedule Redis Updates"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Cache for Redis allows for specifying maintenance windows. A maintenance window allows you to control the days and times of a week during which the VMs hosting your cache can be updated.\n",
- "pgVerified": false,
- "description": "Schedule updates by setting a maintenance window",
- "potentialBenefits": "Higher resilience and availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cache/redis",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "c474fc96-4e6a-4fb0-95d0-a26b3f35933c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-cache-for-redis/cache-network-isolation",
- "name": "Configure private endpoints for Azure Redis Cache"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Use private endpoints for secure connection to cache via a private link, avoiding the public internet.\n",
- "pgVerified": false,
- "description": "Configure Private Endpoints",
- "potentialBenefits": "Secure, private VNet ingress, efficient data transfer",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cache/redis",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Azure Redis cache services not protected by private endpoints.\r\nResources\r\n| where type =~ \"microsoft.cache/redis\"\r\n| where properties['publicNetworkAccess'] == \"Enabled\"\r\n| project recommendationId = \"c474fc96-4e6a-4fb0-95d0-a26b3f35933c\", name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "6c40b7ae-2bea-5748-be1a-9e9e3b834649",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/origin-security?tabs=app-service-functions&pivots=front-door-standard-premium",
- "name": "Secure traffic to Azure Front Door origins"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Front Door's features perform optimally when traffic exclusively comes through Front Door. It's advised to set up your origin to deny access to traffic that bypasses Front Door.\n",
- "pgVerified": true,
- "description": "Restrict traffic to your origins",
- "potentialBenefits": "Enhances security and performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "52bc9a7b-23c8-bc4c-9d2a-7bc43b50104a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/rest/api/frontdoor/",
- "name": "REST API Reference"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "When working with Azure Front Door through APIs, ARM templates, Bicep, or SDKs, using the latest API or SDK version is crucial. Updates bring new functions, important security patches, and bug fixes.\n",
- "pgVerified": true,
- "description": "Use the latest API version and SDK version",
- "potentialBenefits": "Enhanced security and features",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1ad74c3c-e3d7-0046-b83f-a2199974ef15",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/front-door-diagnostics?pivots=front-door-standard-premium",
- "name": "Monitor metrics and logs in Azure Front Door"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Front Door logs offer comprehensive telemetry on each request, crucial for understanding your solution's performance and responses, especially when caching is enabled, as origin servers might not receive every request.\n",
- "pgVerified": true,
- "description": "Configure logs",
- "potentialBenefits": "Enhanced insights and solution monitoring",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "d9bd6780-0d6f-cd4c-bc66-8ddcab12f3d1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/end-to-end-tls?pivots=front-door-standard-premium",
- "name": "End-to-end TLS with Azure Front Door"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Front Door terminates TCP and TLS connections from clients and establishes new connections from each PoP to the origin. Securing these connections with TLS, even for Azure-hosted origins, ensures data is always encrypted during transit.\n",
- "pgVerified": true,
- "description": "Use end-to-end TLS",
- "potentialBenefits": "Ensures data encryption in transit",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Use end-to-end TLS\r\ncdnresources\r\n| where type == \"microsoft.cdn/profiles/afdendpoints/routes\"\r\n| extend forwardingProtocol=tostring(properties.forwardingProtocol),supportedProtocols=properties.supportedProtocols\r\n| project id,name,forwardingProtocol,supportedProtocols,tags\r\n| where forwardingProtocol !~ \"httpsonly\" or supportedProtocols has \"http\"\r\n| project recommendationId= \"d9bd6780-0d6f-cd4c-bc66-8ddcab12f3d1\", name,id,tags,param1=strcat(\"forwardingProtocol:\",forwardingProtocol),param2=strcat(\"supportedProtocols:\",supportedProtocols)\r\n\r\n"
- },
- {
- "aprlGuid": "24ab9f11-a3e4-3043-a985-22cf94c4933a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/front-door-how-to-redirect-https#create-http-to-https-redirect-rule",
- "name": "Create HTTP to HTTPS redirect rule"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Using HTTPS is ideal for secure connections. However, for compatibility with older clients, HTTP requests may be necessary. Azure Front Door enables auto redirection of HTTP to HTTPS, enhancing security without sacrificing accessibility.\n",
- "pgVerified": true,
- "description": "Use HTTP to HTTPS redirection",
- "potentialBenefits": "Enhances security and compliance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Use HTTP to HTTPS redirection\r\ncdnresources\r\n| where type == \"microsoft.cdn/profiles/afdendpoints/routes\"\r\n| extend httpsRedirect=tostring(properties.httpsRedirect)\r\n| project id,name,httpsRedirect,tags\r\n| where httpsRedirect !~ \"enabled\"\r\n| project recommendationId= \"24ab9f11-a3e4-3043-a985-22cf94c4933a\", name,id,tags,param1=strcat(\"httpsRedirect:\",httpsRedirect)\r\n\r\n"
- },
- {
- "aprlGuid": "29d65c41-2fad-d142-95eb-9eab95f6c0a5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/standard-premium/how-to-configure-https-custom-domain?tabs=powershell",
- "name": "Configure HTTPS on an Azure Front Door custom domain using the Azure portal"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "When Front Door manages your TLS certificates, it reduces your operational costs and helps you to avoid costly outages caused by forgetting to renew a certificate. Front Door automatically issues and rotates the managed TLS certificates.\n",
- "pgVerified": true,
- "description": "Use managed TLS certificates",
- "potentialBenefits": "Lowers costs, avoids outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "4638c2c0-03de-6d42-9e09-82ee4478cbf3",
- "recommendationTypeId": "2c057605-4707-4d3e-bbb0-a7fe9b6a626b",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/standard-premium/how-to-configure-https-custom-domain?tabs=powershell#select-the-certificate-for-azure-front-door-to-deploy",
- "name": "Select the certificate for Azure Front Door to deploy"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "If you use your own TLS certificates, set the Key Vault certificate version to 'Latest' to avoid reconfiguring Azure Front Door for new certificate versions and waiting for deployment across Front Door's environments.\n",
- "pgVerified": true,
- "description": "Use latest version for customer-managed certificates",
- "potentialBenefits": "Saves time and automates TLS updates",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "cd6a32af-747a-e649-82a7-a98f528ca842",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/best-practices/host-name-preservation",
- "name": "Preserve the original HTTP host name between a reverse proxy and its back-end web application"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Front Door can rewrite Host headers for custom domain names routing to a single origin, useful for avoiding custom domain configuration at both Front Door and the origin.\n",
- "pgVerified": true,
- "description": "Use the same domain name on Front Door and your origin",
- "potentialBenefits": "Improves session/auth handling",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1bd2b7e8-400f-e64a-99a2-c572f7b08a62",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/web-application-firewall",
- "name": "Web Application Firewall on Azure Front Door"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "For internet-facing applications, enabling the Front Door web application firewall (WAF) and configuring it to use managed rules is recommended for protection against a wide range of attacks using Microsoft-managed rules.\n",
- "pgVerified": true,
- "description": "Enable the WAF",
- "potentialBenefits": "Enhances web app security",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Enable the WAF\r\n\r\nresources\r\n| where type =~ \"microsoft.cdn/profiles\" and sku has \"AzureFrontDoor\"\r\n| project name, cdnprofileid=tolower(id), tostring(tags), resourceGroup, subscriptionId,skuname=tostring(sku.name)\r\n| join kind= fullouter (\r\n cdnresources\r\n | where type == \"microsoft.cdn/profiles/securitypolicies\"\r\n | extend wafpolicyid=tostring(properties['parameters']['wafPolicy']['id'])\r\n | extend splitid=split(id, \"/\")\r\n | extend cdnprofileid=tolower(strcat_array(array_slice(splitid, 0, 8), \"/\"))\r\n | project secpolname=name, cdnprofileid, wafpolicyid\r\n )\r\n on cdnprofileid\r\n| project name, cdnprofileid, secpolname, wafpolicyid,skuname\r\n| join kind = fullouter (\r\n resources\r\n | where type == \"microsoft.network/frontdoorwebapplicationfirewallpolicies\"\r\n | extend\r\n managedrulesenabled=iff(tostring(properties.managedRules.managedRuleSets) != \"[]\", true, false),\r\n enabledState = tostring(properties.policySettings.enabledState)\r\n | project afdwafname=name, managedrulesenabled, wafpolicyid=id, enabledState, tostring(tags)\r\n )\r\n on wafpolicyid\r\n| where name != \"\"\r\n| summarize\r\n associatedsecuritypolicies=countif(secpolname != \"\"),\r\n wafswithmanagedrules=countif(managedrulesenabled == 1)\r\n by name, id=cdnprofileid, tags,skuname\r\n| where associatedsecuritypolicies == 0 or wafswithmanagedrules == 0\r\n| project\r\n recommendationId = \"1bd2b7e8-400f-e64a-99a2-c572f7b08a62\",\r\n name,\r\n id,\r\n todynamic(tags),\r\n param1 = strcat(\"associatedsecuritypolicies:\", associatedsecuritypolicies),\r\n param2 = strcat(\"wafswithmanagedrules:\", wafswithmanagedrules),\r\n param3 = strcat(\"skuname:\",skuname)\r\n\r\n"
- },
- {
- "aprlGuid": "38f3d542-6de6-a44b-86c6-97e3be690281",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/health-probes",
- "name": "Health probes"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Front Door health probes help detect unavailable or unhealthy origins, directing traffic to alternate origins if needed.\n",
- "pgVerified": true,
- "description": "Disable health probes when there is only one origin in an origin group",
- "potentialBenefits": "Reduces unnecessary origin traffic",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Disable health probes when there is only one origin in an origin group\r\ncdnresources\r\n| where type =~ \"microsoft.cdn/profiles/origingroups\"\r\n| extend healthprobe=tostring(properties.healthProbeSettings)\r\n| project origingroupname=name, id, tags, resourceGroup, subscriptionId, healthprobe\r\n| join (\r\n cdnresources\r\n | where type =~ \"microsoft.cdn/profiles/origingroups/Origins\"\r\n | extend origingroupname = tostring(properties.originGroupName)\r\n )\r\n on origingroupname\r\n| summarize origincount=count(), enabledhealthprobecount=countif(healthprobe != \"\") by origingroupname, id, tostring(tags), resourceGroup, subscriptionId\r\n| where origincount == 1 and enabledhealthprobecount != 0\r\n| project\r\n recommendationId = \"38f3d542-6de6-a44b-86c6-97e3be690281\",\r\n name=origingroupname,\r\n id,\r\n todynamic(tags),\r\n param1 = strcat(\"origincount:\", origincount),\r\n param2 = strcat(\"enabledhealthprobecount:\", enabledhealthprobecount)\r\n\r\n"
- },
- {
- "aprlGuid": "5225bba3-28ec-1e43-8986-7eedfd466d65",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/patterns/health-endpoint-monitoring",
- "name": "Health Endpoint Monitoring pattern"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Consider selecting a webpage or location specifically designed for health monitoring as the endpoint for Azure Front Door's health probes. This should encompass the status of critical components like application servers, databases, and caches to serve production traffic efficiently.\n",
- "pgVerified": true,
- "description": "Select good health probe endpoints",
- "potentialBenefits": "Improves traffic routing and uptime",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "5783defe-b49e-d947-84f7-d8677593f324",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/health-probes#supported-http-methods-for-health-probes",
- "name": "Supported HTTP methods for health probes"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Health probes in Azure Front Door can use GET or HEAD HTTP methods. Using the HEAD method for health probes is a recommended practice because it reduces the traffic load on your origins, being less resource-intensive.\n",
- "pgVerified": true,
- "description": "Use HEAD health probes",
- "potentialBenefits": "Reduces traffic load on origins",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "b515690d-3bf9-3a49-8d38-188e0fd45896",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-geo-filtering",
- "name": "Geo filter WAF policy - GeoMatch"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Azure Front Door's geo-filtering through WAF enables defining custom access rules by country/region to restrict or allow web app access.\n",
- "pgVerified": true,
- "description": "Use geo-filtering in Azure Front Door",
- "potentialBenefits": "Enhanced regional access control",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1cfe7834-56ec-ff41-b11d-993734705dba",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/frontdoor/private-link",
- "name": "Private link for Azure Front Door"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Azure Private Link enables secure access to Azure PaaS and services over a private endpoint in your virtual network, ensuring traffic goes over the Microsoft backbone network, not the public internet.\n",
- "pgVerified": true,
- "description": "Secure your Origin with Private Link in Azure Front Door",
- "potentialBenefits": "Enhanced security and private connectivity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "82fa3cff-74bd-4063-b726-834f160592fa",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/frontdoor/understanding-pricing",
- "name": "Compare pricing between Azure Front Door tiers"
- }
- ],
- "recommendationControl": "ServiceUpgradeAndRetirement",
- "longDescription": "Azure Front Door standard is ~45% cheaper then AFD classic and has many additional benefits. Classic is also scheduled to be retired on March 31, 2027.\n",
- "pgVerified": false,
- "description": "Avoid using Classic Azure Front Door",
- "potentialBenefits": "Costs savings and additional supported features",
- "tags": null,
- "recommendationResourceType": "Microsoft.Cdn/profiles",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "//under-development\r\n"
- },
- {
- "aprlGuid": "042c034e-2b85-4c1d-bf9a-65c75a6b43e9",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/deployment-types#global-provisioned",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Global provisioned deployments provide reserved model processing capacity for high and predictable throughput using Azure global infrastructure. Suitable for applications requiring lower latency variance at large workload usage. Provides cost savings.\n",
- "pgVerified": true,
- "description": "Leverage Global provisioned deployment to ensure high and predictable throughput",
- "potentialBenefits": "Low latency variance, high throughputs, business continuity",
- "tags": null,
- "recommendationResourceType": "Microsoft.CognitiveServices/Accounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "081fc8a4-b2d9-405b-b351-334e621016f5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/deployment-types#global-standard",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Global Standard leverages Azure's global infrastructure to route traffic to the best available data center for customer's real-time inference requests. It provides the highest default quota and eliminates the need to load balance across multiple resources. Optimized for low to medium volume usage.\n",
- "pgVerified": true,
- "description": "Ensure PAYG AOAI models leverage Global Standard deployment",
- "potentialBenefits": "Best model availability, business continuity",
- "tags": null,
- "recommendationResourceType": "Microsoft.CognitiveServices/Accounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "0c193899-da60-4a52-b4a0-77d75ac8c5c5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/ai-services/openai/concepts/provisioned-throughput",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Provisioned Throughput offers pre-allocated capacity for consistent workloads, while Pay-as-You-Go charges for actual usage, ideal for variable workloads. During overflow, the Pay-as-You-Go instance manages excess load, ensuring service efficiency.\n",
- "pgVerified": true,
- "description": "Deploy a PAYG instance of the model with provisioned throughput to manage overflow effectively",
- "potentialBenefits": "PAYG model balances cost and performance and helps scale",
- "tags": null,
- "recommendationResourceType": "Microsoft.CognitiveServices/Accounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "8aa9744b-f302-4b05-9776-51d6dd3d0c3a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/deployment-types#global-batch",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Global batch efficiently handles large-scale tasks within 24 hours. Submit requests in a single file, with a separate quota to protect online workloads. Key uses: data processing, content generation, document review, customer support automation, data extraction, NLP tasks, and marketing.\n",
- "pgVerified": true,
- "description": "Ensure that models are deployed using Global batch for large scale processing",
- "potentialBenefits": "Cost effective faster turnaround for large-scale processing.",
- "tags": null,
- "recommendationResourceType": "Microsoft.CognitiveServices/Accounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "ac3add17-013e-41a5-af91-9fefce794a00",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/deployment-types#data-zone-standard",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Data zone deployments route customer traffic to the highest availability data center within the defined data zone, ensuring data at rest remains within the Azure OpenAI resource geography. This approach offers increased quota limits and ensures data processing occurs within the specified data zone.\n",
- "pgVerified": true,
- "description": "Ensure AOAI models are deployed using Data Zone Standard for data residency requirements",
- "potentialBenefits": "Enforce data residency and compliance standards",
- "tags": null,
- "recommendationResourceType": "Microsoft.CognitiveServices/Accounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "72b1b4ad-a14b-4430-9799-91bda782973d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/architecture/ai-ml/openai/architecture/log-monitor-azure-openai",
- "name": "Learn more"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Implementing a comprehensive monitoring solution for AOAI involves using Azure Monitor to track API usage, performance metrics, and security events. This setup helps optimize performance, manage costs, and ensure compliance by providing detailed insights into model usage and potential issues.\n",
- "pgVerified": false,
- "description": "Use comprehensive monitoring solution for AOAI service",
- "potentialBenefits": "Optimize performance and compliance with detailed insights",
- "tags": null,
- "recommendationResourceType": "Microsoft.CognitiveServices/Accounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "61187af4-7d36-4b48-b16e-de78bef143a0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/ai-services/openai/how-to/business-continuity-disaster-recovery",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "If your service needs to always be available, design AOAI Service to either failover into another region or split the workload between two or more regions. Applications requiring high degrees of resiliency should consider this to strengthen their model infrastructure.\n",
- "pgVerified": false,
- "description": "Deploy AOAI Service in multiple regions using Standard and/or Provisioned deployments",
- "potentialBenefits": "Ensures business continuity during regional outages.",
- "tags": null,
- "recommendationResourceType": "Microsoft.CognitiveServices/Accounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "3263a64a-c256-de48-9818-afd3cbc55c2a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/disks-shared",
- "name": "Azure Shared Disk Introduction"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Azure shared disks let you attach a disk to multiple VMs at once for deploying or migrating clustered applications, suitable only when a disk is shared among VM cluster members.\n",
- "pgVerified": true,
- "description": "Shared disks should only be enabled in clustered servers",
- "potentialBenefits": "Enhances clustered server performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/disks",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Disks configured to be Shared. This is not an indication of an issue, but if a disk with this configuration is assigned to two or more VMs without a proper disk control mechanism (like a WSFC) it can lead to data loss\r\nresources\r\n| where type =~ 'Microsoft.Compute/disks'\r\n| where isnotnull(properties.maxShares) and properties.maxShares >= 2\r\n| project id, name, tags, lowerCaseDiskId = tolower(id), diskState = tostring(properties.diskState)\r\n| join kind = leftouter (\r\n resources\r\n | where type =~ 'Microsoft.Compute/virtualMachines'\r\n | project osDiskVmName = name, lowerCaseOsDiskId = tolower(properties.storageProfile.osDisk.managedDisk.id)\r\n | join kind = fullouter (\r\n resources\r\n | where type =~ 'Microsoft.Compute/virtualMachines'\r\n | mv-expand dataDisks = properties.storageProfile.dataDisks\r\n | project dataDiskVmName = name, lowerCaseDataDiskId = tolower(dataDisks.managedDisk.id)\r\n )\r\n on $left.lowerCaseOsDiskId == $right.lowerCaseDataDiskId\r\n | project lowerCaseDiskId = coalesce(lowerCaseOsDiskId, lowerCaseDataDiskId), vmName = coalesce(osDiskVmName, dataDiskVmName)\r\n )\r\n on lowerCaseDiskId\r\n| summarize vmNames = make_set(vmName) by name, id, tostring(tags), diskState\r\n| extend param1 = strcat(\"DiskState: \", diskState), param2 = iif(isempty(vmNames[0]), \"VMName: n/a\", strcat(\"VMName: \", strcat_array(vmNames, \", \")))\r\n| project recommendationId = \"3263a64a-c256-de48-9818-afd3cbc55c2a\", name, id, tags, param1, param2\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "fa0cf4f5-0b21-47b7-89a9-ee936f193ce1",
- "recommendationTypeId": "d4102c0f-ebe3-4b22-8fe0-e488866a87af",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://aka.ms/zrsdisksdoc",
- "name": "Redundancy options for managed disks"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure disks offers a zone-redundant storage (ZRS) option for workloads that need to be resilient to an entire zone being down. Due to the cross-zone data replication, ZRS disks have higher write latency when compared to the locally-redundant option (LRS), so make sure to benchmark your disks.\n",
- "pgVerified": true,
- "description": "Use Azure Disks with Zone Redundant Storage for higher resiliency and availability",
- "potentialBenefits": "Enhanced Disk resilience to failures",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/disks",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find eligible Disks that are not zonal nor zone redundant\r\nresources\r\n| where type == 'microsoft.compute/disks'\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where sku has \"Premium_LRS\" or sku has \"StandardSSD_LRS\"\r\n| where sku.name has_cs 'ZRS' or array_length(zones) > 0\r\n| project recommendationId=\"fa0cf4f5-0b21-47b7-89a9-ee936f193ce1\", name, id, tags, param1 = sku, param2 = sku.name\r\n"
- },
- {
- "aprlGuid": "b49a39fd-f431-4b61-9062-f2157849d845",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/azure-compute-gallery#best-practices",
- "name": "Compute Gallery best practices"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Keeping a minimum of 3 replicas for production images in Azure's Compute Gallery ensures scalability and prevents throttling in multi-VM deployments by distributing VM deployments across different replicas. This reduces the risk of overloading a single replica.\n",
- "pgVerified": true,
- "description": "A minimum of three replicas should be kept for production image versions",
- "potentialBenefits": "Enhances scalability and avoids throttling",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/galleries",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Query to list all image versions,its associated image name and version replica configurations per region in a compute gallery whose version replicas is less than 3\r\nresources\r\n| where type =~ \"microsoft.compute/galleries/images/versions\"\r\n| extend GalleryName = tostring(split(tostring(id), \"/\")[8]), ImageName = tostring(split(tostring(id), \"/\")[10])\r\n| mv-expand VersionReplicas = properties.publishingProfile.targetRegions\r\n| project RecommendationId=\"b49a39fd-f431-4b61-9062-f2157849d845\",name,id,tags,param1=strcat(\"GalleryName: \",GalleryName),param2=strcat(\"ImageName: \",ImageName),param3=strcat(\"VersionReplicaRegionName: \",VersionReplicas.name),param4=strcat(\"VersionReplicationCount: \",VersionReplicas.regionalReplicaCount),rc=toint(VersionReplicas.regionalReplicaCount)\r\n| where rc < 3\r\n| project-away rc\r\n\r\n"
- },
- {
- "aprlGuid": "488dcc8b-f2e3-40ce-bf95-73deb2db095f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/azure-compute-gallery#best-practices",
- "name": "Compute Gallery best practices"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use ZRS for high availability when creating image/VM versions in Azure Compute Gallery, offering resilience against Availability Zone failures. ZRS accounts are advisable in regions with Availability Zones, with the choice of Standard_ZRS recommended over Standard_LRS for these regions.\n",
- "pgVerified": true,
- "description": "Zone redundant storage should be used for image versions",
- "potentialBenefits": "Enhances image version availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/galleries",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Query to list all image versions and its associated image and gallery name whose Storage account type is not using ZRS\r\nresources\r\n| where type =~ \"microsoft.compute/galleries/images/versions\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| extend GalleryName = tostring(split(tostring(id), \"/\")[8]), ImageName = tostring(split(tostring(id), \"/\")[10])\r\n| extend StorageAccountType = tostring(properties.publishingProfile.storageAccountType)\r\n| where StorageAccountType !has \"ZRS\"\r\n| project RecommendationId=\"488dcc8b-f2e3-40ce-bf95-73deb2db095f\",name,id,tags,param1=strcat(\"GalleryName: \",GalleryName),param2=strcat(\"ImageName: \",ImageName),param3=strcat(\"StorageAccountType: \",StorageAccountType)\r\n\r\n"
- },
- {
- "aprlGuid": "1c5e1e58-4e56-491c-8529-10f37af9d4ed",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/azure-compute-gallery#best-practices",
- "name": "Compute Gallery best practices"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "We recommend creating Trusted Launch Supported Images for benefits like Secure Boot, vTPM, trusted launch VMs, large boot volume. These are Gen 2 Images by default and you cannot change a VM's generation after creation, so review the considerations first.\n",
- "pgVerified": true,
- "description": "Consider creating TrustedLaunchSupported images where possible",
- "potentialBenefits": "Enhances VM security and features",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/galleries",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Query to list all images whose Hyper-V generation is not V2\r\nresources\r\n| where type =~ \"microsoft.compute/galleries/images\"\r\n| extend VMGeneration = properties.hyperVGeneration\r\n| where VMGeneration <> 'V2'\r\n| project RecommendationId=\"1c5e1e58-4e56-491c-8529-10f37af9d4ed\",name,id,tags,param1=strcat(\"VMGeneration: \",VMGeneration)\r\n\r\n"
- },
- {
- "aprlGuid": "b14ee8ed-7d27-447b-b6fb-6472cb5f4b75",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/azure-compute-gallery#replication",
- "name": "Compute Gallery Replication"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "On multi-region deployments, replicate Image Versions to a secondary region to ensure disaster recovery capability. This ensures that the Image Versions are available in the secondary region in case of a disaster in the primary region.\n",
- "pgVerified": true,
- "description": "Create Image Versions replicas in secondary region",
- "potentialBenefits": "Enhances disaster recovery capability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/galleries",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "b3c3ba1d-7de6-442d-8c50-023330fbf765",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/azure-compute-gallery#scaling",
- "name": "Compute Gallery Scaling"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "You can set a different replica count in each target region, based on the scale needs for the region. For every 20 VMs that you create concurrently, we recommend you keep one replica.\n",
- "pgVerified": true,
- "description": "Configure Image version replica count per region.",
- "potentialBenefits": "Enhances disaster recovery capability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/galleries",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "273f6b30-68e0-4241-85ea-acf15ffb60bf",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-orchestration-modes#what-has-changed-with-flexible-orchestration-mode",
- "name": "What has changed with Flexible orchestration mode"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Production VM workloads should be deployed on multiple VMs and grouped in a VMSS Flex instance to intelligently distribute across the platform, minimizing the impact of platform faults and updates.\n",
- "pgVerified": true,
- "description": "Run production workloads on two or more VMs using VMSS Flex",
- "potentialBenefits": "Enhanced fault/update resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that are not associated with a VMSS Flex instance\r\nresources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where isnull(properties.virtualMachineScaleSet.id)\r\n| project recommendationId=\"273f6b30-68e0-4241-85ea-acf15ffb60bf\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "2bd0be95-a825-6f47-a8c6-3db1fb5eb387",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/create-portal-availability-zone?tabs=standard",
- "name": "Create virtual machines in an availability zone using the Azure portal"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Availability Zones, within each Azure region, are tolerant to local failures, protecting applications and data against unlikely Datacenter failures by being physically separate.\n",
- "pgVerified": true,
- "description": "Deploy VMs across Availability Zones",
- "potentialBenefits": "Enhanced VM resilience to failures",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that are not assigned to a Zone\r\nResources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where isnull(zones)\r\n| project recommendationId=\"2bd0be95-a825-6f47-a8c6-3db1fb5eb387\", name, id, tags, param1=\"No Zone\"\r\n"
- },
- {
- "aprlGuid": "a8d25876-7951-b646-b4e8-880c9031596b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/flexible-virtual-machine-scale-sets-migration-resources",
- "name": "Migrate deployments and resources to Virtual Machine Scale Sets in Flexible orchestration"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "While availability sets are not scheduled for immediate deprecation, they are planned to be deprecated in the future. Migrate workloads from VMs to VMSS Flex for deployment across zones or within the same zone across different fault domains (FDs) for better reliability.\n",
- "pgVerified": true,
- "description": "Migrate VMs using availability sets to VMSS Flex",
- "potentialBenefits": "Enhances reliability and future-proofs VMs",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs using Availability Sets\r\nresources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where isnotnull(properties.availabilitySet)\r\n| project recommendationId = \"a8d25876-7951-b646-b4e8-880c9031596b\", name, id, tags, param1=strcat(\"availabilitySet: \",properties.availabilitySet.id)\r\n\r\n"
- },
- {
- "aprlGuid": "cfe22a65-b1db-fd41-9e8e-d573922709ae",
- "recommendationTypeId": "ed651749-cd37-4fd5-9897-01b416926745",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/checklist/resiliency-per-service#virtual-machines",
- "name": "Resiliency checklist for Virtual Machines"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Replicating Azure VMs via Site Recovery entails continuous, asynchronous disk replication to a target region. Recovery points are generated every few minutes, ensuring a Recovery Point Objective (RPO) in minutes.\n",
- "pgVerified": true,
- "description": "Replicate VMs using Azure Site Recovery",
- "potentialBenefits": "Minimize downtime in disasters",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that do NOT have replication with ASR enabled\r\nresources\r\n| where type =~ \"Microsoft.Compute/virtualMachines\"\r\n| extend securityType = iif(isnull(properties.securityProfile.securityType), \"Standard\", properties.securityProfile.securityType)\r\n| where securityType !in~ (\"TrustedLaunch\", \"ConfidentialVM\")\r\n| project id, vmIdForJoin = tolower(id), name, tags\r\n| join kind = leftouter (\r\n recoveryservicesresources\r\n | where type =~ \"Microsoft.RecoveryServices/vaults/replicationFabrics/replicationProtectionContainers/replicationProtectedItems\"\r\n and properties.providerSpecificDetails.dataSourceInfo.datasourceType =~ \"AzureVm\"\r\n | project vmResourceId = tolower(properties.providerSpecificDetails.dataSourceInfo.resourceId)\r\n )\r\n on $left.vmIdForJoin == $right.vmResourceId\r\n| where isempty(vmResourceId)\r\n| project recommendationId = \"cfe22a65-b1db-fd41-9e8e-d573922709ae\", name, id, tags\r\n"
- },
- {
- "aprlGuid": "122d11d7-b91f-8747-a562-f56b79bcfbdc",
- "recommendationTypeId": "57ecb3cd-f2b4-4cad-8b3a-232cca527a0b",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/unmanaged-disks-deprecation",
- "name": "Migrate your Azure unmanaged disks by Sep 30, 2025"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure is retiring unmanaged disks on September 30, 2025. Users should plan the migration to avoid disruptions and maintain service reliability.\n",
- "pgVerified": true,
- "description": "Use Managed Disks for VM disks",
- "potentialBenefits": "Avoid retirement disruption, enhance reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that are not using Managed Disks\r\nResources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where isnull(properties.storageProfile.osDisk.managedDisk)\r\n| project recommendationId = \"122d11d7-b91f-8747-a562-f56b79bcfbdc\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "4ea2878f-0d69-8d4a-b715-afc10d1e538e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/managed-disks-overview#data-disk",
- "name": "Introduction to Azure managed disks - Data disks"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "A data disk is a managed disk attached to a virtual machine for storing database or other essential data. These disks are SCSI drives labeled as per choice.\n",
- "pgVerified": true,
- "description": "Host database data on a data disk",
- "potentialBenefits": "Enhances performance, recovery, migration flexibility",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that only have OS Disk\r\nResources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where array_length(properties.storageProfile.dataDisks) < 1\r\n| project recommendationId = \"4ea2878f-0d69-8d4a-b715-afc10d1e538e\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "1981f704-97b9-b645-9c57-33f8ded9261a",
- "recommendationTypeId": "651c7925-17a3-42e5-85cd-73bd095cf27f",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/backup/backup-overview",
- "name": "What is the Azure Backup service?"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Enable backups for your virtual machines with Azure Backup to secure and quickly recover your data. This service offers simple, secure, and cost-effective solutions for backing up and recovering data from the Microsoft Azure cloud.\n",
- "pgVerified": true,
- "description": "Backup VMs with Azure Backup service",
- "potentialBenefits": "Secure data recovery and backup",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that do NOT have Backup enabled\r\n// Run query to see results.\r\nresources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| project name, id, tags\r\n| join kind=leftouter (\r\n recoveryservicesresources\r\n | where type =~ 'Microsoft.RecoveryServices/vaults/backupFabrics/protectionContainers/protectedItems'\r\n | where properties.dataSourceInfo.datasourceType =~ 'Microsoft.Compute/virtualMachines'\r\n | project idBackupEnabled=properties.sourceResourceId\r\n | extend name=strcat_array(array_slice(split(idBackupEnabled, '/'), 8, -1), '/')\r\n) on name\r\n| where isnull(idBackupEnabled)\r\n| project-away idBackupEnabled\r\n| project-away name1\r\n| project recommendationId = \"1981f704-97b9-b645-9c57-33f8ded9261a\", name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "98b334c0-8578-6046-9e43-b6e8fce6318e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/states-billing?context=%2Ftroubleshoot%2Fazure%2Fvirtual-machines%2Fcontext%2Fcontext#power-states-and-billing",
- "name": "States and billing status of Azure Virtual Machines"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Azure Virtual Machines (VM) instances have various states, like provisioning and power states. A non-running VM may indicate issues or it being unnecessary, suggesting removal could help cut costs.\n",
- "pgVerified": true,
- "description": "Review VMs in stopped state",
- "potentialBenefits": "Reduce costs by removing unused VMs",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that are NOT running\r\nResources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where properties.extended.instanceView.powerState.displayStatus != 'VM running'\r\n| project recommendationId = \"98b334c0-8578-6046-9e43-b6e8fce6318e\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "dfedbeb1-1519-fc47-86a5-52f96cf07105",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview",
- "name": "Accelerated Networking (AccelNet) overview"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Accelerated networking enables SR-IOV to a VM, greatly improving its networking performance by bypassing the host from the data path, which reduces latency, jitter, and CPU utilization for demanding network workloads on supported VM types.\n",
- "pgVerified": true,
- "description": "Enable Accelerated Networking (AccelNet)",
- "potentialBenefits": "Reduces latency, jitter and CPU use",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VM NICs that do not have Accelerated Networking enabled\r\nresources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| mv-expand nic = properties.networkProfile.networkInterfaces\r\n| project name, id, tags, lowerCaseNicId = tolower(nic.id), vmSize = tostring(properties.hardwareProfile.vmSize)\r\n| join kind = inner (\r\n resources\r\n | where type =~ 'Microsoft.Network/networkInterfaces'\r\n | where properties.enableAcceleratedNetworking == false\r\n | project nicName = split(id, \"/\")[8], lowerCaseNicId = tolower(id)\r\n )\r\n on lowerCaseNicId\r\n| summarize nicNames = make_set(nicName) by name, id, tostring(tags), vmSize\r\n| extend param1 = strcat(\"NicName: \", strcat_array(nicNames, \", \")), param2 = strcat(\"VMSize: \", vmSize)\r\n| project recommendationId = \"dfedbeb1-1519-fc47-86a5-52f96cf07105\", name, id, tags, param1, param2\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "73d1bb04-7d3e-0d47-bc0d-63afe773b5fe",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/accelerated-networking-overview",
- "name": "Accelerated Networking (AccelNet) overview"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "When Accelerated Networking is enabled, the default Azure VNet interface in GuestOS is swapped for a Mellanox, and its driver comes from a 3rd party. Marketplace images have the latest Mellanox drivers, but post-deployment, updating the driver is the user's responsibility.\n",
- "pgVerified": true,
- "description": "When AccelNet is enabled, you must manually update the GuestOS NIC driver",
- "potentialBenefits": "Enhanced VM network efficiency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "1f629a30-c9d0-d241-82ee-6f2eb9d42cb4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/load-balancer/load-balancer-outbound-connections",
- "name": "Use Source Network Address Translation (SNAT) for outbound connections"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "For outbound internet connectivity of Virtual Machines, using NAT Gateway or Azure Firewall is recommended to enhance security and service resilience, thanks to their higher availability and SNAT ports.\n",
- "pgVerified": true,
- "description": "VMs should not have a Public IP directly associated",
- "potentialBenefits": "Enhanced security and service resiliency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs with PublicIPs directly associated with them\r\nResources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where isnotnull(properties.networkProfile.networkInterfaces)\r\n| mv-expand nic=properties.networkProfile.networkInterfaces\r\n| project name, id, tags, nicId = nic.id\r\n| extend nicId = tostring(nicId)\r\n| join kind=inner (\r\n Resources\r\n | where type =~ 'Microsoft.Network/networkInterfaces'\r\n | where isnotnull(properties.ipConfigurations)\r\n | mv-expand ipconfig=properties.ipConfigurations\r\n | extend publicIp = tostring(ipconfig.properties.publicIPAddress.id)\r\n | where publicIp != \"\"\r\n | project name, nicId = tostring(id), publicIp\r\n) on nicId\r\n| project recommendationId = \"1f629a30-c9d0-d241-82ee-6f2eb9d42cb4\", name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "82b3cf6b-9ae2-2e44-b193-10793213f676",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/network-security-group-how-it-works#intra-subnet-traffic",
- "name": "How network security groups filter network traffic"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Unless you have a specific reason, it's advised to associate a network security group to a subnet or a network interface, but not both, to avoid unexpected communication issues and troubleshooting due to potential rule conflicts between the two associations.\n",
- "pgVerified": true,
- "description": "VM network interfaces and associated subnets both have a Network Security Group associated",
- "potentialBenefits": "Reduces communication problems",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of virtual machines and associated NICs that do have an NSG associated to them and also an NSG associated to the subnet.\r\nResources\r\n| where type =~ 'Microsoft.Network/networkInterfaces'\r\n| where isnotnull(properties.networkSecurityGroup)\r\n| mv-expand ipConfigurations = properties.ipConfigurations, nsg = properties.networkSecurityGroup\r\n| project nicId = tostring(id), subnetId = tostring(ipConfigurations.properties.subnet.id), nsgName=split(nsg.id, '/')[8]\r\n| parse kind=regex subnetId with '/virtualNetworks/' virtualNetwork '/subnets/' subnet\r\n | join kind=inner (\r\n Resources\r\n | where type =~ 'Microsoft.Network/NetworkSecurityGroups' and isnotnull(properties.subnets)\r\n | project name, resourceGroup, subnet=properties.subnets\r\n | mv-expand subnet\r\n | project subnetId=tostring(subnet.id)\r\n ) on subnetId\r\n | project nicId\r\n| join kind=leftouter (\r\n Resources\r\n | where type =~ 'Microsoft.Compute/virtualMachines'\r\n | where isnotnull(properties.networkProfile.networkInterfaces)\r\n | mv-expand nic=properties.networkProfile.networkInterfaces\r\n | project vmName = name, vmId = id, tags, nicId = nic.id, nicName=split(nic.id, '/')[8]\r\n | extend nicId = tostring(nicId)\r\n) on nicId\r\n| project recommendationId = \"82b3cf6b-9ae2-2e44-b193-10793213f676\", name=vmName, id = vmId, tags, param1 = strcat(\"nic-name=\", nicName)\r\n\r\n"
- },
- {
- "aprlGuid": "41a22a5e-5e08-9647-92d0-2ffe9ef1bdad",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/virtual-network-network-interface?tabs=network-interface-portal#enable-or-disable-ip-forwarding",
- "name": "Enable or disable IP forwarding"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "IP forwarding allows a virtual machine network interface to receive and send network traffic not destined for or originating from its assigned IP addresses.\n",
- "pgVerified": true,
- "description": "IP Forwarding should only be enabled for Network Virtual Appliances",
- "potentialBenefits": "Enhances network appliance function",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VM NICs that have IPForwarding enabled. This feature is usually only required for Network Virtual Appliances\r\nResources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where isnotnull(properties.networkProfile.networkInterfaces)\r\n| mv-expand nic=properties.networkProfile.networkInterfaces\r\n| project name, id, tags, nicId = nic.id\r\n| extend nicId = tostring(nicId)\r\n| join kind=inner (\r\n Resources\r\n | where type =~ 'Microsoft.Network/networkInterfaces'\r\n | where properties.enableIPForwarding == true\r\n | project nicId = tostring(id)\r\n) on nicId\r\n| project recommendationId = \"41a22a5e-5e08-9647-92d0-2ffe9ef1bdad\", name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "1cf8fe21-9593-1e4e-966b-779a294c0d30",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-name-resolution-for-vms-and-role-instances",
- "name": "Name resolution for resources in Azure virtual networks"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Configure the DNS Server at the Virtual Network level to prevent any inconsistency across the environment.\n",
- "pgVerified": true,
- "description": "Customer DNS Servers should be configured in the Virtual Network level",
- "potentialBenefits": "Ensures DNS consistency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VM NICs that have DNS Server settings configured in any of the NICs\r\nResources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where isnotnull(properties.networkProfile.networkInterfaces)\r\n| mv-expand nic=properties.networkProfile.networkInterfaces\r\n| project name, id, tags, nicId = nic.id\r\n| extend nicId = tostring(nicId)\r\n| join kind=inner (\r\n Resources\r\n | where type =~ 'Microsoft.Network/networkInterfaces'\r\n | project name, id, dnsServers = properties.dnsSettings.dnsServers\r\n | extend hasDns = array_length(dnsServers) >= 1\r\n | where hasDns != 0\r\n | project name, nicId = tostring(id)\r\n) on nicId\r\n| project recommendationId = \"1cf8fe21-9593-1e4e-966b-779a294c0d30\", name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "70b1d2be-e6c4-b54e-9959-b1b690f9e485",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/disks-enable-private-links-for-import-export-portal",
- "name": "Restrict import/export access for managed disks using Azure Private Link"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Recommended changing to \"Disable public access and enable private access\" and creating a Private Endpoint to improve security by restricting direct public access and ensuring connections are made privately, enhancing data protection and minimizing potential external threats.\n",
- "pgVerified": true,
- "description": "Network access to the VM disk should be set to Disable public access and enable private access",
- "potentialBenefits": "Enhances VM security and privacy",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Disks with \"Enable public access from all networks\" enabled\r\nresources\r\n| where type =~ 'Microsoft.Compute/disks'\r\n| where properties.publicNetworkAccess == \"Enabled\"\r\n| project id, name, tags, lowerCaseDiskId = tolower(id)\r\n| join kind = leftouter (\r\n resources\r\n | where type =~ 'Microsoft.Compute/virtualMachines'\r\n | project osDiskVmName = name, lowerCaseOsDiskId = tolower(properties.storageProfile.osDisk.managedDisk.id)\r\n | join kind = fullouter (\r\n resources\r\n | where type =~ 'Microsoft.Compute/virtualMachines'\r\n | mv-expand dataDisks = properties.storageProfile.dataDisks\r\n | project dataDiskVmName = name, lowerCaseDataDiskId = tolower(dataDisks.managedDisk.id)\r\n )\r\n on $left.lowerCaseOsDiskId == $right.lowerCaseDataDiskId\r\n | project lowerCaseDiskId = coalesce(lowerCaseOsDiskId, lowerCaseDataDiskId), vmName = coalesce(osDiskVmName, dataDiskVmName)\r\n )\r\n on lowerCaseDiskId\r\n| summarize vmNames = make_set(vmName) by name, id, tostring(tags)\r\n| extend param1 = iif(isempty(vmNames[0]), \"VMName: n/a\", strcat(\"VMName: \", strcat_array(vmNames, \", \")))\r\n| project recommendationId = \"70b1d2be-e6c4-b54e-9959-b1b690f9e485\", name, id, tags, param1\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "c42343ae-2712-2843-a285-3437eb0b28a1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/landing-zone/design-principles#policy-driven-governance",
- "name": "Policy-driven governance"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Keeping your virtual machine (VM) secure is crucial for the applications you run. This involves using various Azure services and features to ensure secure access to your VMs and the secure storage of your data, aiming for overall security of your VM and applications.\n",
- "pgVerified": true,
- "description": "Ensure that your VMs are compliant with Azure Policies",
- "potentialBenefits": "Secure VMs and applications",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs in \"Non-compliant\" state with Azure Policies\r\npolicyresources\r\n| where type =~ \"Microsoft.PolicyInsights/policyStates\" and properties.resourceType =~ \"Microsoft.Compute/virtualMachines\" and properties.complianceState =~ \"NonCompliant\"\r\n| project\r\n policyDefinitionId = tolower(properties.policyDefinitionId),\r\n policyAssignmentId = tolower(properties.policyAssignmentId),\r\n targetResourceId = tolower(properties.resourceId)\r\n// Join the policy definition details\r\n| join kind = leftouter (\r\n policyresources\r\n | where type =~ \"Microsoft.Authorization/policyDefinitions\"\r\n | project policyDefinitionId = tolower(id), policyDefinitionDisplayName = properties.displayName\r\n )\r\n on policyDefinitionId\r\n| project policyDefinitionId, policyDefinitionDisplayName, policyAssignmentId, targetResourceId\r\n// Join the policy assignment details\r\n| join kind = leftouter (\r\n policyresources\r\n | where type =~ \"Microsoft.Authorization/policyAssignments\"\r\n | project policyAssignmentId = tolower(id), policyAssignmentDisplayName = properties.displayName\r\n )\r\n on policyAssignmentId\r\n| project policyDefinitionId, policyDefinitionDisplayName, policyAssignmentId, policyAssignmentDisplayName, targetResourceId\r\n// Join the target resource details\r\n| join kind = leftouter (\r\n resources\r\n | where type =~ \"Microsoft.Compute/virtualMachines\"\r\n | project targetResourceId = tolower(id), targetResourceIdPreservedCase = id, targetResourceName = name, targetResourceTags = tags\r\n )\r\n on targetResourceId\r\n| project\r\n recommendationId = \"c42343ae-2712-2843-a285-3437eb0b28a1\",\r\n name = targetResourceName,\r\n id = targetResourceIdPreservedCase,\r\n tags = targetResourceTags,\r\n param1 = strcat(\"DefinitionName: \", policyDefinitionDisplayName),\r\n param2 = strcat(\"DefinitionID: \", policyDefinitionId),\r\n param3 = strcat(\"AssignmentName: \", policyAssignmentDisplayName),\r\n param4 = strcat(\"AssignmentID: \", policyAssignmentId)\r\n"
- },
- {
- "aprlGuid": "f0a97179-133a-6e4f-8a49-8a44da73ffce",
- "recommendationTypeId": "a40cc620-e72c-fdf4-c554-c6ca2cd705c0",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/disk-encryption-overview",
- "name": "Overview of managed disk encryption options"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Consider enabling Azure Disk Encryption (ADE) for encrypting Azure VM disks using DM-Crypt (Linux) or BitLocker (Windows). Additionally, consider Encryption at host and Confidential disk encryption for enhanced data security.\n",
- "pgVerified": true,
- "description": "Virtual Machines should have Azure Disk Encryption or EncryptionAtHost enabled",
- "potentialBenefits": "Enhances data security and integrity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure VM disks without Azure Disk Encryption or encryption at host enabled\r\nresources\r\n| where type =~ \"microsoft.compute/disks\"\r\n| project diskId = id, diskName = name, vmId = tolower(managedBy), azureDiskEncryption = iff(properties.encryptionSettingsCollection.enabled == true, true, false)\r\n| join kind=leftouter (resources\r\n| where type =~ \"microsoft.compute/virtualmachines\"\r\n| project vmId = tolower(id), vmName = name, encryptionAtHost = iff(properties.securityProfile.encryptionAtHost == true, true, false)) on vmId\r\n| where not(encryptionAtHost) and not(azureDiskEncryption)\r\n| project recommendationId = 'f0a97179-133a-6e4f-8a49-8a44da73ffce', name = vmName, id =vmId, param1 = strcat('diskName:',diskName), param2 = strcat('azureDiskEncryption:',iff(azureDiskEncryption, \"Enabled\", \"Disabled\")), param3 = strcat('encryptionAtHost:',iff(encryptionAtHost, \"Enabled\", \"Disabled\"))\r\n"
- },
- {
- "aprlGuid": "b72214bb-e879-5f4b-b9cd-642db84f36f4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-monitor/vm/vminsights-overview",
- "name": "Overview of VM insights"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "VM Insights monitors VM and scale set performance, health, running processes, and dependencies. It enhances the predictability of application performance and availability by pinpointing performance bottlenecks and network issues, and it clarifies if problems are related to other dependencies.\n",
- "pgVerified": true,
- "description": "Enable VM Insights",
- "potentialBenefits": "Improves VM performance and health",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Check for VMs without Azure Monitoring Agent extension installed, missing Data Collection Rule or Data Collection Rule without performance enabled.\r\nResources\r\n| where type == 'microsoft.compute/virtualmachines'\r\n| project idVm = tolower(id), name, tags\r\n| join kind=leftouter (\r\n InsightsResources\r\n | where type =~ \"Microsoft.Insights/dataCollectionRuleAssociations\" and id has \"Microsoft.Compute/virtualMachines\"\r\n | project idDcr = tolower(properties.dataCollectionRuleId), idVmDcr = tolower(substring(id, 0, indexof(id, \"/providers/Microsoft.Insights/dataCollectionRuleAssociations/\"))))\r\non $left.idVm == $right.idVmDcr\r\n| join kind=leftouter (\r\n Resources\r\n | where type =~ \"Microsoft.Insights/dataCollectionRules\"\r\n | extend\r\n isPerformanceEnabled = iif(properties.dataSources.performanceCounters contains \"Microsoft-InsightsMetrics\" and properties.dataFlows contains \"Microsoft-InsightsMetrics\", true, false),\r\n isMapEnabled = iif(properties.dataSources.extensions contains \"Microsoft-ServiceMap\" and properties.dataSources.extensions contains \"DependencyAgent\" and properties.dataFlows contains \"Microsoft-ServiceMap\", true, false)//,\r\n | where isPerformanceEnabled or isMapEnabled\r\n | project dcrName = name, isPerformanceEnabled, isMapEnabled, idDcr = tolower(id))\r\non $left.idDcr == $right.idDcr\r\n| join kind=leftouter (\r\n Resources\r\n | where type == 'microsoft.compute/virtualmachines/extensions' and (name contains 'AzureMonitorWindowsAgent' or name contains 'AzureMonitorLinuxAgent')\r\n | extend idVmExtension = tolower(substring(id, 0, indexof(id, '/extensions'))), extensionName = name)\r\non $left.idVm == $right.idVmExtension\r\n| where isPerformanceEnabled != 1 or (extensionName != 'AzureMonitorWindowsAgent' and extensionName != 'AzureMonitorLinuxAgent')\r\n| project recommendationId = \"b72214bb-e879-5f4b-b9cd-642db84f36f4\", name, id = idVm, tags, param1 = strcat('MonitoringExtension:', extensionName), param2 = strcat('DataCollectionRuleId:', idDcr), param3 = strcat('isPerformanceEnabled:', isPerformanceEnabled)\r\n\r\n"
- },
- {
- "aprlGuid": "4a9d8973-6dba-0042-b3aa-07924877ebd5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-monitor/agents/agents-overview",
- "name": "Azure Monitor Agent overview"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Azure Monitor Metrics automatically receives platform metrics, but platform logs, which offer detailed diagnostics and auditing for resources and their Azure platform, need to be manually routed for collection.\n",
- "pgVerified": true,
- "description": "Configure monitoring for all Azure Virtual Machines",
- "potentialBenefits": "Enhanced diagnostics and auditing capability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Virtual Machines without diagnostic settings enabled/with diagnostic settings enabled but not configured both performance counters and event logs/syslogs.\r\nresources\r\n| where type =~ \"microsoft.compute/virtualmachines\"\r\n| project name, id, tags, lowerCaseVmId = tolower(id)\r\n| join kind = leftouter (\r\n resources\r\n | where type =~ \"Microsoft.Compute/virtualMachines/extensions\" and properties.publisher =~ \"Microsoft.Azure.Diagnostics\"\r\n | project\r\n lowerCaseVmIdOfExtension = tolower(substring(id, 0, indexof(id, \"/extensions/\"))),\r\n extensionType = properties.type,\r\n provisioningState = properties.provisioningState,\r\n storageAccount = properties.settings.StorageAccount,\r\n // Windows\r\n wadPerfCounters = properties.settings.WadCfg.DiagnosticMonitorConfiguration.PerformanceCounters.PerformanceCounterConfiguration,\r\n wadEventLogs = properties.settings.WadCfg.DiagnosticMonitorConfiguration.WindowsEventLog,\r\n // Linux\r\n ladPerfCounters = properties.settings.ladCfg.diagnosticMonitorConfiguration.performanceCounters.performanceCounterConfiguration,\r\n ladSyslog = properties.settings.ladCfg.diagnosticMonitorConfiguration.syslogEvents\r\n | extend\r\n // Windows\r\n isWadPerfCountersConfigured = iif(array_length(wadPerfCounters) > 0, true, false),\r\n isWadEventLogsConfigured = iif(isnotnull(wadEventLogs) and array_length(wadEventLogs.DataSource) > 0, true, false),\r\n // Linux\r\n isLadPerfCountersConfigured = iif(array_length(ladPerfCounters) > 0, true, false),\r\n isLadSyslogConfigured = isnotnull(ladSyslog)\r\n | project\r\n lowerCaseVmIdOfExtension,\r\n extensionType,\r\n provisioningState,\r\n storageAccount,\r\n isPerfCountersConfigured = case(extensionType =~ \"IaaSDiagnostics\", isWadPerfCountersConfigured, extensionType =~ \"LinuxDiagnostic\", isLadPerfCountersConfigured, false),\r\n isEventLogsConfigured = case(extensionType =~ \"IaaSDiagnostics\", isWadEventLogsConfigured, extensionType =~ \"LinuxDiagnostic\", isLadSyslogConfigured, false)\r\n )\r\n on $left.lowerCaseVmId == $right.lowerCaseVmIdOfExtension\r\n| where isempty(lowerCaseVmIdOfExtension) or provisioningState !~ \"Succeeded\" or not(isPerfCountersConfigured and isEventLogsConfigured)\r\n| extend\r\n param1 = strcat(\"DiagnosticSetting: \", iif(isnotnull(extensionType), strcat(\"Enabled, partially configured (\", extensionType, \")\"), \"Not enabled\")),\r\n param2 = strcat(\"ProvisioningState: \", iif(isnotnull(provisioningState), provisioningState, \"n/a\")),\r\n param3 = strcat(\"storageAccount: \", iif(isnotnull(storageAccount), storageAccount, \"n/a\")),\r\n param4 = strcat(\"PerformanceCounters: \", case(isnull(isPerfCountersConfigured), \"n/a\", isPerfCountersConfigured, \"Configured\", \"Not configured\")),\r\n param5 = strcat(\"EventLogs/Syslogs: \", case(isnull(isEventLogsConfigured), \"n/a\", isEventLogsConfigured, \"Configured\", \"Not configured\"))\r\n| project recommendationId = \"4a9d8973-6dba-0042-b3aa-07924877ebd5\", name, id, tags, param1, param2, param3, param4, param5\r\n\r\n"
- },
- {
- "aprlGuid": "52ab9e5c-eec0-3148-8bd7-b6dd9e1be870",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/maintenance-configurations",
- "name": "Use maintenance configurations to control and manage the VM updates"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "The maintenance configuration settings let users schedule and manage updates, making sure the updates or interruptions on the VM are performed within a planned timeframe.\n",
- "pgVerified": true,
- "description": "Use maintenance configurations for the VMs",
- "potentialBenefits": "Scheduled updates for VMs",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find VMS that do not have maintenance configuration assigned\r\nResources\r\n| extend resourceId = tolower(id)\r\n| project name, location, type, id, tags, resourceId, properties\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| join kind=leftouter (\r\nmaintenanceresources\r\n| where type =~ \"microsoft.maintenance/configurationassignments\"\r\n| project planName = name, type, maintenanceProps = properties\r\n| extend resourceId = tostring(maintenanceProps.resourceId)\r\n) on resourceId\r\n| where isnull(maintenanceProps)\r\n| project recommendationId = \"52ab9e5c-eec0-3148-8bd7-b6dd9e1be870\",name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "3201dba8-d1da-4826-98a4-104066545170",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/sizes-b-series-burstable",
- "name": "B-series burstable virtual machine sizes"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "A-series VMs are tailored for entry-level workloads like development and testing, including use cases such as development and test servers, low traffic web servers, and small to medium databases.\n",
- "pgVerified": true,
- "description": "Don't use A or B-Series VMs for production needing constant full CPU performance",
- "potentialBenefits": "Ensures full CPU usage for heavy tasks",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs using A or B series families\r\nresources\r\n| where type == 'microsoft.compute/virtualmachines'\r\n| where properties.hardwareProfile.vmSize contains \"Standard_B\" or properties.hardwareProfile.vmSize contains \"Standard_A\"\r\n| project recommendationId = \"3201dba8-d1da-4826-98a4-104066545170\", name, id, tags, param1=strcat(\"vmSku: \" , properties.hardwareProfile.vmSize)\r\n\r\n"
- },
- {
- "aprlGuid": "df0ff862-814d-45a3-95e4-4fad5a244ba6",
- "recommendationTypeId": "58d6648d-32e8-4346-827c-4f288dd8ca24",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/disks-types#disk-type-comparison",
- "name": "Disk type comparison and decision tree"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Compared to Standard HDD and SSD, Premium SSD, SSD v2, and Ultra Disks offer improved performance, configurability, and higher single-instance VM uptime SLAs. The lowest SLA of all disks on a VM applies, so it is best to use Premium or Ultra Disks for the highest uptime SLA.\n",
- "pgVerified": true,
- "description": "Mission Critical Workloads should consider using Premium or Ultra Disks",
- "potentialBenefits": "Enhanced performance, cost efficiency, and uptime SLA",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that have an attached disk that is not in the Premium or Ultra sku tier.\r\n\r\nresources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| extend lname = tolower(name)\r\n| join kind=leftouter(resources\r\n | where type =~ 'Microsoft.Compute/disks'\r\n | where not(sku.tier =~ 'Premium') and not(sku.tier =~ 'Ultra')\r\n | extend lname = tolower(tostring(split(managedBy, '/')[8]))\r\n | project lname, name\r\n | summarize disks = make_list(name) by lname) on lname\r\n| where isnotnull(disks)\r\n| project recommendationId = \"df0ff862-814d-45a3-95e4-4fad5a244ba6\", name, id, tags, param1=strcat(\"AffectedDisks: \", disks)\r\n\r\n"
- },
- {
- "aprlGuid": "9ab499d8-8844-424d-a2d4-8f53690eb8f8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-boost/overview",
- "name": "Microsoft Azure Boost"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "If the workload is Maintenance sensitive, consider Azure Boost compatible VMs. Azure Boost is designed to lessen the impact on customers when Azure maintenance activities occur on the host.\n",
- "pgVerified": true,
- "description": "Use Azure Boost VMs for Maintenance sensitive workload",
- "potentialBenefits": "Less maintenance impact",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "2de8fa5e-14f4-4c4c-857f-1520f87a629f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/windows/scheduled-event-service",
- "name": "Monitor scheduled events for your Azure VMs"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "If your workload is Maintenance sensitive, enable Scheduled Events. This Azure Metadata Service lets your app prepare for virtual machine maintenance by providing information on upcoming events like reboots, reducing disruptions.\n",
- "pgVerified": true,
- "description": "Enable Scheduled Events for Maintenance sensitive workload VMs",
- "potentialBenefits": "Minimize downtime for VMs",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "302fda08-ee65-4fbe-a916-6dc0b33169c4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://aka.ms/on-demand-capacity-reservations-docs",
- "name": "On-demand Capacity Reservation"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Capacity Reservations ensure high availability for virtual machines by reserving compute capacity in advance within a specific region or availability zone. This guarantees that VMs will have the necessary resources during peak demand or maintenance events, enhancing reliability and uptime.\n",
- "pgVerified": true,
- "description": "Reserve Compute Capacity for critical workloads",
- "potentialBenefits": "Guaranteed capacity in constrained regions/zones",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Virtual Machines not associated with a Capacity Reservation, and provide details for Capacity Reservation like vmSize, location, and zone.\r\nresources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where isnull(properties.capacityReservation)\r\n| extend zoneValue = iff(isnull(zones), \"null\", zones)\r\n| project recommendationId = \"302fda08-ee65-4fbe-a916-6dc0b33169c4\", name, id, tags, param1 = strcat(\"VmSize: \", properties.hardwareProfile.vmSize), param2 = strcat(\"Location: \", location), param3 = strcat(\"Zone: \", zoneValue)\r\n"
- },
- {
- "aprlGuid": "5f7e8a12-3c4f-456b-919c-2e9adff98c38",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/update-linux-agent?tabs=ubuntu",
- "name": "How to update the Azure Linux Agent on a VM"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "If you've installed the Azure Linux Agent or are using an endorsed distribution image, ensure your agent version is up-to-date. Some Linux distributions may disable auto-update or use older agent versions.\n",
- "pgVerified": true,
- "description": "Update the Azure Linux VM Agent",
- "potentialBenefits": "Reduces complications with VM provisioning",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "587ca3e4-113b-4c4f-b4e0-92cd8d2065b6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://aka.ms/on-demand-capacity-reservations-docs",
- "name": "On-demand Capacity Reservation"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "On-Demand Capacity Reservations ensure recovery of virtual machines in the event of a natural disaster by reserving compute capacity in advance within a specific region or zone. This guarantees that VMs have the necessary resources during disaster recovery failover events thus reducing downtime.\n",
- "pgVerified": true,
- "description": "Reserve Compute Capacity in Disaster Recovery Regions",
- "potentialBenefits": "Guaranteed capacity in disaster recovery regions",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "e7495e1c-0c75-0946-b266-b429b5c7f3bf",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-design-overview#when-to-use-scale-sets-instead-of-virtual-machines",
- "name": "When to use VMSS instead of VMs"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Deploying even single instance VMs into a scale set with Flexible orchestration mode future-proofs applications for scaling and availability. This mode guarantees high availability (up to 1000 VMs) by distributing VMs across fault domains in a region or within an Availability Zone.\n",
- "pgVerified": true,
- "description": "Deploy VMSS with Flex orchestration mode instead of Uniform",
- "potentialBenefits": "Higher scalability and availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all zonal VMs that are NOT deployed with Flex orchestration mode\r\nresources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| where isempty(tostring(tags['aks-managed-poolName']))\r\n| where properties.orchestrationMode != \"Flexible\"\r\n| project recommendationId = \"e7495e1c-0c75-0946-b266-b429b5c7f3bf\", name, id, tags, param1 = strcat(\"orchestrationMode: \", tostring(properties.orchestrationMode))\r\n\r\n"
- },
- {
- "aprlGuid": "94794d2a-eff0-2345-9b67-6f9349d0a627",
- "recommendationTypeId": "3b587048-b04b-4f81-aaed-e43793652b0f",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-health-extension?tabs=rest-api",
- "name": "Using Application Health extension with Virtual Machine Scale Sets"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Monitoring application health in Azure Virtual Machine Scale Sets is crucial for deployment management. It supports rolling upgrades such as automatic OS-image upgrades and VM guest patching, leveraging health monitoring for upgrading.\n",
- "pgVerified": true,
- "description": "Enable Azure Virtual Machine Scale Set Application Health Monitoring",
- "potentialBenefits": "Enhances deployment management and upgrades",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that do NOT have health monitoring enabled\r\nresources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| where isempty(tostring(tags['aks-managed-poolName']))\r\n| join kind=leftouter (\r\n resources\r\n | where type == \"microsoft.compute/virtualmachinescalesets\"\r\n | where isempty(tostring(tags['aks-managed-poolName']))\r\n | mv-expand extension=properties.virtualMachineProfile.extensionProfile.extensions\r\n | where extension.properties.type in ( \"ApplicationHealthWindows\", \"ApplicationHealthLinux\" )\r\n | project id\r\n) on id\r\n| where id1 == \"\"\r\n| project recommendationId = \"94794d2a-eff0-2345-9b67-6f9349d0a627\", name, id, tags, param1 = \"extension: null\"\r\n\r\n"
- },
- {
- "aprlGuid": "820f4743-1f94-e946-ae0b-45efafd87962",
- "recommendationTypeId": "b4d988a9-85e6-4179-b69c-549bdd8a55bb",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-automatic-instance-repairs#requirements-for-using-automatic-instance-repairs",
- "name": "Automatic instance repairs for Azure Virtual Machine Scale Sets"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Enabling automatic instance repairs in Azure Virtual Machine Scale Sets enhances application availability through a continuous health check and maintenance process.\n",
- "pgVerified": true,
- "description": "Enable Automatic Repair Policy on Azure Virtual Machine Scale Sets",
- "potentialBenefits": "Boosts app availability by auto-repair",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs that do NOT have automatic repair policy enabled\r\nresources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| where isempty(tostring(tags['aks-managed-poolName']))\r\n| where properties.automaticRepairsPolicy.enabled == false\r\n| project recommendationId = \"820f4743-1f94-e946-ae0b-45efafd87962\", name, id, tags, param1 = \"automaticRepairsPolicy: Disabled\"\r\n\r\n"
- },
- {
- "aprlGuid": "ee66ff65-9aa3-2345-93c1-25827cf79f44",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-monitor/autoscale/autoscale-get-started?WT.mc_id=Portal-Microsoft_Azure_Monitoring",
- "name": "Get started with autoscale in Azure"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Use custom autoscale for VMSS based on metrics and schedules to improve performance and cost effectiveness, adjusting instances as demand changes.\n",
- "pgVerified": true,
- "description": "Configure VMSS Autoscale to custom and configure the scaling metrics",
- "potentialBenefits": "Enhances performance and cost-efficiency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find VMSS instances associated with autoscale settings when autoscale is disabled\r\nresources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| where isempty(tostring(tags['aks-managed-poolName']))\r\n| project name, id, tags\r\n| join kind=leftouter (\r\n resources\r\n | where type == \"microsoft.insights/autoscalesettings\"\r\n | where tostring(properties.targetResourceUri) contains \"Microsoft.Compute/virtualMachineScaleSets\"\r\n | project id = tostring(properties.targetResourceUri), autoscalesettings = properties\r\n) on id\r\n| where isnull(autoscalesettings) or autoscalesettings.enabled == \"false\"\r\n| project recommendationId = \"ee66ff65-9aa3-2345-93c1-25827cf79f44\", name, id, tags, param1 = \"autoscalesettings: Disabled\"\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "3f85a51c-e286-9f44-b4dc-51d00768696c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-monitor/autoscale/autoscale-predictive",
- "name": "Use predictive autoscale to scale out before load demands in virtual machine scale sets"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Predictive autoscale utilizes machine learning to efficiently manage and scale Azure Virtual Machine Scale Sets by forecasting CPU load through historical usage analysis, ensuring timely scale-out to meet demand.\n",
- "pgVerified": true,
- "description": "Enable Predictive autoscale and configure at least for Forecast Only",
- "potentialBenefits": "Optimizes scaling with ML predictions",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find VMSS instances associated with autoscale settings when predictiveAutoscalePolicy_scaleMode is disabled\r\nresources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| where isempty(tostring(tags['aks-managed-poolName']))\r\n| project name, id, tags\r\n| join kind=leftouter (\r\n resources\r\n | where type == \"microsoft.insights/autoscalesettings\"\r\n | where tostring(properties.targetResourceUri) contains \"Microsoft.Compute/virtualMachineScaleSets\"\r\n | project id = tostring(properties.targetResourceUri), autoscalesettings = properties\r\n) on id\r\n| where autoscalesettings.enabled == \"true\" and autoscalesettings.predictiveAutoscalePolicy.scaleMode == \"Disabled\"\r\n| project recommendationId = \"3f85a51c-e286-9f44-b4dc-51d00768696c\", name, id, tags, param1 = \"predictiveAutoscalePolicy_scaleMode: Disabled\"\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "b5a63aa0-c58e-244f-b8a6-cbba0560a6db",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-scale-in-policy",
- "name": "Use scale-in policies with Azure Virtual Machine Scale Sets"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Microsoft advises disabling strictly even VM instance distribution across Availability Zones in VMSS to improve scalability and flexibility, noting that uneven distribution may better serve application load demands despite the potential trade-off in resilience.\n",
- "pgVerified": true,
- "description": "Disable Force strictly even balance across zones to avoid scale in and out fail attempts",
- "potentialBenefits": "Improves scaling, reduces fail attempts",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find VMSS instances where strictly zoneBalance is set to True\r\nresources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| where properties.orchestrationMode == \"Uniform\" and properties.zoneBalance == true\r\n| project recommendationId = \"b5a63aa0-c58e-244f-b8a6-cbba0560a6db\", name, id, tags, param1 = \"strictly zoneBalance: Enabled\"\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "1422c567-782c-7148-ac7c-5fc14cf45adc",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machine-scale-sets/virtual-machine-scale-sets-use-availability-zones",
- "name": "Create a Virtual Machine Scale Set that uses Availability Zones"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "When creating VMSS, implement availability zones as a protection measure for your applications and data against the rare event of datacenter failure.\n",
- "pgVerified": true,
- "description": "Deploy VMSS across availability zones with VMSS Flex",
- "potentialBenefits": "Enhances disaster resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find VMSS instances with one or no Zones selected\r\nresources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| where isempty(tostring(tags['aks-managed-poolName']))\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where array_length(zones) <= 1 or isnull(zones)\r\n| project recommendationId = \"1422c567-782c-7148-ac7c-5fc14cf45adc\", name, id, tags, param1 = \"AvailabilityZones: Single Zone\"\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "e4ffd7b0-ba24-c84e-9352-ba4819f908c0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/automatic-vm-guest-patching",
- "name": "Automatic VM Guest Patching for Azure VMs"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Enabling automatic VM guest patching eases update management by safely, automatically patching virtual machines to maintain security compliance, while limiting blast radius of VMs. Note, the KQL will not return sets using Uniform orchestration.\n",
- "pgVerified": true,
- "description": "Set Patch orchestration options to Azure-orchestrated",
- "potentialBenefits": "Eases patch management, enhances security",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph query\r\n// Identifies VMs and VMSS with manual patch settings, excluding automatic patch modes\r\nresources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| join kind=inner (\r\n resources\r\n | where type == \"microsoft.compute/virtualmachines\"\r\n | project id = tostring(properties.virtualMachineScaleSet.id), vmproperties = properties\r\n) on id\r\n| extend recommendationId = \"e4ffd7b0-ba24-c84e-9352-ba4819f908c0\", param1 = \"patchMode: Manual\", vmproperties.osProfile.linuxConfiguration.patchSettings.patchMode\r\n| where isnotnull(vmproperties.osProfile.linuxConfiguration) and vmproperties.osProfile.linuxConfiguration.patchSettings.patchMode !in (\"AutomaticByPlatform\", \"AutomaticByOS\")\r\n| distinct recommendationId, name, id, param1\r\n| union (resources\r\n| where type == \"microsoft.compute/virtualmachinescalesets\"\r\n| join kind=inner (\r\n resources\r\n | where type == \"microsoft.compute/virtualmachines\"\r\n | project id = tostring(properties.virtualMachineScaleSet.id), vmproperties = properties\r\n) on id\r\n| extend recommendationId = \"e4ffd7b0-ba24-c84e-9352-ba4819f908c0\", param1 = \"patchMode: Manual\", vmproperties.osProfile.windowsConfiguration.patchSettings.patchMode\r\n| where isnotnull(vmproperties.osProfile.windowsConfiguration) and vmproperties.osProfile.windowsConfiguration.patchSettings.patchMode !in (\"AutomaticByPlatform\", \"AutomaticByOS\")\r\n| distinct recommendationId, name, id, param1)\r\n\r\n"
- },
- {
- "aprlGuid": "83d61669-7bd6-9642-a305-175db8adcdf4",
- "recommendationTypeId": "3b739bd1-c193-4bb6-a953-1362ee3b03b2",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/deprecated-images",
- "name": "Deprecated Azure Marketplace images"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Ensure current versions of images are in use to avoid disruption after image deprecation. Please review the publisher, offer, sku information of the VM to ensure you are running on a supported image. Enable Auto Guest Patching or Image Upgrades, to get notifications about image deprecation.\n",
- "pgVerified": true,
- "description": "Upgrade VMSS Image versions scheduled to be deprecated or already retired",
- "potentialBenefits": "Avoid disruptions by updating VMSS images.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachineScaleSets",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "//cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "eb005943-40a8-194b-9db2-474d430046b7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/container-registry-best-practices",
- "name": "Container Registry Best Practices"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Choose a service tier of Azure Container Registry to meet your performance needs. Premium offers the most bandwidth and highest rate of read and write operations for high-volume deployments. Use Basic to start, Standard for production, and Premium for hyper-scale performance and geo-replication.\n",
- "pgVerified": false,
- "description": "Use Premium tier for critical production workloads",
- "potentialBenefits": "High-volume support and geo-replication",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Container Registries that are not using the Premium tier\r\nresources\r\n| where type =~ \"microsoft.containerregistry/registries\"\r\n| where sku.name != \"Premium\"\r\n| project recommendationId = \"eb005943-40a8-194b-9db2-474d430046b7\", name, id, tags, param1=strcat(\"SkuName: \", tostring(sku.name))\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "63491f70-22e4-3b4a-8b0c-845450e46fac",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/zone-redundancy?toc=%2Fazure%2Freliability%2Ftoc.json&bc=%2Fazure%2Freliability%2Fbreadcrumb%2Ftoc.json&branch=main",
- "name": "Registry best practices - Enable zone redundancy"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Container Registry's optional zone redundancy enhances resiliency and high availability for registries or replication resources in a specific region by distributing resources across multiple zones.\n",
- "pgVerified": false,
- "description": "Enable zone redundancy",
- "potentialBenefits": "Enhances resiliency and high availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Container Registries that do not have zone redundancy enabled\r\nresources\r\n| where type =~ \"microsoft.containerregistry/registries\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where properties.zoneRedundancy != \"Enabled\"\r\n| project recommendationId = \"63491f70-22e4-3b4a-8b0c-845450e46fac\", name, id, tags, param1=strcat(\"zoneRedundancy: \", tostring(properties.zoneRedundancy))\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "36ea6c09-ef6e-d743-9cfb-bd0c928a430b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/container-registry-best-practices#geo-replicate-multi-region-deployments",
- "name": "Registry best practices - Enable geo-replication"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Use Azure Container Registry's geo-replication for multi-region deployments to simplify registry management and minimize latency. It enables serving global customers from local data centers and supports distributed development teams. Regional webhooks can notify of events in replicas.\n",
- "pgVerified": false,
- "description": "Create container registries with geo-replication enabled",
- "potentialBenefits": "Simplifies management, reduces latency",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Container Registries that do not have geo-replication enabled\r\nresources\r\n| where type =~ \"microsoft.containerregistry/registries\"\r\n| project registryName = name, registryId = id, tags, primaryRegion = location\r\n| join kind=leftouter (\r\n Resources\r\n | where type =~ \"microsoft.containerregistry/registries/replications\"\r\n | project replicationRegion=name, replicationId = id\r\n | extend registryId=strcat_array(array_slice(split(replicationId, '/'), 0, -3), '/')\r\n ) on registryId\r\n| project-away registryId1, replicationId\r\n| where isempty(replicationRegion)\r\n| project recommendationId = \"36ea6c09-ef6e-d743-9cfb-bd0c928a430b\", name=registryName, id=registryId, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "a5a0101a-a240-8742-90ba-81dbde9a0c0c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/container-registry-best-practices#repository-namespaces",
- "name": "Registry best practices - use repository namespaces"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Using repository namespaces allows a single registry to be shared across multiple groups and deployments within an organization, supporting nested namespaces for group isolation. However, repositories are managed independently, not hierarchically.\n",
- "pgVerified": false,
- "description": "Use Repository namespaces",
- "potentialBenefits": "Enables sharing and group isolation",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "8e389532-5db5-7e4c-9d4d-443b3e55ae82",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/container-registry-best-practices#dedicated-resource-group",
- "name": "Registry best practices - Use dedicated resource group"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Container registries, used across multiple hosts, should be in their own resource group to prevent accidental deletion of images when container instances are deleted, preserving the image collection while experimenting with hosts.\n",
- "pgVerified": false,
- "description": "Move Container Registry to a dedicated resource group",
- "potentialBenefits": "Safeguards image collection",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// List container registries that contain additional resources within the same resource group.\r\nresources\r\n| where type =~ \"microsoft.containerregistry/registries\"\r\n| project registryName=name, registryId=id, registryTags=tags, resourceGroupId=strcat('/subscriptions/', subscriptionId, '/resourceGroups/', resourceGroup), resourceGroup, subscriptionId\r\n| join kind=inner (\r\n resources\r\n | where not(type =~ \"microsoft.containerregistry/registries\")\r\n | summarize recourceCount=count() by subscriptionId, resourceGroup\r\n | where recourceCount != 0\r\n) on resourceGroup, subscriptionId\r\n| project recommendationId = \"8e389532-5db5-7e4c-9d4d-443b3e55ae82\", name=registryName, id=registryId, tags=registryTags, param1=strcat('resourceGroupName:',resourceGroup), param2=strcat('resourceGroupId:',resourceGroupId)\r\n\r\n"
- },
- {
- "aprlGuid": "3ef86f16-f65b-c645-9901-7830d6dc3a1b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/container-registry-best-practices#manage-registry-size",
- "name": "Registry best practices - Manage registry size"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "The storage constraints of Azure Container Registry's service tiers align with usage scenarios: Basic for starters, Standard for production, and Premium for high-scale performance and geo-replication.\n",
- "pgVerified": false,
- "description": "Manage registry size",
- "potentialBenefits": "Reduce costs, optimize storage",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Container Registries that have their retention policy disabled\r\nresources\r\n| where type =~ \"microsoft.containerregistry/registries\"\r\n| where properties.policies.retentionPolicy.status == \"disabled\"\r\n| project recommendationId = \"3ef86f16-f65b-c645-9901-7830d6dc3a1b\", name, id, tags, param1='retentionPolicy:disabled'\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "03f4a7d8-c5b4-7842-8e6e-14997a34842b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/anonymous-pull-access#about-anonymous-pull-access",
- "name": "Enable anonymous pull access"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "By default, Azure container registry requires authentication for pull/push actions. Enabling anonymous pull access exposes all content for public read actions. This applies to all repositories, potentially allowing unrestricted access if repository-scoped tokens are used.\n",
- "pgVerified": false,
- "description": "Disable anonymous pull access",
- "potentialBenefits": "Enhanced security and controlled access",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Container Registries that have anonymous pull access enabled\r\nresources\r\n| where type =~ \"microsoft.containerregistry/registries\"\r\n| where properties.anonymousPullEnabled == \"true\"\r\n| project recommendationId = \"03f4a7d8-c5b4-7842-8e6e-14997a34842b\", name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "44107155-7a32-9348-89f3-d5aa7e7c5a1d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/monitor-service#collection-and-routing",
- "name": "Monitor Azure Container Registry - Enable diagnostic logs"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Resource Logs are not collected and stored until you create a diagnostic setting and route them to one or more locations.\n",
- "pgVerified": false,
- "description": "Configure Diagnostic Settings for all Azure Container Registries",
- "potentialBenefits": "Enhanced tracking and debugging",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "d594cde6-4116-d143-a64a-25f63289a2f8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/monitor-service",
- "name": "Monitor Azure Container Registry"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Monitoring Azure resources using Azure Monitor enhances their availability, performance, and operation. Azure Container Registry, a full-stack monitoring service, provides features for Azure and other cloud and on-premises resources.\n",
- "pgVerified": false,
- "description": "Monitor Azure Container Registry with Azure Monitor",
- "potentialBenefits": "Enhanced monitoring and operation",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "e7f0fd54-fba0-054e-9ab8-e676f2851f88",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/container-registry/container-registry-soft-delete-policy",
- "name": "Enable soft delete policy"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Enabling soft delete preview feature in Azure Container Registry (ACR) allows for the management of deleted artifacts with a specified retention period. Users can list, filter, and restore these artifacts until automatically purged post-retention.\n",
- "pgVerified": false,
- "description": "Enable soft delete policy",
- "potentialBenefits": "Recovery of deleted artifacts",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerRegistry/registries",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure Container Registry resources that do not have soft delete enabled\r\nresources\r\n| where type =~ \"microsoft.containerregistry/registries\"\r\n| where properties.policies.softDeletePolicy.status == \"disabled\"\r\n| project recommendationId = \"e7f0fd54-fba0-054e-9ab8-e676f2851f88\", name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "4f63619f-5001-439c-bacb-8de891287727",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/aks/availability-zones",
- "name": "AKS Availability Zones"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Availability Zones ensure high availability by offering independent locations within regions, equipped with their own power, cooling, and networking to ensure applications and data are protected from datacenter-level failures.\n",
- "pgVerified": true,
- "description": "Deploy AKS cluster across availability zones",
- "potentialBenefits": "Enhanced fault tolerance for AKS",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns AKS clusters that do not have any availability zones enabled or only use a single zone\r\nresources\r\n| where type =~ \"Microsoft.ContainerService/managedClusters\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| project id, name, tags, location, pools = properties.agentPoolProfiles\r\n| mv-expand pool = pools\r\n| extend\r\n numOfAvailabilityZones = iif(isnull(pool.availabilityZones), 0, array_length(pool.availabilityZones))\r\n| where numOfAvailabilityZones < 2\r\n| project\r\n recommendationId = \"4f63619f-5001-439c-bacb-8de891287727\",\r\n id,\r\n name,\r\n tags,\r\n param1 = strcat(\"NodePoolName: \", pool.name),\r\n param2 = strcat(\"Mode: \", pool.mode),\r\n param3 = strcat(\"AvailabilityZones: \", iif(numOfAvailabilityZones == 0, \"None\", strcat(\"Zone \", strcat_array(pool.availabilityZones, \", \")))),\r\n param4 = strcat(\"Location: \", location)\r\n"
- },
- {
- "aprlGuid": "5ee083cd-6ac3-4a83-8913-9549dd36cf56",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/aks/use-system-pools?tabs=azure-cli#system-and-user-node-pools",
- "name": "System and user node pools"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "AKS assigns the kubernetes.azure.com/mode: system label to nodes in system node pools signaling the preference for system pods should be scheduled there. The CriticalAddonsOnly=true:NoSchedule taint can be added to your system nodes to prohibit application pods from being scheduled on them.\n",
- "pgVerified": false,
- "description": "Isolate system and application pods",
- "potentialBenefits": "Enhanced reliability via pod isolation",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns each AKS cluster with nodepools that do not have system pods labelled with CriticalAddonsOnly\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\r\n| where agentPoolProfile.mode =~ 'System' // system node pools\r\n| extend taint = tostring(parse_json(agentPoolProfile.nodeTaints))\r\n| extend hasCriticalAddonsTaint = agentPoolProfile.kubeletConfig has 'CriticalAddonsOnly'\r\n| extend hasNodeLabel = agentPoolProfile.customNodeLabels has 'CriticalAddonsOnly'\r\n| extend hasCriticalAddonsOnly = hasCriticalAddonsTaint or hasNodeLabel or isempty(taint)\r\n| extend nodePool = tostring(parse_json(agentPoolProfile.name))\r\n| where hasCriticalAddonsOnly\r\n| project\r\n recommendationId=\"5ee083cd-6ac3-4a83-8913-9549dd36cf56\",\r\n id,\r\n name,\r\n tags,\r\n param1=strcat(\"nodepoolName: \", nodePool)\r\n"
- },
- {
- "aprlGuid": "ca324d71-54b0-4a3e-b9e4-10e767daa9fc",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/aks/concepts-identity#azure-ad-integration",
- "name": "Entra integration"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Local Kubernetes accounts in AKS, being non-auditable and legacy, are discouraged. Microsoft Entra's integration offers centralized management, multi-factor authentication, RBAC for detailed access, and a secure, scalable authentication system compatible with Azure and external identity providers.\n",
- "pgVerified": false,
- "description": "Disable local accounts",
- "potentialBenefits": "Enhanced security and access control",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns a list of AKS clusters not using AAD enabled\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| extend aadProfile = tostring (parse_json(properties.aadProfile))\r\n| extend disablelocalAdmin = tostring(parse_json(properties.disableLocalAccounts))\r\n| extend RBAC = tostring(parse_json(properties.enableRBAC))\r\n| where RBAC == \"false\"\r\n| project recommendationId=\"ca324d71-54b0-4a3e-b9e4-10e767daa9fc\", name, id, tags, param1=strcat(\"aadProfile: \", aadProfile), param2=strcat(\"disablelocalAdmin: \",disablelocalAdmin), param3=strcat(\"RBAC: \", RBAC)\r\n\r\n"
- },
- {
- "aprlGuid": "c22db132-399b-4e7c-995d-577a60881be8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/aks/configure-azure-cni-dynamic-ip-allocation",
- "name": "Configure Azure CNI networking"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Azure CNI enhances cluster IP and network management, allowing dynamic IP allocation, scalable subnets, direct pod-VNET connectivity, and supports diverse network policies for pods and nodes with Azure Network Policies and Calico, optimizing network efficiency and security\n",
- "pgVerified": false,
- "description": "Configure Azure CNI networking for dynamic allocation of IPs or use CNI overlay",
- "potentialBenefits": "Dynamic IP allocation, scalable subnets, direct VNET access",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Check AKS Clusters using kubenet network profile\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| extend networkProfile = tostring (parse_json(properties.networkProfile.networkPlugin))\r\n| where networkProfile ==\"kubenet\"\r\n| project recommendationId=\"c22db132-399b-4e7c-995d-577a60881be8\", name, id, tags, param1=strcat(\"networkProfile :\",networkProfile)\r\n\r\n"
- },
- {
- "aprlGuid": "902c82ff-4910-4b61-942d-0d6ef7f39b67",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/cluster-autoscaler?tabs=azure-cli",
- "name": "Use the Cluster Autoscaler on AKS"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "The cluster auto-scaler in AKS adjusts node counts based on pod resource needs and available capacity, enabling scaling as per demand to prevent outages.\n",
- "pgVerified": true,
- "description": "Enable the cluster auto-scaler on an existing cluster",
- "potentialBenefits": "Optimizes scaling and prevents outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find AKS clusters with auto-scaling disabled\r\nResources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| extend autoScaling = tostring (parse_json(properties.agentPoolProfiles.[0].enableAutoScaling))\r\n| where autoScaling == \"false\"\r\n| project recommendationId=\"902c82ff-4910-4b61-942d-0d6ef7f39b67\", name, id, tags, param1=strcat(\"autoScaling :\", autoScaling)\r\n\r\n"
- },
- {
- "aprlGuid": "269a9f1a-6675-460a-831e-b05a887a8c4b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/backup/azure-kubernetes-service-cluster-backup",
- "name": "AKS Backups"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "AKS, popular for stateful apps needing backups, can now use Azure Backup to secure clusters and attached volumes through an installed Backup Extension, enabling backup and restore operations via a Backup Vault.\n",
- "pgVerified": true,
- "description": "Back up Azure Kubernetes Service",
- "potentialBenefits": "Ensures data safety for AKS",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find AKS clusters that do not have backup enabled\r\n\r\nresources\r\n| where type =~ 'Microsoft.ContainerService/managedClusters'\r\n| extend lname = tolower(name)\r\n| join kind=leftouter(recoveryservicesresources\r\n | where type =~ 'microsoft.dataprotection/backupvaults/backupinstances'\r\n | extend lname = tolower(tostring(split(properties.dataSourceInfo.resourceID, '/')[8]))\r\n | extend protectionState = properties.currentProtectionState\r\n | project lname, protectionState) on lname\r\n| where protectionState != 'ProtectionConfigured'\r\n| extend param1 = iif(isnull(protectionState), 'Protection Not Configured', strcat('Protection State: ', protectionState))\r\n| project recommendationId = \"269a9f1a-6675-460a-831e-b05a887a8c4b\", name, id, tags, param1\r\n\r\n"
- },
- {
- "aprlGuid": "d3111036-355d-431b-ab49-8ddad042800b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/reliability/availability-zones-overview?tabs=azure-cli",
- "name": "Availability zones overview"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "ZRS ensures data replication across three zones, protecting against zonal outages. It's available for Azure Disks, Container Storage, Files, and Blob by setting the SKU to ZRS in storage classes, enhancing multi-zone AKS clusters from v1.29.\n",
- "pgVerified": true,
- "description": "Use zone-redundant storage for persistent volumes when running multi-zone AKS",
- "potentialBenefits": "Increases data durability and availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "b002c030-72e6-4a37-8217-1cb276c43169",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/csi-storage-drivers",
- "name": "CSI Storage Drivers"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "From Kubernetes 1.26, Azure Disk and Azure File in-tree drivers are deprecated in favor of CSI drivers. Existing deployments remain operational but untested; users should switch to CSI drivers for new features and SKUs.\n",
- "pgVerified": true,
- "description": "Upgrade Persistent Volumes using in-tree drivers to Azure CSI drivers",
- "potentialBenefits": "Ensures future compatibility",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "9a1c17e5-c9a0-43db-b920-adaf54d1bcb7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://kubernetes.io/docs/concepts/policy/resource-quotas/",
- "name": "Resource Quotas"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "A ResourceQuota object sets limits on resource use per namespace, controlling the number and type of objects created, and the total compute resources available.\n",
- "pgVerified": false,
- "description": "Implement Resource Quota to ensure that Kubernetes resources do not exceed hard resource limits",
- "potentialBenefits": "Limits AKS resource usage per namespace",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "b4639ca7-6308-429a-8b98-92f0bf9bf813",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/virtual-nodes",
- "name": "Virtual Nodes"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "To rapidly scale AKS workloads, utilize virtual nodes for quick pod provisioning, unlike Kubernetes auto-scaler. For clusters with availability zones, ensure one nodepool per AZ due to persistent volumes not working across AZs, preventing auto-scaler pod creation failures if lacking access.\n",
- "pgVerified": false,
- "description": "Attach Virtual Nodes (ACI) to the AKS cluster",
- "potentialBenefits": "Faster scaling with virtual nodes",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "0611251f-e70f-4243-8ddd-cfe894bec2e7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/aks/free-standard-pricing-tiers",
- "name": "Pricing Tiers"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Production AKS clusters require the Standard or Premium tier for a financially backed SLA and enhanced node scalability, as the free service lacks these features. Use the Premium tier for mission-critical workloads.\n",
- "pgVerified": true,
- "description": "Update AKS tier to Standard or Premium",
- "potentialBenefits": "SLA guarantee and better scalability",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns all AKS clusters not running on the Standard tier or the Premium tier.\r\nresources\r\n| where type =~ \"Microsoft.ContainerService/managedClusters\"\r\n| where sku.tier !in~ (\"Standard\", \"Premium\")\r\n| project recommendationId = \"0611251f-e70f-4243-8ddd-cfe894bec2e7\", id, name, tags, param1 = strcat(\"skuName: \", sku.name), param2 = strcat(\"skuTier: \", sku.tier)\r\n"
- },
- {
- "aprlGuid": "dcaf8128-94bd-4d53-9235-3a0371df6b74",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/monitor-aks",
- "name": "Monitor AKS"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Azure Monitor enables real-time health and performance insights for AKS by collecting events, capturing container logs, and gathering CPU/Memory data from the Metrics API. It allows data visualization using Azure Monitor Container Insights, Prometheus, Grafana, or others.\n",
- "pgVerified": true,
- "description": "Enable AKS Monitoring",
- "potentialBenefits": "Real-time AKS health/performance insights",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns AKS clusters where either Azure Monitor is not enabled and/or Container Insights is not enabled\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| extend azureMonitor = tostring(parse_json(properties.azureMonitorProfile.metrics.enabled))\r\n| extend insights = tostring(parse_json(properties.addonProfiles.omsagent.enabled))\r\n| where isempty(azureMonitor) or isempty(insights)\r\n| project recommendationId=\"dcaf8128-94bd-4d53-9235-3a0371df6b74\",id, name, tags, param1=strcat(\"azureMonitorProfileEnabled: \", iff(isempty(azureMonitor), \"false\", azureMonitor)), param2=strcat(\"containerInsightsEnabled: \", iff(isempty(insights), \"false\", insights))\r\n\r\n"
- },
- {
- "aprlGuid": "a7bfcc18-b0d8-4d37-81f3-8131ed8bead5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/concepts-storage#ephemeral-os-disk",
- "name": "Ephemeral OS disk"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Ephemeral OS disks on AKS offer lower read/write latency due to local attachment, eliminating the need for replication seen with managed disks. This enhances performance and speeds up cluster operations such as scaling or upgrading due to quicker re-imaging and boot times.\n",
- "pgVerified": true,
- "description": "Use Ephemeral OS disks on AKS clusters",
- "potentialBenefits": "Lower latency, faster re-imaging and booting",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns any AKS cluster nodepools that do not have Ephemeral Disks\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\r\n| extend type = tostring(agentPoolProfile.osDiskType)\r\n| where type != 'Ephemeral'\r\n| project recommendationId=\"a7bfcc18-b0d8-4d37-81f3-8131ed8bead5\", name, id, param1=strcat(\"osDiskType: \", type)\r\n"
- },
- {
- "aprlGuid": "26ebaf1f-c70d-4ebd-8641-4b60a0ce0094",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/architecture/reference-architectures/containers/aks/baseline-aks?toc=https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fazure%2Faks%2Ftoc.json&bc=https%3A%2F%2Flearn.microsoft.com%2Fen-us%2Fazure%2Fbread%2Ftoc.json#policy-management",
- "name": "AKS Baseline - Policy Management"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Azure Policies in AKS clusters help enforce governance best practices concerning security, authentication, provisioning, networking, and more, ensuring a robust and secure environment for operations.\n",
- "pgVerified": false,
- "description": "Enable and remediate Azure Policies configured for AKS",
- "potentialBenefits": "Enhanced AKS governance and security",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns a count of non-compliant policy items per AKS cluster\r\nPolicyResources\r\n| where type =~ 'Microsoft.PolicyInsights/PolicyStates'\r\n| extend complianceState = tostring(properties.complianceState)\r\n| where complianceState == 'NonCompliant'\r\n| where properties.resourceType =~ 'Microsoft.ContainerService/managedClusters'\r\n| extend\r\n id = tostring(properties.resourceId)\r\n| summarize count() by id\r\n| join kind=inner (\r\n resources\r\n | where type =~ 'Microsoft.ContainerService/managedClusters'\r\n | project id, name\r\n) on id\r\n| project recommendationId=\"26ebaf1f-c70d-4ebd-8641-4b60a0ce0094\", id, name, param1=strcat(\"numNonCompliantAlerts: \", count_)\r\n"
- },
- {
- "aprlGuid": "5f3cbd68-692a-4121-988c-9770914859a9",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/architecture/guide/aks/aks-cicd-github-actions-and-gitops",
- "name": "GitOps with AKS"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "GitOps, an operating model for cloud-native apps, uses Git for storing application and infrastructure code as a source of truth for continuous delivery.\n",
- "pgVerified": false,
- "description": "Enable GitOps when using DevOps frameworks",
- "potentialBenefits": "Ensures AKS config consistency",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns AKS clusters where GitOps is not enabled\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| extend gitops = tostring (parse_json(properties.addOnProfiles.gitops.enabled))\r\n| where isempty(gitops)\r\n| project recommendationId=\"5f3cbd68-692a-4121-988c-9770914859a9\", id, name, tags, param1=strcat(\"gitopsEnabled: \", \"false\")\r\n\r\n"
- },
- {
- "aprlGuid": "928fcc6f-5e9a-42d9-9bd4-260af42de2e5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/",
- "name": "Topology Spread Constraints"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Enhance availability and reliability by using pod topology spread constraints to control pod distribution based on node or zone topology, ensuring pods are spread across your cluster.\n",
- "pgVerified": true,
- "description": "Use pod topology spread constraints to ensure that pods are spread across different nodes or zones",
- "potentialBenefits": "Ensures high availability and efficient use",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "cd6791b1-c60e-4b37-ac98-9897b1e6f4b8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/",
- "name": "Configure probes"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "AKS kubelet controller uses liveness probes to validate containers and applications health, ensuring the system knows when to restart a container based on its health status.\n",
- "pgVerified": true,
- "description": "Configures Pods Liveness, Readiness, and Startup Probes",
- "potentialBenefits": "Enhances container health monitoring",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "bcfe71f1-ebed-49e5-a84a-193b81ad5d27",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://kubernetes.io/docs/concepts/workloads/controllers/replicaset/",
- "name": "Replica Sets"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Configuring multiple replicas in Pod or Deployment manifests stabilizes the number of replica Pods, ensuring that a specified number of identical Pods are always available, thereby guaranteeing their availability.\n",
- "pgVerified": true,
- "description": "Use deployments with multiple replicas in production applications to guarantee availability",
- "potentialBenefits": "Ensures stable pod availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "7f7ae535-a5ba-4665-b7e0-c451dbdda01f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/use-system-pools?tabs=azure-cli",
- "name": "System nodepools"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "The system node pool should be configured with a minimum node count of two to ensure critical system pods are resilient to node outages.\n",
- "pgVerified": true,
- "description": "Configure system nodepool count",
- "potentialBenefits": "Ensures pod resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns each AKS cluster with nodepools that have system nodepools with less than 2 nodes\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\r\n| extend taints = tostring(parse_json(agentPoolProfile.nodeTaints))\r\n| extend nodePool = tostring(parse_json(agentPoolProfile.name))\r\n| where taints has \"CriticalAddonsOnly=true:NoSchedule\" and agentPoolProfile.minCount < 2\r\n| project recommendationId=\"7f7ae535-a5ba-4665-b7e0-c451dbdda01f\", id, name, param1=strcat(\"nodePoolName: \", nodePool), param2=strcat(\"nodePoolMinNodeCount: \", agentPoolProfile.minCount)\r\n\r\n"
- },
- {
- "aprlGuid": "005ccbbd-aeab-46ef-80bd-9bd4479412ec",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/service-guides/azure-kubernetes-service#design-checklist",
- "name": "Azure Well-Architected Framework review for Azure Kubernetes Service (AKS)"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Configuring the user node pool with at least two nodes is essential for applications needing high availability, ensuring they remain operational and accessible without interruption.\n",
- "pgVerified": true,
- "description": "Configure user nodepool count",
- "potentialBenefits": "Ensures high app availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns each AKS cluster with nodepools that have user nodepools with less than 2 nodes\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\r\n| extend taints = tostring(parse_json(agentPoolProfile.nodeTaints))\r\n| extend nodePool = tostring(parse_json(agentPoolProfile.name))\r\n| where taints !has \"CriticalAddonsOnly=true:NoSchedule\" and agentPoolProfile.minCount < 2\r\n| project recommendationId=\"005ccbbd-aeab-46ef-80bd-9bd4479412ec\", id, name, param1=strcat(\"nodePoolName: \", nodePool), param2=strcat(\"nodePoolMinNodeCount: \", agentPoolProfile.minCount)\r\n\r\n"
- },
- {
- "aprlGuid": "a08a06a0-e41a-4b99-83bb-69ce8bca54cb",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://kubernetes.io/docs/tasks/run-application/configure-pdb/",
- "name": "Configure PDBs"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "A Pod Disruption Budget is a Kubernetes resource configuring the minimum number or percentage of pods that should remain available during disruptions like maintenance or scaling, ensuring a minimum number of pods are always available in the cluster.\n",
- "pgVerified": true,
- "description": "Configure pod disruption budgets (PDBs)",
- "potentialBenefits": "Ensures cluster resiliency during disruptions",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "e620fa98-7a40-41a0-bfc9-b4407297fb58",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/configure-azure-cni-dynamic-ip-allocation",
- "name": "Azure CNI Dynamic IP Allocation"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Nodepool subnets sized for max auto-scale settings enable AKS to efficiently scale out nodes, meeting increased demand while reducing resource constraints and potential service disruptions.\n",
- "pgVerified": false,
- "description": "Nodepool subnet size needs to accommodate maximum auto-scale settings",
- "potentialBenefits": "Efficient scaling, reduced disruptions",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns each AKS cluster with nodepools that have user nodepools with a subnetmask that does not match autoscale configured max-nodes\r\n// Subtracting the network address, broadcast address, and default 3 addresses Azure reserves within each subnet\r\n\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| extend nodePools = properties['agentPoolProfiles']\r\n| mv-expand nodePools = properties.agentPoolProfiles\r\n| where nodePools.enableAutoScaling == true\r\n| extend nodePoolName=nodePools.name, maxNodes = nodePools.maxCount, subnetId = tostring(nodePools.vnetSubnetID)\r\n| project clusterId = id, clusterName=name, nodePoolName=nodePools.name, toint(maxNodes), subnetId\r\n| join kind = leftouter (\r\n resources\r\n | where type == 'microsoft.network/virtualnetworks'\r\n | extend subnets = properties.subnets\r\n | mv-expand subnets\r\n | project id = tostring(subnets.id), addressPrefix = tostring(subnets.properties['addressPrefix'])\r\n | extend subnetmask = toint(substring(addressPrefix, indexof(addressPrefix, '/')+1, string_size(addressPrefix)))\r\n | extend possibleMaxNodeCount = toint(exp2(32-subnetmask) - 5)\r\n) on $left.subnetId == $right.id\r\n| project-away id, subnetmask\r\n| where possibleMaxNodeCount <= maxNodes\r\n| extend param1 = strcat(nodePoolName, \" autoscaler upper limit: \", maxNodes)\r\n| extend param2 = strcat(\"ip addresses on subnet: \", possibleMaxNodeCount)\r\n| project recommendationId=\"e620fa98-7a40-41a0-bfc9-b4407297fb58\", name=clusterName, id=clusterId, param1, param2\r\n\r\n"
- },
- {
- "aprlGuid": "a01afc4c-7439-4919-b2da-3565992ea2a7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/quotas/quotas-overview",
- "name": "Azure Quotas"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Node pool settings should not exceed the subscription core quota to ensure AKS can scale out nodes efficiently, meeting increased demand while reducing resource constraints and potential service disruptions.\n",
- "pgVerified": false,
- "description": "Subscription core quota should be increased if Node pool auto-scale settings exceed the quota",
- "potentialBenefits": "Reduced disruptions",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "f46b0d1d-56ef-4795-b98a-f6ee00cb341a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/use-azure-linux",
- "name": "Azure Linux"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Linux on AKS boosts resiliency with a native image using validated, source-built components. It's lightweight, reducing the attack surface and maintenance. A Microsoft-hardened kernel, optimized for Azure, enhances stability and security for container workloads.\n",
- "pgVerified": false,
- "description": "Use Azure Linux for Linux nodepools",
- "potentialBenefits": "Reduced disruptions",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Returns each AKS cluster with nodepools that have Linux nodepools not using Azure Linux\r\nresources\r\n| where type == \"microsoft.containerservice/managedclusters\"\r\n| mv-expand agentPoolProfile = properties.agentPoolProfiles\r\n| where agentPoolProfile.osType == 'Linux' and agentPoolProfile.osSKU != 'AzureLinux'\r\n| project recommendationid=\"f46b0d1d-56ef-4795-b98a-f6ee00cb341a\", name, id, param1=strcat(\"nodePoolName: \", agentPoolProfile.name)\r\n"
- },
- {
- "aprlGuid": "9200aca6-0e83-4749-a5eb-e3939367bdc2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/aks/best-practices-app-cluster-reliability#multi-replica-applications",
- "name": "Multi-replica apps"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Deploying at least two replicas of your application ensures that your application is highly available and can tolerate node failures.\n",
- "pgVerified": false,
- "description": "Deploy at least two replicas of your application",
- "potentialBenefits": "Ensures high app availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.ContainerService/managedClusters",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "6cd57b65-ef84-4088-9ada-c0d8de74c2f7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/Azure/managed-grafana/how-to-enable-zone-redundancy",
- "name": "Enable zone redundancy in Azure Managed Grafana"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Managed Grafana Standard tier is hosted on a dedicated set of VMs to provide redundancy. With zone redundancy enabled, VMs are spread across availability zones (AZ). Related resources are also configured for AZ. Zone redundancy can only be enabled when creating the Azure Managed Grafana instance.\n",
- "pgVerified": false,
- "description": "Enable zone redundancy in Managed Grafana",
- "potentialBenefits": "Enhanced Managed Grafana resilience to failures",
- "tags": null,
- "recommendationResourceType": "Microsoft.Dashboard/grafana",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure Managed Grafana resources that do not zone redundancy enabled.\r\nresources\r\n| where type =~ \"Microsoft.Dashboard/grafana\"\r\n| extend zoneRedundancy = properties.zoneRedundancy\r\n| where zoneRedundancy !~ \"Enabled\"\r\n| project\r\n recommendationId = \"6cd57b65-ef84-4088-9ada-c0d8de74c2f7\",\r\n name,\r\n id,\r\n tags,\r\n param1 = strcat(\"location: \", location),\r\n param2 = strcat(\"sku: \", sku.name),\r\n param3 = strcat(\"zoneRedundancy: \", zoneRedundancy)\r\n"
- },
- {
- "aprlGuid": "0e835cc2-2551-a247-b1f1-3c5f25c9cb70",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/release-notes/runtime/databricks-runtime-ver",
- "name": "Databricks runtime support lifecycles"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Databricks recommends migrating workloads to the latest or LTS version of its runtime for enhanced stability and support. If on Runtime 11.3 LTS or above, move directly to the latest 12.x version. If below, first migrate to 11.3 LTS, then to the latest 12.x version as per the migration guide.\n",
- "pgVerified": true,
- "description": "Databricks runtime version is not latest or is not LTS version",
- "potentialBenefits": "Enhanced stability and support",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "5877a510-8444-7a4c-8412-a8dab8662f7e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-machines/disks-types#premium-ssd",
- "name": "Azure managed disk types"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Upgrade HDDs in premium VMs to SSDs for better speed and reliability. Premium SSDs boost IO-heavy apps; Standard SSDs balance cost and performance. Ideal for critical workloads, upgrading improves connectivity with brief reboot. Consider for vital VMs\n",
- "pgVerified": true,
- "description": "Use SSD backed VMs for Worker VM Type and Driver type",
- "potentialBenefits": "Faster, reliable VM performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "5c72f0d6-55ec-d941-be84-36c194fa78c0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices#enable-autoscaling-for-batch-workloadss",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Autoscaling adjusts cluster sizes automatically based on workload demands, offering benefits for many use cases in terms of costs and performance. It includes guidance on when and how to best utilize Autoscaling. For streaming, Delta Live Tables with autoscaling is advised.\n",
- "pgVerified": true,
- "description": "Enable autoscaling for batch workloads",
- "potentialBenefits": "Cost and performance optimization",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "362ad2b6-b92c-414f-980a-0cf69467ccce",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices#enable-autoscaling-for-sql-warehouse",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "The scaling parameter of a SQL warehouse defines the min and max number of clusters for distributing queries. By default, it's set to one. Increasing the cluster count can accommodate more concurrent users effectively.\n",
- "pgVerified": true,
- "description": "Enable autoscaling for SQL warehouse",
- "potentialBenefits": "Improves concurrency and efficiency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "cd77db98-9b13-6e4b-bd2b-74c2cb538628",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/databricks/delta-live-tables/settings#use-autoscaling-to-increase-efficiency-and-reduce-resource-usage",
- "name": "Databricks enhanced autoscaling"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Databricks enhanced autoscaling optimizes cluster utilization by automatically allocating cluster resources based on workload volume, with minimal impact on the data processing latency of your pipelines.\n",
- "pgVerified": true,
- "description": "Use Delta Live Tables enhanced autoscaling",
- "potentialBenefits": "Optimized resource use and minimal latency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "3d3e53b5-ebd1-db42-b43b-d4fad74824ec",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "To conserve cluster resources, you can terminate a cluster to store its configuration for future reuse or autostart jobs. Clusters can auto-terminate after inactivity, but this only tracks Spark jobs, not local processes, which might still be running even after Spark jobs end.\n",
- "pgVerified": true,
- "description": "Automatic Job Termination is enabled, ensure there are no user-defined local processes",
- "potentialBenefits": "Saves cluster resources, avoids idle use",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "7fb90127-5364-bb4d-86fa-30778ed713fb",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/clusters/configure#cluster-log-delivery",
- "name": "Create a cluster"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "When creating a Databricks cluster, you can set a log delivery location for the Spark driver, worker nodes, and events. Logs are delivered every 5 mins and archived hourly. Upon cluster termination, all generated logs until that point are guaranteed to be delivered.\n",
- "pgVerified": true,
- "description": "Enable Logging-Cluster log delivery",
- "potentialBenefits": "Improved troubleshooting and audit",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "da4ea916-4df3-8c4d-8060-17b49da45977",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Delta Lake is an open source storage format enhancing data lakes' reliability with ACID transactions, schema enforcement, and scalable metadata handling.\n",
- "pgVerified": true,
- "description": "Use Delta Lake for higher reliability",
- "potentialBenefits": "Enhances data reliability and processing",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "7e52d64d-8cc0-8548-a593-eb49ab45630d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "BusinessContinuity",
- "longDescription": "Invalid or nonconforming data can crash workloads dependent on specific data formats. Best practices recommend filtering such data at ingestion to improve end-to-end resilience, ensuring no data is lost or missed.\n",
- "pgVerified": true,
- "description": "Automatically rescue invalid or nonconforming data with Databricks Auto Loader or Delta Live Tables",
- "potentialBenefits": "Enhanced data resilience and integrity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "84e44da6-8cd7-b349-b02c-c8bf72cf587c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use Databricks and MLflow for deploying models as Spark UDFs for job scheduling, retries, autoscaling. Model serving offers scalable infrastructure, processes models using MLflow, and serves them via REST API using serverless compute managed in Databricks cloud.\n",
- "pgVerified": true,
- "description": "Configure jobs for automatic retries and termination",
- "potentialBenefits": "Enhanced reliability and autoscaling",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "4cbb7744-ff3d-0447-badb-baf068c95696",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Use Databricks and MLflow for deploying models as Apache Spark UDFs, benefiting from job scheduling, retries, autoscaling, etc.\n",
- "pgVerified": true,
- "description": "Use a scalable and production-grade model serving infrastructure",
- "potentialBenefits": "Enhances scalability and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1b0d0893-bf0e-8f4c-9dc6-f18f145c1ecf",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Curate data by creating a layered architecture to increase data quality across layers. Start with a raw layer for ingested source data, continue with a curated layer for cleansed and refined data, and finish with a final layer catered to business needs, focusing on security and performance.\n",
- "pgVerified": true,
- "description": "Use a layered storage architecture",
- "potentialBenefits": "Enhances data quality and trust",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "e93fe702-e385-d741-ba37-1f1656482ecd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "BusinessContinuity",
- "longDescription": "Copying data leads to redundancy, lost integrity, lineage, and access issues, affecting lakehouse data quality. Temporary copies are useful for agility and innovation but can become problematic operational data silos, questioning data's master status and currency.\n",
- "pgVerified": true,
- "description": "Improve data integrity by reducing data redundancy",
- "potentialBenefits": "Enhanced data integrity and quality",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "b7e1d13f-54c9-1648-8a52-34c0abe8ce16",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Uncontrolled schema changes can lead to invalid data and failing jobs. Databricks validates and enforces schema through Delta Lake, which prevents bad records during ingestion, and Auto Loader, which detects new columns and supports schema evolution to maintain data integrity.\n",
- "pgVerified": true,
- "description": "Actively manage schemas",
- "potentialBenefits": "Prevents invalid data and job failures",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "a42297c4-7e4f-8b41-8d4b-114033263f0e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices#use-constraints-and-data-expectations",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "BusinessContinuity",
- "longDescription": "Delta tables verify data quality automatically with SQL constraints, triggering an error for violations. Delta Live Tables enhance this by defining expectations for data quality, utilizing Python or SQL, to manage actions for record failures, ensuring data integrity and compliance.\n",
- "pgVerified": true,
- "description": "Use constraints and data expectations",
- "potentialBenefits": "Ensures data quality and integrity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "932d45d6-b46d-e341-abfb-d97bce832f1f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices#create-regular-backups",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "To recover from a failure, regular backups are needed. The Databricks Labs project migrate lets admins create backups by exporting workspace assets using the Databricks CLI/API. These backups help in restoring or migrating workspaces.\n",
- "pgVerified": true,
- "description": "Create regular backups",
- "potentialBenefits": "Ensures data recovery and migration",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "12e9d852-5cdc-2743-bffe-ee21f2ef7781",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices#recover-from-structured-streaming-query-failures",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Structured Streaming ensures fault-tolerance and data consistency in streaming queries. With Azure Databricks workflows, you can set up your queries to automatically restart after failure, picking up precisely where they left off.\n",
- "pgVerified": true,
- "description": "Recover from Structured Streaming query failures",
- "potentialBenefits": "Fault-tolerance and auto-restart for queries",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "a18d60f8-c98c-ba4e-ad6e-2fac72879df1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices#recover-etl-jobs-based-on-delta-time-travel",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Despite thorough testing, a production job can fail or yield unexpected data. Sometimes, repairs are done by adding jobs post-issue identification and pipeline correction.\n",
- "pgVerified": true,
- "description": "Recover ETL jobs based on Delta time travel",
- "potentialBenefits": "Easy rollback and fix for ETL jobs",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "c0e22580-3819-444d-8546-a80e4ed85c83",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Databricks Workflows enable efficient error recovery in multi-task jobs by offering a matrix view for issue examination. Fixes can be applied to initiate repair runs targeting only failed and dependent tasks, preserving successful outcomes and thereby saving time and money.\n",
- "pgVerified": true,
- "description": "Use Databricks Workflows and built-in recovery",
- "potentialBenefits": "Saves time and money with smart recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "4fdb7112-4531-6f48-b60e-c917a6068d9b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://github.com/Azure/AzureDatabricksBestPractices/tree/master",
- "name": "Azure Databricks Best Practices"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Implementing a disaster recovery pattern is vital for Azure Databricks, ensuring data teams' access even during rare regional outages.\n\nIt is important to note that the Azure Databricks service is not entirely zone redudant and does support zonal failover.\n",
- "pgVerified": false,
- "description": "Configure a disaster recovery pattern",
- "potentialBenefits": "Ensures service continuity during disasters",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "42aedaa8-6151-424d-b782-b8666c779969",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/operational-excellence/best-practices#2-automate-deployments-and-workloads",
- "name": "Best practices for operational excellence"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "The Databricks Terraform provider manages Azure Databricks workspaces and cloud infrastructure flexibly and powerfully.\n",
- "pgVerified": false,
- "description": "Automate deployments and workloads",
- "potentialBenefits": "Efficient, reliable automation",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "20193ff9-dbcd-a74e-b197-71d7d9d3c1e6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/operational-excellence/best-practices#system-monitoring",
- "name": "Best practices for operational excellence"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "The Databricks Terraform provider is a flexible, powerful tool for managing Azure Databricks workspaces and cloud infrastructure.\n",
- "pgVerified": false,
- "description": "Set up monitoring, alerting, and logging",
- "potentialBenefits": "Enhanced reliability and automation",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "397cdebb-9d6e-ab4f-83a1-8c481de0a3a7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://github.com/Azure/AzureDatabricksBestPractices/blob/master/toc.md#deploy-workspaces-in-multiple-subscriptions-to-honor-azure-capacity-limits",
- "name": "Azure Databricks Best Practices"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Customers often naturally divide workspaces by teams or departments. However, it's crucial to also consider Azure Subscription and Azure Databricks (ADB) Workspace limits when partitioning.\n",
- "pgVerified": false,
- "description": "Deploy workspaces in separate Subscriptions",
- "potentialBenefits": "Enhanced limits management, team separation",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "5e722c4f-415a-9b4c-bd4c-96b74dce29ad",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://github.com/Azure/AzureDatabricksBestPractices/blob/master/toc.md#consider-isolating-each-workspace-in-its-own-vnet",
- "name": "Azure Databricks Best Practices"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Deploying only one Databricks Workspace per VNet aligns with Azure Databricks' isolation model.\n",
- "pgVerified": false,
- "description": "Isolate each workspace in its own VNet",
- "potentialBenefits": "Enhanced security and resource isolation",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "14310ba6-77ad-3641-a2db-57a2218b9bc7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://github.com/Azure/AzureDatabricksBestPractices/blob/master/toc.md#do-not-store-any-production-data-in-default-dbfs-folders",
- "name": "Azure Databricks Best Practices"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Driven by security and data availability concerns, each Azure Databricks Workspace comes with a default DBFS designed for system-level artifacts like libraries and Init scripts, not for production data.\n",
- "pgVerified": false,
- "description": "Do not Store any Production Data in Default DBFS Folders",
- "potentialBenefits": "Enhanced security, data protection",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "b5af7e26-3939-1b48-8fba-f8d4a475c67a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/spot-vms",
- "name": "Use Azure Spot Virtual Machines"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Spot VMs are not suitable for critical production workloads needing high availability and reliability. They are meant for fault-tolerant tasks and can be evicted with 30-seconds notice if Azure needs the capacity, with no SLA guarantees.\n",
- "pgVerified": false,
- "description": "Do not use Azure Spot VMs for critical Production workloads",
- "potentialBenefits": "Ensures high reliability for production",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "8aa63c34-dd9d-49bd-9582-21ec310dfbdd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/databricks/resources/supported-regions#--azure-databricks-control-plane-addresses",
- "name": "Azure Databricks control plane addresses"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Move workspaces to in-region control plane for increased regional isolation. Identify current control plane region using the workspace URL and nslookup. When region from CNAME differs from workspace region and an in-region control is available, consider migration using tools provided below.\n",
- "pgVerified": false,
- "description": "Evaluate regional isolation for workspaces",
- "potentialBenefits": "Improves resilience and data sovereignty",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "028593be-956e-4736-bccf-074cb10b92f4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/databricks/compute/cluster-config-best-practices",
- "name": "Compute configuration best practices"
- }
- ],
- "recommendationControl": "Personalized",
- "longDescription": "Azure Databricks planning should include VM SKU swap strategies for capacity issues. VMs are regional, and allocation failures may occur, shown by a \"CLOUD PROVIDER\" error.\n",
- "pgVerified": false,
- "description": "Define alternate VM SKUs",
- "potentialBenefits": "Ensures service availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "e94da1f8-33e7-48a6-b301-72f19a53bc29",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/databricks/lakehouse-architecture/reliability/best-practices#use-managed-services-where-possible",
- "name": "Best practices for reliability"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Where possible Leverage managed services (serverless compute) from the Databricks Data Intelligence Platform, such as:serverless SQL warehouses, model serving, serverless jobs, serverless compute for notebooks.\n",
- "pgVerified": true,
- "description": "Use managed services where possible",
- "potentialBenefits": "Improve resiliency and scalability at no additional cost",
- "tags": null,
- "recommendationResourceType": "Microsoft.Databricks/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "88856605-53d8-4bbd-a75b-4a7b14939d32",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/mysql/flexible-server/concepts-high-availability",
- "name": "High availability concepts in Azure Database for MySQL - Flexible Server"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Enable HA with zone redundancy on flexible server instances to deploy a standby replica in a different zone, offering automatic failover capability for improved reliability and disaster recovery.\n",
- "pgVerified": true,
- "description": "Enable HA with zone redundancy",
- "potentialBenefits": "Enhanced uptime and data protection",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforMySQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for MySQL instances that are not zone redundant\r\nresources\r\n| where type == \"microsoft.dbformysql/flexibleservers\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where properties.highAvailability.mode != \"ZoneRedundant\"\r\n| project recommendationId = \"88856605-53d8-4bbd-a75b-4a7b14939d32\", name, id, tags, param1 = \"ZoneRedundant: False\"\r\n"
- },
- {
- "aprlGuid": "82a9a0f2-24ee-496f-9ad2-25f81710942d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/mysql/flexible-server/concepts-maintenance",
- "name": "Scheduled maintenance in Azure Database for MySQL - Flexible Server"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Use custom maintenance schedule on flexible server instances to select a preferred time for service updates to be applied.\n",
- "pgVerified": true,
- "description": "Enable custom maintenance schedule",
- "potentialBenefits": "Control update timings",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforMySQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for MySQL instances that do not have a custom maintenance window\r\nresources\r\n| where type =~ \"microsoft.dbformysql/flexibleservers\"\r\n| where properties.maintenanceWindow.customWindow != \"Enabled\"\r\n| project recommendationId = \"82a9a0f2-24ee-496f-9ad2-25f81710942d\", name, id, tags, param1 = strcat(\"customWindow:\", properties['maintenanceWindow']['customWindow'])\r\n"
- },
- {
- "aprlGuid": "5c96afc3-7d2e-46ff-a4c7-9c32850c441b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/mysql/flexible-server/concepts-backup-restore",
- "name": "Backup and restore in Azure Database for MySQL - Flexible Server"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Configure GRS to ensure that your database meets its availability and durability targets even in the face of failures or disasters.\n",
- "pgVerified": true,
- "description": "Configure geo redundant backup storage",
- "potentialBenefits": "Recover from regional failure and/or disaster",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforMySQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for MySQL instances that do not have geo redundant backup storage enabled\r\nresources\r\n| where type =~ \"microsoft.dbformysql/flexibleservers\"\r\n| where properties.backup.geoRedundantBackup != \"Enabled\"\r\n| project recommendationId = \"5c96afc3-7d2e-46ff-a4c7-9c32850c441b\", name, id, tags, param1 = strcat(\"geoRedundantBackup:\", properties['backup']['geoRedundantBackup'])\r\n"
- },
- {
- "aprlGuid": "b49a8653-cc43-48c9-8513-a2d2e3f14dd1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/mysql/flexible-server/concepts-read-replicas",
- "name": "Read replicas in Azure Database for MySQL - Flexible Server"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Configure one or more read replicas to ensure that your database meets its availability and durability targets even in the face of failures or disasters.\n",
- "pgVerified": true,
- "description": "Configure one or more read replicas",
- "potentialBenefits": "Recover from regional failure and/or disaster",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforMySQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for MySQL instances that do not have a read replica configured\r\nresources\r\n| where type =~ \"microsoft.dbformysql/flexibleservers\"\r\n| where properties.replicationRole == \"None\"\r\n| project recommendationId = \"b49a8653-cc43-48c9-8513-a2d2e3f14dd1\", name, id, tags, param1 = strcat(\"replicationRole:\", properties['replicationRole'])\r\n"
- },
- {
- "aprlGuid": "8176a79d-8645-4e52-96be-a10fc0204fe5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/mysql/flexible-server/concepts-service-tiers-storage#storage-auto-grow",
- "name": "Azure Database for MySQL - Flexible Server service tiers - Storage auto grow"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Configure storage auto-grow to prevent the server from running out of storage and becoming read-only.\n",
- "pgVerified": true,
- "description": "Configure storage auto-grow",
- "potentialBenefits": "Scale storage automatically to meet increasing demand",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforMySQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for MySQL instances that do not have a storage auto-grow\r\nresources\r\n| where type =~ \"microsoft.dbformysql/flexibleservers\"\r\n| where properties.storage.autoGrow != \"Enabled\"\r\n| project recommendationId = \"8176a79d-8645-4e52-96be-a10fc0204fe5\", name, id, tags, param1 = strcat(\"autoGrow:\", properties['storage']['autoGrow'])\r\n"
- },
- {
- "aprlGuid": "ca87914f-aac4-4783-ab67-82a6f936f194",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-high-availability",
- "name": "Overview of high availability with Azure Database for PostgreSQL"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Enable HA with zone redundancy on flexible server instances to deploy a standby replica in a different zone, offering automatic failover capability for improved reliability and disaster recovery.\n",
- "pgVerified": true,
- "description": "Enable HA with zone redundancy",
- "potentialBenefits": "Enhanced uptime and data protection",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforPostgreSQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for PostgreSQL instances that are not zone redundant\r\nresources\r\n| where type == \"microsoft.dbforpostgresql/flexibleservers\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where properties.highAvailability.mode != \"ZoneRedundant\"\r\n| project recommendationId = \"ca87914f-aac4-4783-ab67-82a6f936f194\", name, id, tags, param1 = \"ZoneRedundant: False\"\r\n"
- },
- {
- "aprlGuid": "b2bad57d-7e03-4c0f-9024-597c9eb295bb",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/postgresql/flexible-server/concepts-maintenance",
- "name": "Scheduled maintenance in Azure Database for PostgreSQL - Flexible Server"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Use custom maintenance schedule on flexible server instances to select a preferred time for service updates to be applied.\n",
- "pgVerified": true,
- "description": "Enable custom maintenance schedule",
- "potentialBenefits": "Control update timings",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforPostgreSQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for PostgreSQL instances that do not have a custom maintenance window\r\nresources\r\n| where type == \"microsoft.dbforpostgresql/flexibleservers\"\r\n| where properties.maintenanceWindow.customWindow != \"Enabled\"\r\n| project recommendationId = \"b2bad57d-7e03-4c0f-9024-597c9eb295bb\", name, id, tags, param1 = strcat(\"customWindow:\", properties['maintenanceWindow']['customWindow'])\r\n"
- },
- {
- "aprlGuid": "31f4ac4b-29cb-4588-8de2-d8fe6f13ceb3",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-backup-restore",
- "name": "Backup and restore in Azure Database for PostgreSQL - Flexible Server"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Configure GRS to ensure that your database meets its availability and durability targets even in the face of failures or disasters.\n",
- "pgVerified": true,
- "description": "Configure geo redundant backup storage",
- "potentialBenefits": "Recover from regional failure and/or disaster",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforPostgreSQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for PostgreSQL instances that do not have geo redundant backup storage configured\r\nresources\r\n| where type == \"microsoft.dbforpostgresql/flexibleservers\"\r\n| where properties.backup.geoRedundantBackup != \"Enabled\"\r\n| project recommendationId = \"31f4ac4b-29cb-4588-8de2-d8fe6f13ceb3\", name, id, tags, param1 = strcat(\"geoRedundantBackup:\", properties['backup']['geoRedundantBackup'])\r\n"
- },
- {
- "aprlGuid": "2ab85a67-26be-4ed2-a0bb-101b2513ec63",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/concepts-read-replicas",
- "name": "Read replicas in Azure Database for PostgreSQL - Flexible Server"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Configure one or more read replicas to ensure that your database meets its availability and durability targets even in the face of failures or disasters.\n",
- "pgVerified": true,
- "description": "Configure one or more read replicas",
- "potentialBenefits": "Recover from regional failure and/or disaster",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforPostgreSQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Database for PostgreSQL instances that do not have read replicas\r\nresources\r\n| where type == \"microsoft.dbforpostgresql/flexibleservers\" and properties.replicationRole == \"AsyncReplica\"\r\n| project replicaServerId = id, id = tostring(properties.sourceServerResourceId)\r\n| join kind=fullouter (resources | where type == \"microsoft.dbforpostgresql/flexibleservers\" and properties.replicationRole != \"AsyncReplica\") on id\r\n| where isempty(replicaServerId)\r\n| project recommendationId = \"2ab85a67-26be-4ed2-a0bb-101b2513ec63\", name, id = id1, tags, param1 = strcat(\"replicationRole:\", properties['replicationRole'])\r\n"
- },
- {
- "aprlGuid": "6293a3cc-6b4a-4c0f-9ea7-b8ae8d7dd3d5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/postgresql/flexible-server/how-to-auto-grow-storage-portal",
- "name": "Storage autogrow using Azure portal in Azure Database for PostgreSQL - Flexible Server"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Configure storage auto-grow to prevent the server from running out of storage and becoming read-only.\n",
- "pgVerified": false,
- "description": "Configure storage auto-grow",
- "potentialBenefits": "Scale storage automatically to meet increasing demand",
- "tags": null,
- "recommendationResourceType": "Microsoft.DBforPostgreSQL/flexibleServers",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "013ac34e-7c4b-425f-9e0c-216f0cc06181",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/configure-validation-environment?tabs=azure-portal",
- "name": "Configure a host pool as a validation environment"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Validation host pools let you monitor service updates before the service applies them to your standard or non-validation environment.\n",
- "pgVerified": true,
- "description": "Create a validation host pool",
- "potentialBenefits": "Enhanced environment stability",
- "tags": null,
- "recommendationResourceType": "Microsoft.DesktopVirtualization/hostPools",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "979ff8be-5f3a-4d8e-9aa3-407ecdd6d6f7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/scheduled-agent-updates",
- "name": "Scheduled Agent Updates for Azure Virtual Desktop host pools"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Create up to two maintenance windows for the Azure Virtual Desktop agent, side-by-side stack, and Geneva Monitoring agent to get updated so that updates don't happen during peak business hours.\n",
- "pgVerified": true,
- "description": "Configure host pool scheduled agent updates",
- "potentialBenefits": "Enhanced environment stability",
- "tags": null,
- "recommendationResourceType": "Microsoft.DesktopVirtualization/hostPools",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// Azure Resource Graph Query\r\n// This resource graph query will return all AVD host pools that does not have scheduled agent updates configured\r\nresources\r\n| where type =~ \"Microsoft.DesktopVirtualization/hostpools\"\r\n| where isnull(properties.agentUpdate)\r\n| project recommendationId = \"979ff8be-5f3a-4d8e-9aa3-407ecdd6d6f7\", name, id, tags, param1 = 'No scheduled agent updates'\r\n"
- },
- {
- "aprlGuid": "939cb85c-102a-4e0a-ab82-5c92116d3778",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/deploy/virtual-dc/adds-on-azure-vm#configure-the-vms-and-install-active-directory-domain-services",
- "name": "Configure the VMs and install Active Directory Domain Services"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Place domain joined session hosts VMs in unique OUs. Segregate Prod and DR units for environment-specific settings. This ensures targeted configurations for session hosts, including FSLogix, session controls, etc.\n",
- "pgVerified": true,
- "description": "Ensure a unique OU is used when deploying host pools with domain joined session hosts",
- "potentialBenefits": "Improved AVD hostpool config & segmentation",
- "tags": null,
- "recommendationResourceType": "Microsoft.DesktopVirtualization/hostPools",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "38721758-2cc2-4d6b-b7b7-8b47dadbf7df",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/site-recovery/site-recovery-overview",
- "name": "About Site Recovery"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Implement Azure Site Recovery (ASR) to replicate or backup stateful session hosts. This replicates VMs to a secondary Azure region or availability zone, ensuring recovery from a known VM state in case of an outage.\n",
- "pgVerified": true,
- "description": "Use Azure Site Recovery to protect stateful session hosts",
- "potentialBenefits": "Ensures VM recovery & failover",
- "tags": null,
- "recommendationResourceType": "Microsoft.Compute/virtualMachines",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "499769ae-67c9-492e-9ca5-cfd4cece5209",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/autoscale-scaling-plan?tabs=portal",
- "name": "Create and assign an autoscale scaling plan"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Scaling plans can only be assigned to host pools in the same region, on multi-region deployment scenario each region should has its own scaling plan.\n",
- "pgVerified": true,
- "description": "Create scaling plans per region",
- "potentialBenefits": "Enhanced scaling",
- "tags": null,
- "recommendationResourceType": "Microsoft.DesktopVirtualization/scalingPlans",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "783c6c18-760b-4867-9ced-3010a0bc5aa3",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-bulk-identity-mgmt",
- "name": "Import and export IoT Hub device identities in bulk"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Device Identities should be copied to the failover region IoT Hub for all IoT devices to ensure connectivity in case of a failover. Manual Failover to another region is quicker (RTO), suitable for mission critical workloads.\n",
- "pgVerified": false,
- "description": "Device Identities are exported to a secondary region",
- "potentialBenefits": "Faster failover; Ensures device connectivity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Devices/IotHubs",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "eeba3a49-fef0-481f-a471-7ff01139b474",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-scaling",
- "name": "Choose the right IoT Hub tier and size for your solution"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "In a production scenario, the IoT Hub tier should not be Free because the Free tier does not provide the necessary Service Level Agreement.\n",
- "pgVerified": false,
- "description": "Do not use free tier",
- "potentialBenefits": "Ensures SLA for production",
- "tags": null,
- "recommendationResourceType": "Microsoft.Devices/IotHubs",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// list all IoT Hubs that are using the Free tier\r\nresources\r\n| where type =~ \"microsoft.devices/iothubs\" and\r\n tostring(sku.tier) =~ 'Free'\r\n| project recommendationId=\"eeba3a49-fef0-481f-a471-7ff01139b474\", name, id, tags, param1=strcat(\"tier:\", tostring(sku.tier))\r\n\r\n"
- },
- {
- "aprlGuid": "214cbc46-747e-4354-af6e-6bf0054196a5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-ha-dr#availability-zones",
- "name": "Azure IoT Hub high availability and disaster recovery"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "In regions supporting Availability Zones for IoT Hub, using these zones boosts availability. They're automatically activated for new IoT Hubs in supported areas.\n",
- "pgVerified": false,
- "description": "Use Availability Zones",
- "potentialBenefits": "Boosts IoT Hub availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Devices/IotHubs",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "b1e1378d-4572-4414-bebd-b8872a6d4d1c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/iot-dps/concepts-service",
- "name": "IoT Hub Device Provisioning Service (DPS) terminology"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Device Provisioning Service (DPS) enables easy redistribution of IoT devices for scaling and availability, allowing devices to be reassigned and not bound to specific IoT Hub instances. Devices in IoT Hubs using DPS should be verified for DPS utilization.\n",
- "pgVerified": false,
- "description": "Use Device Provisioning Service",
- "potentialBenefits": "Enhances scalability and availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Devices/IotHubs",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// list all IoT Hubs that do not have a linked IoT Hub Device Provisioning Service (DPS)\r\nresources\r\n| where type =~ \"microsoft.devices/iothubs\"\r\n| project id, iotHubName=tostring(properties.hostName), tags, resourceGroup\r\n| join kind=fullouter (\r\n resources\r\n | where type == \"microsoft.devices/provisioningservices\"\r\n | mv-expand iotHubs=properties.iotHubs\r\n | project iotHubName = tostring(iotHubs.name), dpsName = name, name=iotHubs.name\r\n) on iotHubName\r\n| where dpsName == ''\r\n| project recommendationId=\"b1e1378d-4572-4414-bebd-b8872a6d4d1c\", name=iotHubName, id, tags, param1='DPS:none'\r\n\r\n"
- },
- {
- "aprlGuid": "02568a5d-335e-4e51-9f7c-fe2ada977300",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-ha-dr",
- "name": "IoT Hub high availability and disaster recovery"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "In case of a regional failure, an IoT Hub can failover to a second region, automatically or manually, to ensure your application continues working.\n",
- "pgVerified": false,
- "description": "Define Failover Guidelines",
- "potentialBenefits": "Ensures business continuity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Devices/IotHubs",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "e7dbd21f-b27a-4b8c-a901-cedb1e6d8e1e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/iot-hub/iot-hub-devguide-messages-d2c#fallback-route",
- "name": "Use message routing - Fallback route"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Using message routing for custom endpoints in IoT Hub, messages might not reach these destinations if specific conditions are unmet. A default route ensures all messages are received, but disabling this safety net risks leaving some messages undelivered.\n",
- "pgVerified": false,
- "description": "Disabled Fallback Route",
- "potentialBenefits": "Prevents undelivered messages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Devices/IotHubs",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// list all IoT Hubs that have the fallback route disabled\r\nresources\r\n| where type == \"microsoft.devices/iothubs\"\r\n| extend fallbackEnabled=properties.routing.fallbackRoute.isEnabled\r\n| where fallbackEnabled == false\r\n| project recommendationId=\"e7dbd21f-b27a-4b8c-a901-cedb1e6d8e1e\", name, id, tags, param1='FallbackRouteEnabled:false'\r\n\r\n"
- },
- {
- "aprlGuid": "43663217-a1d3-844b-80ea-571a2ce37c6c",
- "recommendationTypeId": "b57f7a29-dcc8-43de-86fa-18d3f9d3764d",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cosmos-db/distribute-data-globally",
- "name": "Distribute data globally with Azure Cosmos DB"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Enable a secondary region in Cosmos DB for higher SLA without downtime. Simple as pinning a location on a map. For Strong consistency, configure at least three regions for write availability in case of failure.\n",
- "pgVerified": true,
- "description": "Configure at least two regions for high availability",
- "potentialBenefits": "Enhances SLA and resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Query to find Azure Cosmos DB accounts that have less than 2 regions or less than 3 regions with strong consistency level\r\nResources\r\n| where type =~ 'Microsoft.DocumentDb/databaseAccounts'\r\n| where\r\n array_length(properties.locations) < 2 or\r\n (array_length(properties.locations) < 3 and properties.consistencyPolicy.defaultConsistencyLevel == 'Strong')\r\n| project recommendationId='43663217-a1d3-844b-80ea-571a2ce37c6c', name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "9cabded7-a1fc-6e4a-944b-d7dd98ea31a2",
- "recommendationTypeId": "5de9f2e6-087e-40da-863a-34b7943beed4",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cosmos-db/how-to-manage-database-account#automatic-failover",
- "name": "Manage an Azure Cosmos DB account by using the Azure portal"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Cosmos DB boasts high uptime and resiliency. Even so, issues may arise. With Service-Managed failover, if a region is down, Cosmos DB automatically switches to the next available region, requiring no user action.\n",
- "pgVerified": true,
- "description": "Enable service-managed failover for multi-region accounts with single write region",
- "potentialBenefits": "Auto failover for high uptime",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Query to list all Azure Cosmos DB accounts that do not have multiple write locations or automatic failover enabled\r\nResources\r\n| where type =~ 'Microsoft.DocumentDb/databaseAccounts'\r\n| where\r\n array_length(properties.locations) > 1 and\r\n tobool(properties.enableAutomaticFailover) == false and\r\n tobool(properties.enableMultipleWriteLocations) == false\r\n| project recommendationId='9cabded7-a1fc-6e4a-944b-d7dd98ea31a2', name, id, tags\r\n"
- },
- {
- "aprlGuid": "921631f6-ed59-49a5-94c1-f0f3ececa580",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/reliability/reliability-cosmos-db-nosql",
- "name": "High availability in Azure Cosmos DB"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "When availability zones are configured, Azure Cosmos DB intelligently distributes the 4 replicas of your data across all available zones. It ensures that your Azure Cosmos DB can withstand an outage in one availability zone and remain fully operational throughout.\n",
- "pgVerified": false,
- "description": "Enable availability zones",
- "potentialBenefits": "Enhances high availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Query to find Azure Cosmos DB accounts that do not utilize availability zones and are deployed in availability-zone supported regions\r\nResources\r\n| where type == \"microsoft.documentdb/databaseaccounts\"\r\n| where properties.capabilities !has_cs 'EnableServerless'\r\n| project recommendationId='921631f6-ed59-49a5-94c1-f0f3ececa580', name, id, tags, locations=properties.locations\r\n| mv-expand locations\r\n| where not(locations.isZoneRedundant) //filter out already AZ enabled regions\r\n| extend location=tostring(locations.locationName)\r\n| project-away locations\r\n| where location in (\r\n 'Australia East', 'Brazil South', 'Canada Central', 'Central India', 'Central US',\r\n 'China North 3', 'East Asia', 'East US', 'East US 2', 'France Central',\r\n 'Germany West Central', 'Israel Central', 'Italy North', 'Japan East', 'Japan West',\r\n 'Korea Central', 'Mexico Central', 'New Zealand North', 'North Europe', 'Norway East',\r\n 'Poland Central', 'Qatar Central', 'South Africa North', 'South Central US', 'Southeast Asia',\r\n 'Spain Central', 'Sweden Central', 'Switzerland North', 'UAE North', 'UK South',\r\n 'US Gov Virginia', 'West Europe', 'West US 2', 'West US 3') // filter out regions unsupported for AZs\r\n| project-rename param1=location\r\n"
- },
- {
- "aprlGuid": "9ce78192-74a0-104c-b5bb-9a443f941649",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cosmos-db/distribute-data-globally",
- "name": "Distribute data globally with Azure Cosmos DB"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Multi-region write capability allows for designing applications that are highly available across multiple regions, though it demands careful attention to consistency requirements and conflict resolution. Improper setup may decrease availability and cause data corruption due to unhandled conflicts.\n",
- "pgVerified": true,
- "description": "Evaluate multi-region write capability",
- "potentialBenefits": "Enhances high availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Query to find Azure Cosmos DB accounts that have multiple read locations but do not have multiple write locations enabled\r\nResources\r\n| where type =~ 'Microsoft.DocumentDb/databaseAccounts'\r\n| where\r\n array_length(properties.locations) > 1 and\r\n properties.enableMultipleWriteLocations == false\r\n| project recommendationId='9ce78192-74a0-104c-b5bb-9a443f941649', name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "e544520b-8505-7841-9e77-1f1974ee86ec",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cosmos-db/continuous-backup-restore-introduction",
- "name": "Continuous backup with point in time restore feature in Azure Cosmos DB"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Cosmos DB's backup is always on, offering protection against data mishaps. Continuous mode allows for self-serve restoration to a pre-mishap point, unlike periodic mode which requires contacting Microsoft support, leading to longer restore times.\n",
- "pgVerified": true,
- "description": "Configure continuous backup mode",
- "potentialBenefits": "Faster self-serve data restore",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Query all Azure Cosmos DB accounts that do not have continuous backup mode configured\r\nResources\r\n| where type =~ 'Microsoft.DocumentDb/databaseAccounts'\r\n| where\r\n properties.backupPolicy.type == 'Periodic' and\r\n properties.enableMultipleWriteLocations == false and\r\n properties.enableAnalyticalStorage == false\r\n| project recommendationId='e544520b-8505-7841-9e77-1f1974ee86ec', name, id, tags\r\n"
- },
- {
- "aprlGuid": "c006604a-0d29-684c-99f0-9729cb40dac5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cosmos-db/nosql/query/pagination#handling-multiple-pages-of-results",
- "name": "Pagination in Azure Cosmos DB"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Cosmos DB has a 4 MB response limit, leading to paginated results for large or partition-spanning queries. Each page shows availability and provides a continuation token for the next. A while loop in code is necessary to traverse all pages until completion.\n",
- "pgVerified": true,
- "description": "Ensure query results are fully drained",
- "potentialBenefits": "Maximizes data retrieval efficiency",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "7eb32cf9-9a42-1540-acf8-597cbba8a418",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cosmos-db/nosql/conceptual-resilient-sdk-applications",
- "name": "Designing resilient applications with Azure Cosmos DB SDKs"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Using a single instance of the SDK client for each account and application is crucial as connections are tied to the client. Compute environments have a limit on open connections, affecting connectivity when exceeded.\n",
- "pgVerified": true,
- "description": "Maintain singleton pattern in your client",
- "potentialBenefits": "Optimizes connections and efficiency",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "fa6ac22f-0584-bb4b-80e4-80f4755d1a97",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cosmos-db/nosql/conceptual-resilient-sdk-applications",
- "name": "Designing resilient applications with Azure Cosmos DB SDKs"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Cosmos DB SDKs automatically manage many transient errors through retries. Despite this, it's crucial for applications to implement additional retry policies targeting specific cases that the SDKs can't generically address, ensuring more robust error handling.\n",
- "pgVerified": true,
- "description": "Implement retry logic in your client",
- "potentialBenefits": "Enhances error handling resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "deaea200-013c-414b-ac9f-bfa7a7fb13f0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cosmos-db/create-alerts",
- "name": "Create alerts for Azure Cosmos DB using Azure Monitor"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Monitoring the availability and responsiveness of Azure Cosmos DB resources and having alerts set up for your workload is a good practice. This ensures you stay proactive in handling unforeseen events.\n",
- "pgVerified": true,
- "description": "Monitor Cosmos DB health and set up alerts",
- "potentialBenefits": "Proactive issue management",
- "tags": null,
- "recommendationResourceType": "Microsoft.DocumentDB/databaseAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "54c3191b-b535-1946-bba9-b754f44060f6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/event-grid/enable-diagnostic-logs-topic",
- "name": "Azure Event Grid - Enable diagnostic logs for Event Grid resources"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Enabling diagnostic settings on Azure Event Grid resources like custom topics, system topics, and domains lets you capture and view diagnostic information to troubleshoot failures effectively.\n",
- "pgVerified": false,
- "description": "Configure Diagnostic Settings for all Azure Event Grid resources",
- "potentialBenefits": "Enhanced troubleshooting for Event Grid",
- "tags": null,
- "recommendationResourceType": "Microsoft.EventGrid/topics",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "92162eb5-4323-3145-8a6c-525ce2f0700e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/event-grid/delivery-and-retry#dead-letter-events",
- "name": "Azure Event Grid delivery and retry"
- }
- ],
- "recommendationControl": "Personalized",
- "longDescription": "Event Grid may not deliver an event within a specific time or after several attempts, leading to dead-lettering where undelivered events are sent to a storage account.\n",
- "pgVerified": false,
- "description": "Configure Dead-letter to save events that cannot be delivered",
- "potentialBenefits": "Saves undelivered events",
- "tags": null,
- "recommendationResourceType": "Microsoft.EventGrid/topics",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "b2069f64-4741-3d4a-a71d-50c8b03f5ab7",
- "recommendationTypeId": "bdac9c7b-b9b8-f572-0450-f161c430861c",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/event-grid/configure-private-endpoints",
- "name": "Configure private endpoints for Azure Event Grid topics or domains"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Use private endpoints for secure event ingress to custom topics/domains via a private link, avoiding the public internet. It employs an IP from the VNet space for your topic/domain.\n",
- "pgVerified": false,
- "description": "Azure Event Grid topics should use Private Link Private Endpoints",
- "potentialBenefits": "Secure, private VNet ingress",
- "tags": null,
- "recommendationResourceType": "Microsoft.EventGrid/topics",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all eventgrid services not protected by private endpoints.\r\nResources\r\n| where type contains \"eventgrid\"\r\n| where properties['publicNetworkAccess'] == \"Enabled\"\r\n| project recommendationId = \"b2069f64-4741-3d4a-a71d-50c8b03f5ab7\", name, id, tags\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "84636c6c-b317-4722-b603-7b1ffc16384b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/event-hubs/event-hubs-geo-dr?tabs=portal#availability-zones",
- "name": "Azure Event Hubs - Geo-disaster recovery"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "When using the Azure portal, zone redundancy is automatically enabled. However, some Infrastructure as Code (IaC) tools may default this to false. To ensure replication of metadata and events across data centers in an availability zone, always verify that zone redundancy is enabled.\n",
- "pgVerified": true,
- "description": "Ensure zone redundancy is enabled in supported regions",
- "potentialBenefits": "Enhanced fault tolerance for Event Hub",
- "tags": null,
- "recommendationResourceType": "Microsoft.EventHub/namespaces",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Event Hub namespace instances that are not zone redundant\r\nresources\r\n| where type == \"microsoft.eventhub/namespaces\"\r\n| where properties.zoneRedundant == false\r\n| project recommendationId = \"84636c6c-b317-4722-b603-7b1ffc16384b\", name, id, tags, param1 = \"ZoneRedundant: False\"\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "fbfef3df-04a5-41b2-a8fd-b8541eb04956",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/event-hubs/event-hubs-auto-inflate",
- "name": "Azure Event Hubs - Automatically scale throughput units"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Enable auto-inflate on Event Hub Standard tier namespaces to automatically scale up throughput units (TUs), meeting usage needs and preventing data ingress or egress throttle scenarios by adjusting to allowed rates.\n",
- "pgVerified": true,
- "description": "Enable auto-inflate on Event Hub Standard tier",
- "potentialBenefits": "Prevents throttling by autoscaling TUs",
- "tags": null,
- "recommendationResourceType": "Microsoft.EventHub/namespaces",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Event Hub namespace instances that are Standard tier and do not have Auto Inflate enabled\r\nresources\r\n| where type == \"microsoft.eventhub/namespaces\"\r\n| where sku.tier == \"Standard\"\r\n| where properties.isAutoInflateEnabled == \"false\"\r\n| project recommendationId = \"fbfef3df-04a5-41b2-a8fd-b8541eb04956\", name, id, tags, param1 = \"AutoInflateEnabled: False\"\r\n\r\n"
- },
- {
- "aprlGuid": "be448849-0d7d-49ba-9c94-9573ee533d5d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/service-health/resource-health-overview",
- "name": "Resource Health"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Configure Resource Health Alerts for all applicable resources to stay informed about the current and historical health status of your Azure resources. They notify you when these resources have a change in their health status.\n",
- "pgVerified": true,
- "description": "Configure Resource Health Alerts",
- "potentialBenefits": "Stay informed on resource status",
- "tags": null,
- "recommendationResourceType": "Microsoft.Insights/activityLogAlerts",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "dac421ec-2832-4c37-839e-b6dc5a38f2fa",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-monitor/app/convert-classic-resource",
- "name": "Migrate an Application Insights classic resource to a workspace-based resource"
- }
- ],
- "recommendationControl": "ServiceUpgradeAndRetirement",
- "longDescription": "Classic Application Insights retires in February 2024. To minimize disruption to existing application monitoring scenarios, transition to workspace-based Application Insights before 29 February 2024.\n",
- "pgVerified": false,
- "description": "Convert Classic Deployments",
- "potentialBenefits": "Avoid service disruption post-Feb 2024",
- "tags": null,
- "recommendationResourceType": "Microsoft.Insights/components",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph query\r\n// Filters Application Insights resources with ‘Classic’ deployment type\r\nresources\r\n| where type =~ \"microsoft.insights/components\"\r\n| extend IngestionMode = properties.IngestionMode\r\n| where IngestionMode =~ 'ApplicationInsights'\r\n| project recommendationId= \"dac421ec-2832-4c37-839e-b6dc5a38f2fa\", name, id, tags, param1=\"ApplicationInsightsDeploymentType: Classic\"\r\n\r\n"
- },
- {
- "aprlGuid": "1cca00d2-d9ab-8e42-a788-5d40f49405cb",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview",
- "name": "Azure Key Vault soft-delete overview"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Key Vault's soft-delete feature enables recovery of deleted vaults and objects like keys, secrets, and certificates. When enabled, marked resources are retained for 90 days, allowing for their recovery, essentially undoing deletion.\n",
- "pgVerified": true,
- "description": "Key vaults should have soft delete enabled",
- "potentialBenefits": "Enables recovery of deleted items",
- "tags": null,
- "recommendationResourceType": "Microsoft.KeyVault/vaults",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This Resource Graph query will return all Key Vaults that do not have soft delete enabled.\r\nresources\r\n| where type == \"microsoft.keyvault/vaults\"\r\n| where isnull(properties.enableSoftDelete) or properties.enableSoftDelete != \"true\"\r\n| project recommendationId = \"1cca00d2-d9ab-8e42-a788-5d40f49405cb\", name, id, tags, param1 = \"EnableSoftDelete: Disabled\"\r\n\r\n"
- },
- {
- "aprlGuid": "70fcfe6d-00e9-5544-a63a-fff42b9f2edb",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/key-vault/general/soft-delete-overview#purge-protection",
- "name": "Azure Key Vault purge-protection overview"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Purge protection secures against malicious deletions by enforcing a retention period for soft deleted key vaults, ensuring no one, not even insiders or Microsoft, can purge your key vaults during this period, preventing permanent data loss.\n",
- "pgVerified": true,
- "description": "Key vaults should have purge protection enabled",
- "potentialBenefits": "Protects from insider attacks, avoids data loss",
- "tags": null,
- "recommendationResourceType": "Microsoft.KeyVault/vaults",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This resource graph query will return all Key Vaults that do not have Purge Protection enabled.\r\nresources\r\n| where type == \"microsoft.keyvault/vaults\"\r\n| where isnull(properties.enablePurgeProtection) or properties.enablePurgeProtection != \"true\"\r\n| project recommendationId = \"70fcfe6d-00e9-5544-a63a-fff42b9f2edb\", name, id, tags, param1 = \"EnablePurgeProtection: Disabled\"\r\n\r\n"
- },
- {
- "aprlGuid": "00c3d2b0-ea6e-4c4b-89be-b78a35caeb51",
- "recommendationTypeId": "2e96bc2f-1972-e471-9e70-ae58d41e9d2a",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/key-vault/general/security-features#network-security",
- "name": "Azure Key Vault Private Link Service overview"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Azure Private Link Service lets you securely and privately connect to Azure Key Vault via a Private Endpoint in your VNet, using a private IP and eliminating public Internet exposure.\n",
- "pgVerified": true,
- "description": "Private endpoint should be configured for Key Vault",
- "potentialBenefits": "Secure Key Vault with Private Link",
- "tags": null,
- "recommendationResourceType": "Microsoft.KeyVault/vaults",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This resource graph query will return all Key Vaults that does not have a Private Endpoint Connection or where a private endpoint exists but public access is enabled\r\n\r\nresources\r\n| where type == \"microsoft.keyvault/vaults\"\r\n| where isnull(properties.privateEndpointConnections) or properties.privateEndpointConnections[0].properties.provisioningState != (\"Succeeded\") or (isnull(properties.networkAcls) and properties.publicNetworkAccess == 'Enabled')\r\n| extend param1 = strcat('Private Endpoint: ', iif(isnotnull(properties.privateEndpointConnections),split(properties.privateEndpointConnections[0].properties.privateEndpoint.id,'/')[8],'No Private Endpoint'))\r\n| extend param2 = strcat('Access: ', iif(properties.publicNetworkAccess == 'Disabled', 'Public Access Disabled', iif(isnotnull(properties.networkAcls), 'NetworkACLs in place','Public Access Enabled')))\r\n| project recommendationId = \"00c3d2b0-ea6e-4c4b-89be-b78a35caeb51\", name, id, tags, param1, param2\r\n\r\n"
- },
- {
- "aprlGuid": "e7091145-3642-bd41-bb58-66502e64d2cd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/key-vault/general/best-practices#why-we-recommend-separate-key-vaults",
- "name": "Azure Key Vault best practices overview"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Key vaults are security boundaries for secret storage. Grouping secrets together increases risk during a security event, as attacks could access multiple secrets.\n",
- "pgVerified": true,
- "description": "Use separate key vaults per application per environment",
- "potentialBenefits": "Enhanced security, Reduced risk",
- "tags": null,
- "recommendationResourceType": "Microsoft.KeyVault/vaults",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1dc0821d-4f14-7644-bab4-ba208ff5f7fa",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/key-vault/general/logging?tabs=Vault",
- "name": "Azure Key Vault logging overview"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Enable logs, set up alerts, and adhere to retention requirements for improved monitoring and security of Key Vault access, detailing the frequency and identity of users.\n",
- "pgVerified": true,
- "description": "Diagnostic logs in Key Vault should be enabled",
- "potentialBenefits": "Enhanced monitoring and security compliance",
- "tags": null,
- "recommendationResourceType": "Microsoft.KeyVault/vaults",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "611c7c96-ac55-4ddf-909e-9eb70fd048b7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/how-to-manage-registries?view=azureml-api-2&tabs=cli",
- "name": "Manage Azure Machine Learning registries"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Azure Machine Learning registries enables to create and use assets (models, env, components, and datasets) in different workspaces. Registries support multi-region replication for low latency access to assets, allowing to use them in workspaces located in different Azure regions.\n",
- "pgVerified": false,
- "description": "Create the Azure machine learning registry in multiple regions",
- "potentialBenefits": "Improves performance and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/registries",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "a86ed26a-59d9-47bd-b440-6bc71b843978",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/how-to-high-availability-machine-learning?view=azureml-api-2",
- "name": "Plan for multi-regional deployment"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Ensure you have a recovery strategy defined. Check regional availability and paired regions. Machine Learning doesn't have auto failover. Therefore, you must design a strategy that encompasses the workspace and all its dependencies, such as Key Vault, Azure Storage, and Container Registry.\n",
- "pgVerified": false,
- "description": "Plan for a multi-regional deployment of Azure Machine Learning and associated resources",
- "potentialBenefits": "Provides multi-region disaster recovery strategy",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "675d249a-9486-45e3-8e89-863f5802782d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/how-to-high-availability-machine-learning?view=azureml-api-2",
- "name": "Failover for business continuity and disaster recovery"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "If your primary workspace is unavailable, switch to the secondary workspace to continue work. Azure Machine Learning doesn't auto-submit jobs to the secondary workspace during an outage. Update your code configuration to point to the new workspace resource.\n",
- "pgVerified": false,
- "description": "Deploy Azure Machine learning workspace in secondary region",
- "potentialBenefits": "Provides recovery from regional outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "13794a63-8d95-47ce-acbd-5925ede5b208",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/how-to-high-availability-machine-learning?view=azureml-api-2",
- "name": "Failover for business continuity and disaster recovery"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Create compute resources for training a Machine Learning model in selected regions. Ensure both regions have sufficient compute quota for dynamic scaling. Customers must configure HA across zones for attached compute resources like AKS, Azure Databricks, Container Instances.\n",
- "pgVerified": false,
- "description": "Ensure to create Machine Learning Compute resources in secondary region",
- "potentialBenefits": "High availability and disaster recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "98f15850-f31e-4fb2-8874-74f5aabbcf91",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/reference-checkpoint-performance-for-large-models?view=azureml-api-2&tabs=PYTORCH#why-checkpoint-optimization-for-large-model-training-matters",
- "name": "Importance of checkpoint optimization"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Checkpoint optimization for large model training is crucial for disaster recovery. It reduces training time, increases reliability, improves cost efficiency, enhances resource utilization, and supports scalability by saving model states periodically to resume training from the last saved point.\n",
- "pgVerified": false,
- "description": "Ensure checkpoints are used for AI training models",
- "potentialBenefits": "Reduces costs, training time and increases reliability.",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "6e4f0fd1-1853-4b94-9736-6d6d239d2694",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/how-to-manage-quotas?view=azureml-api-2",
- "name": "Manage resource quotas"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "When selecting regions for BCDR, ensure that both regions offer adequate compute quotas to meet your requirements in the same SKU. This ensures that you can failover to the secondary region without any issues.\n",
- "pgVerified": false,
- "description": "Selecting regions for BCDR, ensure that both regions offer adequate compute quotas",
- "potentialBenefits": "Provide enough compute resources to the secondary region",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "6e2af91f-477d-46a5-b8ce-6cd1b8176550",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/concept-compute-target?view=azureml-api-2#supported-vm-series-and-sizes",
- "name": "What are compute targets in Azure Machine Learning"
- }
- ],
- "recommendationControl": "ServiceUpgradeAndRetirement",
- "longDescription": "When choosing SKUs, opt for those that support longer terms and steer clear of any SKUs that are nearing retirement. This ensures that you can continue to use the SKU for a longer period of time.\n",
- "pgVerified": false,
- "description": "Choose SKUs with longer terms and avoid those nearing retirement",
- "potentialBenefits": "supportability, longer term support",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "cf2569bb-1cf2-46ce-8885-d742dc6f4a4c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/n-series-migration",
- "name": "Migration Guide for GPU Compute Workloads in Azure"
- }
- ],
- "recommendationControl": "ServiceUpgradeAndRetirement",
- "longDescription": "Avoid selecting NC and NC_Promo series Azure virtual machines for machine learning VM quotas and make sure to migrate to newer versions.\n",
- "pgVerified": false,
- "description": "Avoid NC and NC_Promo series Azure VMs for machine learning quotas; migrate to newer versions",
- "potentialBenefits": "Avoid service disruption, longer term support",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "48ea6480-6263-40ba-8937-326d790e63f6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/how-to-manage-quotas?view=azureml-api-2",
- "name": "Manage and increase quotas and limits for resources with Azure Machine Learning"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Requests for additional Azure Machine Learning quota should be made through the Azure Machine Learning Studio instead of the subscription level in the Azure portal.\n",
- "pgVerified": false,
- "description": "Make Azure Machine Learning quota requests through the Azure Machine Learning Studio",
- "potentialBenefits": "Scalability,capacity planning",
- "tags": null,
- "recommendationResourceType": "Microsoft.MachineLearningServices/workspaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "af426a99-62a6-6b4c-9662-42d220b413b8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-service-levels",
- "name": "Service levels for Azure NetApp Files | Microsoft Learn"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Service levels, part of capacity pool attributes, determine the maximum throughput per volume quota in Azure NetApp Files. It combines read and write speed, offering three levels: Standard (16 MiB/s per 1TiB), Premium (64 MiB/s per 1TiB), and Ultra (128 MiB/s per 1TiB) throughput.\n",
- "pgVerified": true,
- "description": "Use the correct service level and volume quota size for the expected performance level",
- "potentialBenefits": "Optimized performance and cost efficiency",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "ab984130-c57b-6c4a-8d04-6723b4e1bdb6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/azure-netapp-files-network-topologies",
- "name": "Guidelines for Azure NetApp Files network planning | Microsoft Learn"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Standard network feature in Azure NetApp Files enhances IP limits and VNet capabilities, including network security groups, user-defined routes on subnets, and diverse connectivity options.\n",
- "pgVerified": true,
- "description": "Use standard network features for production in Azure NetApp Files",
- "potentialBenefits": "Enhanced connectivity and security",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This Resource Graph query will return all Azure NetApp Files volumes without standard network features.\r\nresources\r\n| where type =~ \"microsoft.netapp/netappaccounts/capacitypools/volumes\"\r\n| where properties.networkFeatures != \"Standard\"\r\n| project recommendationId = \"ab984130-c57b-6c4a-8d04-6723b4e1bdb6\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "47d100a5-7f85-5742-967a-67eb5081240a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/use-availability-zones",
- "name": "Use availability zones for high availability in Azure NetApp Files | Microsoft Learn"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Availability zones are distinct locations within an Azure region to withstand local failures. Deploy your workload in multiple availability zones and use application-based replication or Azure NetApp Files cross-zone replication to achieve high availability. Note that failover is a manual process.\n",
- "pgVerified": true,
- "description": "Use availability zones for high availability in Azure NetApp Files",
- "potentialBenefits": "High Availability across availability zones",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This Resource Graph query will return all Azure NetApp Files volumes without an availability zone defined.\r\nResources\r\n| where type =~ \"Microsoft.NetApp/netAppAccounts/capacityPools/volumes\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where array_length(zones) == 0 or isnull(zones)\r\n| project recommendationId = \"47d100a5-7f85-5742-967a-67eb5081240a\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "8bb690e8-64d5-4838-8703-9ee3dbac688f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/manage-availability-zone-volume-placement",
- "name": "Manage availability zone volume placement for Azure NetApp Files | Microsoft Learn"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Azure NetApp Files' availability zone (AZ) volume placement feature lets you deploy volumes in the same AZ with Azure compute and other services to have within AZ latency and share the same AZ failure domain.\n",
- "pgVerified": true,
- "description": "Deploy ANF volumes in the same availability zone with Azure compute and other services",
- "potentialBenefits": "Within AZ latency and tolerate failure of other AZ",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "72827434-c773-4345-9493-34848ddf5803",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/snapshots-introduction",
- "name": "How Azure NetApp Files snapshots work | Microsoft Learn"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure NetApp Files snapshot technology ensures stability, scalability, and swift data recoverability without affecting performance. It supports automatic snapshot creation via policies for Azure NetApp Files data.\n",
- "pgVerified": true,
- "description": "Use snapshots for data protection in Azure NetApp Files",
- "potentialBenefits": "Stable, scalable, swift recovery, no perf impact",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This Resource Graph query will return all Azure NetApp Files volumes without a snapshot policy defined.\r\nresources\r\n| where type == \"microsoft.netapp/netappaccounts/capacitypools/volumes\"\r\n| where properties.dataProtection.snapshot.snapshotPolicyId == \"\"\r\n| project recommendationId = \"72827434-c773-4345-9493-34848ddf5803\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "b2fb3e60-97ec-e34d-af29-b16a0d61c2ac",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/backup-introduction",
- "name": "Understand Azure NetApp Files backup | Microsoft Learn"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Azure NetApp Files offers a fully managed backup solution enhancing long-term recovery, archiving, and compliance.\n",
- "pgVerified": true,
- "description": "Enable backup for data protection in Azure NetApp Files",
- "potentialBenefits": "Enhances data recovery and compliance",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This Resource Graph query will return all Azure NetApp Files volumes without a backup policy defined.\r\nresources\r\n| where type == \"microsoft.netapp/netappaccounts/capacitypools/volumes\"\r\n| where properties.dataProtection.backup.backupPolicyId == \"\"\r\n| project recommendationId = \"b2fb3e60-97ec-e34d-af29-b16a0d61c2ac\", name, id, tags\r\n"
- },
- {
- "aprlGuid": "e30317d2-c502-4dfe-a2d3-0a737cc79545",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-netapp-files/cross-region-replication-introduction",
- "name": "Cross-region replication of Azure NetApp Files volumes"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Azure NetApp Files replication offers data protection by allowing asynchronous cross-region volume replication for application failover in case of regional outages. Volumes can be replicated across regions, not concurrently with cross-zone replication. Note that failover is a manual process.\n",
- "pgVerified": true,
- "description": "Enable Cross-region replication of Azure NetApp Files volumes",
- "potentialBenefits": "Enhanced data protection and disaster recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This Resource Graph query will return all Azure NetApp Files volumes without cross-region replication.\r\nresources\r\n| where type == \"microsoft.netapp/netappaccounts/capacitypools/volumes\"\r\n| extend remoteVolumeRegion = properties.dataProtection.replication.remoteVolumeRegion\r\n| extend volumeType = properties.volumeType\r\n| extend replicationType = iff((remoteVolumeRegion == location), \"CZR\", iff((remoteVolumeRegion == \"\"),\"n/a\",\"CRR\"))\r\n| where replicationType != \"CRR\" and volumeType != \"DataProtection\"\r\n| project recommendationId = \"e30317d2-c502-4dfe-a2d3-0a737cc79545\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "e3d742e1-dacd-9b48-b6b1-510ec9f87c96",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/cross-zone-replication-introduction",
- "name": "Cross-zone replication of Azure NetApp Files volumes | Microsoft Learn"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "The cross-zone replication (CZR) feature enables asynchronous data replication between Azure NetApp Files volumes across different availability zones, ensuring data protection and critical application failover in case of zone-wide disasters. Note that failover is a manual process.\n",
- "pgVerified": true,
- "description": "Enable Cross-zone replication of Azure NetApp Files volumes",
- "potentialBenefits": "Enhances disaster recovery across availability zones",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This Resource Graph query will return all Azure NetApp Files volumes without cross-zone replication.\r\nresources\r\n| where type == \"microsoft.netapp/netappaccounts/capacitypools/volumes\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| extend remoteVolumeRegion = properties.dataProtection.replication.remoteVolumeRegion\r\n| extend volumeType = properties.volumeType\r\n| extend replicationType = iff((remoteVolumeRegion == location), \"CZR\", iff((remoteVolumeRegion == \"\"),\"n/a\",\"CRR\"))\r\n| where replicationType != \"CZR\" and volumeType != \"DataProtection\"\r\n| project recommendationId = \"e3d742e1-dacd-9b48-b6b1-510ec9f87c96\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "2f579fc9-e599-0d44-8b97-254f50ae04d8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/monitor-azure-netapp-files",
- "name": "Ways to monitor Azure NetApp Files | Microsoft Learn"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Azure NetApp Files offers metrics like allocated storage, actual usage, volume IOPS, and latency, enabling a better understanding of usage patterns and volume performance for NetApp accounts.\n",
- "pgVerified": true,
- "description": "Monitor Azure NetApp Files metrics to better understand usage pattern and performance",
- "potentialBenefits": "Optimize usage and performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "687ae58f-517f-ca43-90fe-922497e61283",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/azure-policy-definitions",
- "name": "Azure Policy definitions for Azure NetApp Files | Microsoft Learn"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Azure NetApp Files supports Azure policy integration using either built-in policy definitions or by creating custom ones to maintain organizational standards and compliance.\n",
- "pgVerified": true,
- "description": "Enforce standards and assess compliance in Azure NetApp Files with Azure policy",
- "potentialBenefits": "Enforce standards and assess compliance",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "cfa2244b-5436-47de-8287-b217875d3b0a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/configure-network-features",
- "name": "Configure network features for an Azure NetApp Files volume"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Access to the delegated subnet should be limited to specific Azure Virtual Networks. SMB-enabled volumes' share permissions should move away from 'Everyone/Full control'. NFS-enabled volumes' access needs to be controlled via export policies and/or NFSv4.1 ACLs.\n",
- "pgVerified": true,
- "description": "Restrict default access to Azure NetApp Files volumes",
- "potentialBenefits": "Enhanced security, Reduced data breach risk",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "d1e7ccc3-e6c1-40e9-a36e-fd134711c808",
- "recommendationTypeId": "e4bebd74-387a-4a74-b757-475d2d1b4e3e",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/faq-application-resilience#do-i-need-to-take-special-precautions-for-smb-based-applications",
- "name": "Do I need to take special precautions for SMB-based applications? | Microsoft Learn"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Certain SMB applications need SMB Transparent Failover for maintenance without interrupting server connectivity. Azure NetApp Files provides this through SMB Continuous Availability for applications like Citrix App Layering, FSLogix user/profile containers, Microsoft SQL Server, MSIX app attach.\n",
- "pgVerified": true,
- "description": "Make use of SMB continuous availability for supported applications",
- "potentialBenefits": "Zero downtime for SMB apps",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "60f36f9b-fac9-4160-bbf5-57af04da4f53",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-netapp-files/faq-application-resilience#what-do-you-recommend-for-handling-potential-application-disruptions-due-to-storage-service-maintenance-events",
- "name": "What do you recommend for handling potential application disruptions due to storage service maintenance events? | Microsoft Learn"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure NetApp Files might undergo occasional planned maintenance such as platform updates or service and software upgrades. It's important to be aware of the application's resiliency settings to cope with these storage service maintenance events.\n",
- "pgVerified": true,
- "description": "Ensure application resilience for service maintenance events",
- "potentialBenefits": "Minimizes downtime during maintenance",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetApp/netAppAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "823b0cff-05c0-2e4e-a1e7-9965e1cfa16f",
- "recommendationTypeId": "c9c9750b-9ddb-436f-b19a-9c725539a0b5",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/application-gateway/application-gateway-autoscaling-zone-redundant#autoscaling-and-high-availability",
- "name": "Application Gateway Autoscaling Zone-Redundant"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Azure Application Gateways v2 are always deployed in a highly available fashion with multiple instances by default. Enabling autoscale ensures the service is not reliant on manual intervention for scaling.\n",
- "pgVerified": true,
- "description": "Ensure Autoscale feature has been enabled",
- "potentialBenefits": "Enhances uptime and enables autoscaling",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will return all Application Gateways that do not have autoscale enabled or have a min capacity of 1\r\nresources\r\n| where type =~ \"microsoft.network/applicationGateways\"\r\n| where isnull(properties.autoscaleConfiguration) or properties.autoscaleConfiguration.minCapacity <= 1\r\n| project recommendationId = \"823b0cff-05c0-2e4e-a1e7-9965e1cfa16f\", name, id, tags, param1 = \"autoScaleConfiguration: isNull or MinCapacity <= 1\"\r\n| order by id asc\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "233a7008-71e9-e745-923e-1a1c7a0b92f3",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/services/networking/azure-application-gateway#security",
- "name": "Application Gateway Security"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Secure all incoming connections using HTTPS for production services with end-to-end SSL/TLS or SSL/TLS termination at the Application Gateway to protect against attacks and ensure data remains private and encrypted between the web server and browsers.\n",
- "pgVerified": true,
- "description": "Secure all incoming connections with SSL",
- "potentialBenefits": "Enhanced security and privacy",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// You can use the following Azure Resource Graph query to check if an HTTP rule is using an SSL certificate or is using Azure Key Vault to store the certificates\r\nresources\r\n| where type =~ \"microsoft.network/applicationGateways\"\r\n| mv-expand frontendPorts = properties.frontendPorts\r\n| mv-expand httpListeners = properties.httpListeners\r\n| where isnull(parse_json(httpListeners.properties.sslCertificate))\r\n| project recommendationId=\"233a7008-71e9-e745-923e-1a1c7a0b92f3\", name, id, tags, param1=strcat(\"frontendPort: \", frontendPorts.properties.port), param2=\"tls: false\"\r\n\r\n"
- },
- {
- "aprlGuid": "8d9223c4-730d-ca47-af88-a9a024c37270",
- "recommendationTypeId": "efe75f01-6fff-5d9d-08e6-092b98d3fb3f",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/application-gateway/features#web-application-firewall",
- "name": "Application Gateway - Web Application Firewall"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Use Application Gateway with Web Application Firewall (WAF) in an application virtual network to safeguard inbound HTTP/S internet traffic. WAF offers centralized defense against potential exploits through OWASP core rule sets-based rules.\n",
- "pgVerified": true,
- "description": "Enable Web Application Firewall policies",
- "potentialBenefits": "Enhanced security for HTTP/S traffic",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will return all Application Gateways that do not have WAF enabled\r\nResources\r\n| where type =~ \"microsoft.network/applicationGateways\"\r\n| where properties.firewallpolicy != \"\"\r\n| project recommendationId = \"8d9223c4-730d-ca47-af88-a9a024c37270\", name, id, tags, param1 = \"webApplicationFirewallConfiguration: isNull\"\r\n| order by id asc\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "7893f0b3-8622-1d47-beed-4b50a19f7895",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/application-gateway/overview-v2",
- "name": "Application Gateway Overview V2"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Use Application Gateway v2 for built-in features like autoscaling, static VIPs, Azure KeyVault integration for better traffic management and performance, unless v1 is necessary.\n",
- "pgVerified": true,
- "description": "Migrate to Application Gateway v2",
- "potentialBenefits": "Better performance, autoscaling, more features",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Get all Application Gateways, which are using the deprecated V1 SKU\r\nresources\r\n| where type =~ 'microsoft.network/applicationgateways'\r\n| extend tier = properties.sku.tier\r\n| where tier == 'Standard' or tier == 'WAF'\r\n| project recommendationId = \"7893f0b3-8622-1d47-beed-4b50a19f7895\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "5d035919-898d-a047-8d5d-454e199692e5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/application-gateway/application-gateway-metrics",
- "name": "Application Gateway Metrics"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Enable logging in storage accounts, Log Analytics, and monitoring services for auditing and insights.\n",
- "pgVerified": true,
- "description": "Monitor and Log the configurations and traffic",
- "potentialBenefits": "Enhanced traffic insight and audit",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "847a8d88-21c4-bc48-a94e-562206edd767",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/application-gateway/application-gateway-probe-overview",
- "name": "Application Gateway Probe Overview"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Using custom health probes enhances understanding of backend availability and facilitates monitoring of backend services for any impact.\n",
- "pgVerified": true,
- "description": "Use Health Probes to detect backend availability",
- "potentialBenefits": "Ensures backend uptime monitoring.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Application Gateways are not using health probes to monitor the availability of the backend systems\r\nresources\r\n| where type =~ \"microsoft.network/applicationGateways\"\r\n| where array_length(properties.probes) == 0\r\n| project recommendationId=\"847a8d88-21c4-bc48-a94e-562206edd767\", name, id, tags, param1=\"customHealthProbeUsed: false\"\r\n\r\n"
- },
- {
- "aprlGuid": "c9c00f2a-3888-714b-a72b-b4c9e8fcffb2",
- "recommendationTypeId": "5c488377-be3e-4365-92e8-09d1e8d9038c",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/services/networking/azure-application-gateway#reliability",
- "name": "Well-Architected Framework Application Gateway Reliability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Deploying Application Gateway in a zone-aware configuration ensures continued customer access to services even if a specific zone goes down, as services in other zones remain available.\n",
- "pgVerified": true,
- "description": "Deploy Application Gateway in a zone-redundant configuration",
- "potentialBenefits": "Enhanced uptime and customer access",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// list Application Gateways that are not configured to use at least 2 Availability Zones\r\nresources\r\n| where type =~ \"microsoft.network/applicationGateways\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where isnull(zones) or array_length(zones) < 2\r\n| extend zoneValue = iff((isnull(zones)), \"null\", zones)\r\n| project recommendationId = \"c9c00f2a-3888-714b-a72b-b4c9e8fcffb2\", name, id, tags, param1=\"Zones: No Zone or Zonal\", param2=strcat(\"Zones value: \", zoneValue )\r\n\r\n"
- },
- {
- "aprlGuid": "10f02bc6-e2e7-004d-a2c2-f9bf9f16b915",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/application-gateway/features#connection-draining",
- "name": "Application Gateway Connection Draining"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Using connection draining for backend maintenance ensures graceful removal of backend pool members during updates or health issues. It's enabled via Backend Setting and applies to all members during rule creation.\n",
- "pgVerified": true,
- "description": "Plan for backend maintenance by using connection draining",
- "potentialBenefits": "Smooth updates, no dropped users",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will check if connection draining is enabled\r\nresources\r\n| where type =~ \"microsoft.network/applicationGateways\"\r\n| mv-expand backendHttpSettings = properties.backendHttpSettingsCollection\r\n| extend connectionDrainingEnabled = backendHttpSettings.properties.connectionDraining.enabled\r\n| where connectionDrainingEnabled != true\r\n| extend backendPoolName = backendHttpSettings.name\r\n| project recommendationId = \"10f02bc6-e2e7-004d-a2c2-f9bf9f16b915\", name, id, tags, param1 = \"connectionDraining: Disabled\", param2 = strcat(\"backendSettingsName: \", backendPoolName)\r\n\r\n"
- },
- {
- "aprlGuid": "8364fd0a-7c0e-e240-9d95-4bf965aec243",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/application-gateway/configuration-infrastructure#size-of-the-subnet",
- "name": "Azure Application Gateway infrastructure configuration | Microsoft Learn"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Application Gateway v2 (Standard_v2 or WAF_v2 SKU) can support up to 125 instances. A /24 subnet isn't mandatory for deployment but is advised to provide enough space for autoscaling and maintenance upgrades.\n",
- "pgVerified": true,
- "description": "Ensure Application Gateway Subnet is using a /24 subnet mask",
- "potentialBenefits": "Allows autoscaling and maintenance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/applicationGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will validate the subnet id for an appGW ends with a /24\r\n\r\nresources\r\n| where type =~ 'Microsoft.Network/applicationGateways'\r\n| extend subnetid = tostring(properties.gatewayIPConfigurations[0].properties.subnet.id)\r\n| join kind=leftouter(resources\r\n | where type == \"microsoft.network/virtualnetworks\"\r\n | mv-expand properties.subnets\r\n | extend subnetid = tostring(properties_subnets.id)\r\n | extend addressprefix = tostring(properties_subnets.properties.addressPrefix)\r\n | project subnetid, addressprefix) on subnetid\r\n| where addressprefix !endswith '/24'\r\n| project recommendationId = \"8364fd0a-7c0e-e240-9d95-4bf965aec243\", name, id, tags, param1 = strcat('AppGW subnet prefix: ', addressprefix)\r\n\r\n"
- },
- {
- "aprlGuid": "c72b7fee-1fa0-5b4b-98e5-54bcae95bb74",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/framework/services/networking/azure-firewall",
- "name": "Azure Well Architected Framework - Azure Firewall"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Firewall offers different SLAs depending on its deployment; in a single availability zone or across multiple, potentially improving reliability and performance.\n",
- "pgVerified": true,
- "description": "Deploy Azure Firewall across multiple availability zones",
- "potentialBenefits": "Enhanced SLA and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/azureFirewalls",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// List all Azure Firewalls that are not configured with multiple availability zones or deployed without a zone\r\nresources\r\n| where type == 'microsoft.network/azurefirewalls'\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where array_length(zones) <= 1 or isnull(zones)\r\n| where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id)\r\n| project recommendationId = \"c72b7fee-1fa0-5b4b-98e5-54bcae95bb74\", name, id, tags, param1=\"multipleZones:false\"\r\n\r\n"
- },
- {
- "aprlGuid": "3c8fa7c6-6b78-a24a-a63f-348a7c71acb9",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-monitor/essentials/metrics-supported#microsoftnetworkazurefirewalls",
- "name": "Azure Firewall metrics supported in Azure Monitor"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Monitor Azure Firewall for overall health, processed throughput, and outbound SNAT port usage. Get alerted before limits impact services. Consider NAT gateway integration with zonal deployments; note limitations with zone redundant firewalls and secure virtual hub networks.\n",
- "pgVerified": true,
- "description": "Monitor Azure Firewall metrics",
- "potentialBenefits": "Improve health and performance monitoring",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/azureFirewalls",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// List all Azure Firewalls resources in-scope, along with any metrics associated to Azure Monitor alert rules, that are not fully configured.\r\nresources\r\n| where type == \"microsoft.network/azurefirewalls\"\r\n| project firewallId = tolower(id), name, tags\r\n| join kind = leftouter (\r\n resources\r\n | where type == \"microsoft.insights/metricalerts\"\r\n | mv-expand properties.scopes\r\n | mv-expand properties.criteria.allOf\r\n | where properties_scopes contains \"azureFirewalls\"\r\n | project metricId = tolower(properties_scopes), monitoredMetric = properties_criteria_allOf.metricName, tags\r\n | summarize monitoredMetrics = make_list(monitoredMetric) by tostring(metricId)\r\n | project\r\n metricId,\r\n monitoredMetrics,\r\n allAlertsConfigured = monitoredMetrics contains(\"FirewallHealth\") and monitoredMetrics contains (\"Throughput\") and monitoredMetrics contains (\"SNATPortUtilization\")\r\n) on $left.firewallId == $right.metricId\r\n| extend alertsNotFullyConfigured = isnull(allAlertsConfigured) or not(allAlertsConfigured)\r\n| where alertsNotFullyConfigured\r\n| project recommendationId = \"c8fa7c6-6b78-a24a-a63f-348a7c71acb9\", name, id = firewallId, tags, param1 = strcat(\"MetricsAlerts:\", monitoredMetrics)\r\n\r\n"
- },
- {
- "aprlGuid": "1b2dbf4a-8a0b-5e4b-8f4e-3f758188910d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/ddos-protection/ddos-protection-overview",
- "name": "Azure DDoS Protection overview"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Associate a DDoS protection plan with the virtual network hosting Azure Firewall to provide enhanced mitigation against DDoS attacks. Azure Firewall Manager integrates the creation of firewall infrastructure and DDoS protection plans.\n",
- "pgVerified": true,
- "description": "Configure DDoS Protection on the Azure Firewall VNet",
- "potentialBenefits": "Enhanced DDoS attack defense",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/azureFirewalls",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// List all in-scope Azure Firewall resources, where the VNet is not associated to a DDoS Protection Plan\r\nresources\r\n| where type =~ \"Microsoft.Network/azureFirewalls\"\r\n| where isempty(properties.virtualHub.id) or isnull(properties.virtualHub.id)\r\n| mv-expand ipConfig = properties.ipConfigurations\r\n| project\r\n name,\r\n firewallId = id,\r\n tags,\r\n vNetName = split(ipConfig.properties.subnet.id, \"/\", 8)[0],\r\n vNetId = tolower(substring(ipConfig.properties.subnet.id, 0, indexof(ipConfig.properties.subnet.id, \"/subnet\")))\r\n| join kind=fullouter (\r\n resources\r\n | where type =~ \"Microsoft.Network/ddosProtectionPlans\"\r\n | mv-expand vNet = properties.virtualNetworks\r\n | project ddosProtectionPlanId = id, vNetId = tolower(vNet.id)\r\n )\r\n on vNetId\r\n| where isempty(ddosProtectionPlanId)\r\n| project recommendationId = \"1b2dbf4a-8a0b-5e4b-8f4e-3f758188910d\", name, id = firewallId, tags, param1 = strcat(\"vNet: \", vNetName), param2 = \"ddosProtection: Disabled\"\r\n"
- },
- {
- "aprlGuid": "3a63560a-1ed3-6140-acd1-d1d23f9a2e12",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/firewall-manager/rule-hierarchy",
- "name": "Azure Firewall Policy hierarchy"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Azure Firewall policy supports rule hierarchies for compliance enforcement, using a central base policy with higher priority over child policies, and employs Azure custom roles to safeguard base policy and manage access within subscriptions or groups.\n",
- "pgVerified": true,
- "description": "Leverage Azure Firewall policy inheritance model",
- "potentialBenefits": "Enhanced compliance and rule hierarchy",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/azureFirewalls",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "d2e4a38e-2307-4299-a217-4c0cebc9a7f6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/service-guides/azure-firewall#recommendations",
- "name": "Azure Well-Architected Framework review - Azure Firewall"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Configure a minimum of two to four public IP addresses per Azure Firewall to avoid SNAT exhaustion. Azure Firewall offers SNAT for all outbound traffic to public IPs, providing 2,496 SNAT ports for each additional PIP.\n",
- "pgVerified": false,
- "description": "Configure 2-4 PIPs for SNAT Port utilization",
- "potentialBenefits": "Avoids SNAT exhaustion.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/azureFirewalls",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under development\r\n\r\n"
- },
- {
- "aprlGuid": "8faace2d-a36e-425c-aa58-2ad99e3e0b7a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/service-guides/azure-firewall#recommendations",
- "name": "Azure Well-Architected Framework review - Azure Firewall"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Using the Azure Firewall latency probe metric to monitor sustained latency over 30ms (accounting for normal spikes) can help identify when firewall instance CPU utilization is under stress, potentially indicating performance issues\n",
- "pgVerified": true,
- "description": "Monitor \"AZFW Latency Probe\" metric",
- "potentialBenefits": "Improved CPU stress detection",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/azureFirewalls",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under development\r\n\r\n"
- },
- {
- "aprlGuid": "c9b0c6f6-1f64-4b4b-8165-00770b295dd7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/reliability/reliability-bastion",
- "name": "Reliability in Azure Bastion"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure Bastion provides secure operational access to workload components. By distributing your Bastion resource across multiple availability zones, you can enhance the resiliency and reliability of your production workloads.\n",
- "pgVerified": true,
- "description": "Deploy Azure Bastion across Availability Zones",
- "potentialBenefits": "Provide high availability and resilience to failures",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/bastionHosts",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "0e57956d-71d9-4a35-bdcf-d7cfd7cd71f4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/reliability/reliability-bastion#multi-region-support",
- "name": "Multi-region support in Azure bastion"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Azure Bastion is a single-region service, if the primary region becomes unavailable, the Bastion resource will also be unavailable. To ensure disaster recovery, it is recommended to deploy Azure Bastion into separate virtual networks across different regions.\n",
- "pgVerified": true,
- "description": "Deploy Azure Bastion into the virtual network in secondary Azure region",
- "potentialBenefits": "Provides disaster recovery from regional outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/bastionHosts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "f6a14b32-a727-4ace-b5fa-7b1c6bdff402",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/expressroute/about-fastpath",
- "name": "About ExpressRoute FastPath"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "ExpressRoute gateways facilitate network traffic and route exchanges. FastPath enhances on-premises to virtual network data path performance by directing traffic straight to virtual machines, bypassing the gateway for improved resiliency through reduced gateway utilization.\n",
- "pgVerified": true,
- "description": "For better data path performance enable FastPath on ExpressRoute Connections",
- "potentialBenefits": "Enhances speed and resiliency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/connections",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// Azure Resource Graph Query\r\n// Find all ExpressRoute Connections that are connected to ErGw3AZ or UltraPerformance gateway sku that don't have\r\n// FastPath enabled for both the Gateway Bypass or Private Endpoint/Link service.\r\nresources\r\n| where type == \"microsoft.network/connections\"\r\n| where properties.connectionType =~ 'expressroute'\r\n| extend gatewayId = tostring(properties.virtualNetworkGateway1.id)\r\n| join kind=inner (\r\n resources\r\n | where type =~ \"Microsoft.Network/virtualNetworkGateways\"\r\n | where properties.sku.name in~ (\"ErGw3AZ\", \"UltraPerformance\")\r\n | extend gatewayId = tostring(id)\r\n) on gatewayId\r\n| extend erGatewayBypass = tobool(properties.expressRouteGatewayBypass)\r\n| extend privateLinkFastPath = tobool(properties.enablePrivateLinkFastPath)\r\n| where not(erGatewayBypass) or not(privateLinkFastPath)\r\n| project recommendationId = \"f6a14b32-a727-4ace-b5fa-7b1c6bdff402\", id, name, tags,\r\n param1 = iff(erGatewayBypass, \"Enabled: Gateway Bypass\", \"Disabled: Gateway Bypass\"),\r\n param2 = iff(privateLinkFastPath, \"Enabled: PE FastPath\", \"Disabled: PE FastPath\")\r\n"
- },
- {
- "aprlGuid": "a5f3a4bd-4cf1-4196-a3cb-f5a0876198b2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/lock-resources?tabs=json",
- "name": "Protect your Azure resources with a lock - Azure Resource Manager | Microsoft Learn"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Configure an Azure Resource lock for Gateway Connection resources to prevent accidental deletion and maintain connectivity between on-premises networks and Azure workloads.\n",
- "pgVerified": true,
- "description": "Configure an Azure Resource Lock on connections to prevent accidental deletion",
- "potentialBenefits": "Prevents accidental deletion of connections",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/connections",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "ae054bf2-aefa-cf4a-8282-741194cef8da",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/ddos-protection/monitor-ddos-protection-reference",
- "name": "Monitoring Azure DDoS Protection"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Azure DDoS Plan metrics differentiate packets and bytes by tags: Dropped (packets scrubbed by DDoS), Forwarded (packets to VIP not filtered), and No tag (total packets, sum of dropped and forwarded).\n",
- "pgVerified": true,
- "description": "Monitor Azure DDoS Protection Plan metrics",
- "potentialBenefits": "Enhanced security and traffic insight",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/ddosProtectionPlans",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "bdd38c02-96bf-4d4e-a636-293729463f3d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/dns/private-resolver-reliability",
- "name": "Resiliency in Azure DNS Private Resolver"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Deploy Azure DNS Private Resolvers across multiple regions to establish cross-region failover.\n",
- "pgVerified": false,
- "description": "Setup DNS cross-region failover using Azure DNS Private Resolvers",
- "potentialBenefits": "Ensures BCDR during regional outages.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/dnsResolvers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "7d09523b-b3c0-403e-b104-d5d46240d683",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/reliability/reliability-dns",
- "name": "Reliability in Azure DNS"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Azure DNS allows the Time-To-Live (TTL) for record sets in the zone to be set to a value between 1 and 2147483647 seconds. You should ensure that the TTL for the DNS record sets in your DNS Zones are set appropriately to meet your RTO targets.\n",
- "pgVerified": false,
- "description": "Ensure Time-To-Live (TTL) is set appropriately to ensure RTOs can be met",
- "potentialBenefits": "Ensures that no cached DNS records exist past RTO targets",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/dnsZones",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "4d703025-dafc-f840-a183-5dc440456134",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering",
- "name": "Designing for disaster recovery with ExpressRoute private peering"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Connecting each ExpressRoute Gateway to a minimum of two circuits in different peering locations enhances redundancy and reliability by ensuring alternate pathways for data in case one circuit fails.\n",
- "pgVerified": true,
- "description": "Connect on-prem networks to Azure critical workloads via multiple ExpressRoutes peering locations",
- "potentialBenefits": "Enhanced reliability and redundancy",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteCircuits",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "0e19cc41-8274-1342-b0db-0e4146eacef8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/expressroute/designing-for-high-availability-with-expressroute",
- "name": "Designing for high availability with ExpressRoute"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Microsoft or the ExpressRoute provider always ensures physical redundancy in their services. It's essential to maintain this level of physical redundancy (two devices, two links) from the ExpressRoute peering location to your network for optimal performance and reliability.\n",
- "pgVerified": true,
- "description": "Ensure ExpressRoute's physical links connect to distinct network edge devices",
- "potentialBenefits": "Enhanced reliability and fault tolerance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteCircuits",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "f06a2bbe-5839-d447-9f39-fc3d20562d88",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/designing-for-high-availability-with-expressroute#active-active-connections",
- "name": "Designing for high availability with ExpressRoute - Active-active connections"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Operating both connections of an ExpressRoute circuit in active-active mode enhances high availability as the Microsoft network will load balance the traffic across the connections on a per-flow basis.\n",
- "pgVerified": true,
- "description": "Ensure both connections of an ExpressRoute are configured in active-active mode",
- "potentialBenefits": "Improved high availability and load balancing",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteCircuits",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "2a5bf650-586d-db4c-a292-d922be7d3e0e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/expressroute-bfd",
- "name": "Configure BFD over ExpressRoute"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Enabling BFD over ExpressRoute speeds up link failure detection between MSEE devices and routers configured for ExpressRoute (CE/PE), applicable over both customer and Partner Edge routing devices with managed Layer 3 service.\n",
- "pgVerified": true,
- "description": "Activate Bidirectional Forwarding Detection on edge devices for faster failover",
- "potentialBenefits": "Faster link failure detection",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteCircuits",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "9771a435-d031-814e-9827-9b5fdafc0f87",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://azure.github.io/azure-monitor-baseline-alerts/services/Network/expressRouteCircuits/",
- "name": "Azure Monitor Baseline Alerts - expressRouteCircuits"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Use Network Insights for monitoring ExpressRoute circuit availability, QoS, and throughput. Set alerts based on Azure Monitor Baseline Alerts for availability, QoS metrics, and throughput metrics exceeding specific thresholds.\n",
- "pgVerified": true,
- "description": "Configure monitoring and alerting for ExpressRoute circuits",
- "potentialBenefits": "Enhanced network performance and health",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteCircuits",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "26cb547f-aabc-dc40-be02-d0a9b6b04b1a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/maintenance-alerts",
- "name": "How to view and configure alerts for Azure ExpressRoute circuit maintenance"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "ExpressRoute leverages service health for notifications on both planned and unplanned maintenance, ensuring users are informed about any changes to their ExpressRoute circuits.\n",
- "pgVerified": true,
- "description": "Configure service health to receive ExpressRoute circuit maintenance notification",
- "potentialBenefits": "Stay informed on circuit updates",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteCircuits",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "d40c769d-2f08-4980-8d8f-a386946276e6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/expressroute/rate-limit",
- "name": "Rate limiting for ExpressRoute Direct circuits (Preview)"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Rate limiting controls traffic volume between on-premises networks and Azure via ExpressRoute Direct, applying to private or Microsoft peering. It distributes port bandwidth, ensures stability, and prevents congestion, with steps outlined for enabling on circuits.\n",
- "pgVerified": true,
- "description": "Implement rate-limiting across ExpressRoute Direct Circuits to optimize network flow",
- "potentialBenefits": "Optimizes network, prevents congestion",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteCircuits",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will return all the ExpressRoute circuits (Direct Based) that have Direct Port Rate Limiting disabled\r\nresources\r\n| where type =~ \"microsoft.network/expressroutecircuits\"\r\n| where properties.expressRoutePort != \"\" or isnotnull(properties.expressRoutePort)\r\n| where properties.enableDirectPortRateLimit == false\r\n| project recommendationId = \"d40c769d-2f08-4980-8d8f-a386946276e6\", name, id, tags, param1=strcat(\"enableDirectPortRateLimit: \",properties.enableDirectPortRateLimit)\r\n"
- },
- {
- "aprlGuid": "9987c813-d687-4163-a511-95f31bc5e536",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering",
- "name": "Designing for disaster recovery with ExpressRoute private peering"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For improved reliability, each ExpressRoute gateway should connect to at least two circuits, with each circuit sourced from a different peering location. This setup ensures diverse connectivity paths, enhancing resilience and minimizing service disruption risks.\n",
- "pgVerified": true,
- "description": "Connect ExpressRoute gateway with circuits from diverse peering locations",
- "potentialBenefits": "Enhanced resilience through diverse connectivity paths",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "17e8d380-e4b4-41a1-9b37-2e4df9fd5125",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-wan/monitoring-best-practices#expressroute-gateway",
- "name": "Virtual WAN Monitoring Best Practices"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Set up monitoring and alerts for ExpressRoute Gateway. Create alert rule for ensuring promptly response to critical events such as exceeding packets per second, exceeding BGP routes prefixes, Gateway overutilization and high frequency in route changes.\n",
- "pgVerified": true,
- "description": "Monitor health for ExpressRoute gateway",
- "potentialBenefits": "Detection and mitigation to avoid disruptions.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRouteGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "60077378-7cb1-4b35-89bb-393884d9921d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/expressroute/expressroute-howto-erdirect#state",
- "name": "How to configure ExpressRoute Direct Change Admin State of links"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "In Azure ExpressRoute Direct, the \"Admin State\" indicates the administrative status of layer 1 links, showing if a link is enabled or disabled, effectively turning the physical port on or off.\n",
- "pgVerified": true,
- "description": "The Admin State of both Links of an ExpressRoute Direct should be in Enabled state",
- "potentialBenefits": "Ensures optimal connectivity.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/ExpressRoutePorts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Express Route Directs that do not have Admin State of both Links Enabled\r\nresources\r\n| where type == \"microsoft.network/expressrouteports\"\r\n| where properties['links'][0]['properties']['adminState'] == \"Disabled\" or properties['links'][1]['properties']['adminState'] == \"Disabled\"\r\n| project recommendationId = \"60077378-7cb1-4b35-89bb-393884d9921d\", name, id, tags, param1 = strcat(\"Link1AdminState: \", properties['links'][0]['properties']['adminState']), param2 = strcat(\"Link2AdminState: \", properties['links'][1]['properties']['adminState'])\r\n\r\n"
- },
- {
- "aprlGuid": "0bee356b-7348-4799-8cab-0c71ffe13018",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/expressroute/expressroute-erdirect-about?source=recommendations#circuit-sizes",
- "name": "About ExpressRoute Direct Circuit Sizes"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Provisioning ExpressRoute circuits on a 10-Gbps or 100-Gbps ExpressRoute Direct resource up to 20-Gbps or 200-Gbps is possible but not recommended for resiliency. If an ExpressRoute Direct port fails, and circuits are using full capacity, the remaining port won't handle the extra load.\n",
- "pgVerified": false,
- "description": "Ensure ExpressRoute Direct is not over-subscribed",
- "potentialBenefits": "Improves resilience during port failures",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/ExpressRoutePorts",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Express Route Directs that are over subscribed\r\nresources\r\n| where type == \"microsoft.network/expressrouteports\"\r\n| where toint(properties['provisionedBandwidthInGbps']) > toint(properties['bandwidthInGbps'])\r\n| project recommendationId = \"0bee356b-7348-4799-8cab-0c71ffe13018\", name, id, tags, param1 = strcat(\"provisionedBandwidthInGbps: \", properties['provisionedBandwidthInGbps']), param2 = strcat(\"bandwidthInGbps: \", properties['bandwidthInGbps'])\r\n\r\n"
- },
- {
- "aprlGuid": "55815823-d588-4cb7-a5b8-ae581837356e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://azure.github.io/azure-monitor-baseline-alerts/services/Network/expressRoutePorts/",
- "name": "Azure Monitor Baseline Alerts - expressRoutePorts"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Use Network Insights for monitoring ExpressRoute Port light levels, bits per second in/out, and line protocol. Set alerts based on Azure Monitor Baseline Alerts for light levels, bits per second in/out, and line protocol exceeding specific thresholds.\n",
- "pgVerified": false,
- "description": "Configure monitoring and alerting for ExpressRoute Ports",
- "potentialBenefits": "Enhanced network performance and health",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRoutePorts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "cce3353a-f409-4559-9959-0ca0e3717114",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering",
- "name": "Designing for disaster recovery with ExpressRoute private peering"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Ensure resilient connectivity by connecting on-premises networks to Azure through multiple ExpressRoutes, each originating from distinct peering locations, to provide alternate data paths in case of a peering location failure.\n",
- "pgVerified": true,
- "description": "Connect on-prem networks to Azure critical workloads via multiple ExpressRoutes peering locations",
- "potentialBenefits": "Enhanced reliability and redundancy",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRoutePorts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "222fbb78-be76-4855-a14f-a5e17ef1ccf5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/expressroute/designing-for-high-availability-with-expressroute",
- "name": "Designing for high availability with ExpressRoute"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Microsoft or the ExpressRoute provider always ensures physical redundancy in their services. It's essential to maintain this level of physical redundancy (two devices, two links) from the ExpressRoute peering location to your network for optimal performance and reliability.\n",
- "pgVerified": true,
- "description": "Ensure ExpressRoute's physical links connect to distinct network edge devices",
- "potentialBenefits": "Enhanced reliability and fault tolerance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRoutePorts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "859886df-3996-4eab-8439-c1a38c416e0e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/designing-for-high-availability-with-expressroute#active-active-connections",
- "name": "Designing for high availability with ExpressRoute - Active-active connections"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Operating both connections of an ExpressRoute circuit in active-active mode enhances high availability as the Microsoft network will load balance the traffic across the connections on a per-flow basis.\n",
- "pgVerified": true,
- "description": "Ensure both connections of an ExpressRoute are configured in active-active mode",
- "potentialBenefits": "Improved high availability and load balancing",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/expressRoutePorts",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "d0cfe47f-686b-5043-bf83-5a3868acb80a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/web-application-firewall/afds/waf-front-door-monitor?pivots=front-door-standard-premium#access-logs",
- "name": "Azure Web Application Firewall monitoring and logging - Access Log"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "WAF may mistakenly block legitimate requests (false positives). These can be identified by examining the last 24 hours of blocked requests in Log Analytics.\n",
- "pgVerified": true,
- "description": "Inspect Azure Front Door WAF logs for wrongfully blocked legitimate requests",
- "potentialBenefits": "Reduces false positives, improves access",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/frontdoorWebApplicationFirewallPolicies",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "537b4d94-edd1-4041-b13d-8217dfa485f0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/web-application-firewall/ag/application-gateway-waf-metrics#logs-and-diagnostics",
- "name": "Azure Web Application Firewall Monitoring and Logging"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "WAF may block legitimate requests as false positives. Identifying blocked requests within the last 24 hours through Log Analytics can help manage and mitigate these incorrect blockages efficiently.\n",
- "pgVerified": true,
- "description": "Check Azure Application Gateway WAF logs for mistakenly blocked valid requests",
- "potentialBenefits": "Improve false positive identification",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/frontdoorWebApplicationFirewallPolicies",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "5357ae22-0f52-1a49-9fd4-1f00ace6add0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/web-application-firewall/ag/ag-overview#waf-monitoring",
- "name": "WAF monitoring"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Monitoring the health of your Web Application Firewall and the applications it protects is crucial. This can be achieved through integration with Microsoft Defender for Cloud, Azure Monitor, and Azure Monitor logs, ensuring optimal performance and security.\n",
- "pgVerified": false,
- "description": "Monitor Web Application Firewall",
- "potentialBenefits": "Enhanced security and health insight",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/frontdoorWebApplicationFirewallPolicies",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "38c3bca1-97a1-eb42-8cd3-838b243f35ba",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/framework/services/networking/azure-load-balancer/reliability",
- "name": "Reliability and Azure Load Balancer"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Selecting Standard SKU Load Balancer enhances reliability through availability zones and zone resiliency, ensuring deployments withstand zone and region failures. Unlike Basic, it supports global load balancing and offers an SLA.\n",
- "pgVerified": true,
- "description": "Use Standard Load Balancer SKU",
- "potentialBenefits": "Enhanced reliability and SLA support",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/loadBalancers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all LoadBalancers using Basic SKU\r\nresources\r\n| where type =~ 'Microsoft.Network/loadBalancers'\r\n| where sku.name == 'Basic'\r\n| project recommendationId = \"38c3bca1-97a1-eb42-8cd3-838b243f35ba\", name, id, tags, Param1=strcat(\"sku-tier: basic\")\r\n\r\n"
- },
- {
- "aprlGuid": "6d82d042-6d61-ad49-86f0-6a5455398081",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/checklist/resiliency-per-service#azure-load-balancer",
- "name": "Resiliency checklist for specific Azure services- Azure Load Balancer"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Deploying Azure Load Balancers with at least two instances in the backend prevents a single point of failure and supports scalability. Pairing with Virtual Machine Scale Sets is advised for optimal scale building.\n",
- "pgVerified": true,
- "description": "Ensure the Backend Pool contains at least two instances",
- "potentialBenefits": "Enhances reliability and scalability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/loadBalancers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all LoadBalancers which only have 1 backend pool defined or only 1 VM in the backend pool\r\nresources\r\n| where type =~ 'Microsoft.Network/loadBalancers'\r\n| extend bep = properties.backendAddressPools\r\n| extend BackEndPools = array_length(bep)\r\n| where BackEndPools == 0\r\n| project recommendationId = \"6d82d042-6d61-ad49-86f0-6a5455398081\", name, id, Param1=\"backendPools\", Param2=toint(0), tags\r\n| union (resources\r\n | where type =~ 'Microsoft.Network/loadBalancers'\r\n | where sku.name == \"Standard\"\r\n | extend bep = properties.backendAddressPools\r\n | extend BackEndPools = toint(array_length(bep))\r\n | mv-expand bip = properties.backendAddressPools\r\n | extend BackendAddresses = array_length(bip.properties.loadBalancerBackendAddresses)\r\n | where toint(BackendAddresses) <= 1\r\n | project recommendationId = \"6d82d042-6d61-ad49-86f0-6a5455398081\", name, id, tags, Param1=\"backendAddresses\", Param2=toint(BackendAddresses))\r\n| union (\r\n resources\r\n | where type =~ 'Microsoft.Network/loadBalancers'\r\n | where sku.name == \"Basic\"\r\n | mv-expand properties.backendAddressPools\r\n | extend backendPoolId = properties_backendAddressPools.id\r\n | project id, name, tags, tostring(backendPoolId), recommendationId = \"6d82d042-6d61-ad49-86f0-6a5455398081\", Param1=\"BackEndPools\"\r\n | join kind = leftouter (\r\n resources\r\n | where type =~ \"Microsoft.Network/networkInterfaces\"\r\n | mv-expand properties.ipConfigurations\r\n | mv-expand properties_ipConfigurations.properties.loadBalancerBackendAddressPools\r\n | extend backendPoolId = tostring(properties_ipConfigurations_properties_loadBalancerBackendAddressPools.id)\r\n | summarize poolMembers = count() by backendPoolId\r\n | project tostring(backendPoolId), poolMembers ) on backendPoolId\r\n | where toint(poolMembers) <= 1\r\n | extend BackendAddresses = poolMembers\r\n | project id, name, tags, recommendationId, Param1=\"backendAddresses\", Param2=toint(BackendAddresses))\r\n"
- },
- {
- "aprlGuid": "8d319a05-677b-944f-b9b4-ca0fb42e883c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/checklist/resiliency-per-service#azure-load-balancer",
- "name": "Resiliency checklist for specific Azure services- Azure Load Balancer"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Outbound rules for Standard Public Load Balancer involve manual port allocation for backend pools, limiting scalability and risk of SNAT port exhaustion. NAT Gateway is recommended for its dynamic scaling and secure internet connectivity.\n",
- "pgVerified": true,
- "description": "Use NAT Gateway instead of Outbound Rules for Production Workloads",
- "potentialBenefits": "Enhanced scalability and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/loadBalancers",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all LoadBalancers with Outbound rules configured\r\nresources\r\n| where type =~ 'Microsoft.Network/loadBalancers'\r\n| extend outboundRules = array_length(properties.outboundRules)\r\n| where outboundRules > 0\r\n| project recommendationId = \"8d319a05-677b-944f-b9b4-ca0fb42e883c\", name, id, tags, Param1 = \"outboundRules: >=1\"\r\n\r\n"
- },
- {
- "aprlGuid": "621dbc78-3745-4d32-8eac-9e65b27b7512",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/load-balancer/load-balancer-standard-availability-zones#zone-redundant",
- "name": "Load Balancer and Availability Zones"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "In regions with Availability Zones, assigning a zone-redundant frontend IP to a Standard Load Balancer ensures continuous traffic distribution even if one availability zone fails, provided other healthy zones and backend instances are available to receive the traffic.\n",
- "pgVerified": true,
- "description": "Ensure Standard Load Balancer is zone-redundant",
- "potentialBenefits": "Enhances uptime and resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/loadBalancers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all LoadBalancers with with regional or zonal public IP Addresses\r\nresources\r\n| where type == \"microsoft.network/loadbalancers\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where tolower(sku.name) != 'basic'\r\n| mv-expand feIPconfigs = properties.frontendIPConfigurations\r\n| extend\r\n feConfigName = (feIPconfigs.name),\r\n PrivateSubnetId = toupper(feIPconfigs.properties.subnet.id),\r\n PrivateIPZones = feIPconfigs.zones,\r\n PIPid = toupper(feIPconfigs.properties.publicIPAddress.id),\r\n JoinID = toupper(id)\r\n| where isnotempty(PrivateSubnetId)\r\n| where isnull(PrivateIPZones) or array_length(PrivateIPZones) < 2\r\n| project name, feConfigName, id\r\n| union (resources\r\n | where type == \"microsoft.network/loadbalancers\"\r\n | where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n | where tolower(sku.name) != 'basic'\r\n | mv-expand feIPconfigs = properties.frontendIPConfigurations\r\n | extend\r\n feConfigName = (feIPconfigs.name),\r\n PIPid = toupper(feIPconfigs.properties.publicIPAddress.id),\r\n JoinID = toupper(id)\r\n | where isnotempty(PIPid)\r\n | join kind=innerunique (\r\n resources\r\n | where type == \"microsoft.network/publicipaddresses\"\r\n | where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n | where isnull(zones) or array_length(zones) < 2\r\n | extend\r\n LBid = toupper(substring(properties.ipConfiguration.id, 0, indexof(properties.ipConfiguration.id, '/frontendIPConfigurations'))),\r\n InnerID = toupper(id)\r\n ) on $left.PIPid == $right.InnerID)\r\n| project recommendationId = \"621dbc78-3745-4d32-8eac-9e65b27b7512\", name, id, tags, param1=\"Zones: No Zone or Zonal\", param2=strcat(\"Frontend IP Configuration:\", \" \", feConfigName)\r\n\r\n"
- },
- {
- "aprlGuid": "e5f5fcea-f925-4578-8599-9a391e888a60",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/load-balancer/load-balancer-custom-probe-overview",
- "name": "Load Balancer Health Probe Overview"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Health probes are used by Azure Load Balancers to determine the status of backend endpoints. Using custom health probes that are aligned with vendor recommendations enhances understanding of backend availability and facilitates monitoring of backend services for any impact.\n",
- "pgVerified": true,
- "description": "Use Health Probes to detect backend instances availability",
- "potentialBenefits": "Ensures backend uptime monitoring.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/loadBalancers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// List the load balancers which don't have health probe configured\r\nresources\r\n| where type =~ \"microsoft.network/loadbalancers\"\r\n| where array_length(properties.probes) == 0\r\n| project recommendationId=\"e5f5fcea-f925-4578-8599-9a391e888a60\", name, id, tags, param1=\"customHealthProbeUsed: false\"\r\n"
- },
- {
- "aprlGuid": "babf75d6-6407-4d90-b01e-5a1768e621f5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/nat-gateway/nat-metrics",
- "name": "What is Azure NAT Gateway metrics and alerts?"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Use Network Insights for monitoring and alerting on your NAT gateway.Use Total SNAT connection count metric to determine if you're nearing the connection limit of NAT gateway. Set alerts based on Azure Monitor Baseline Alerts (AMBA) thresholds for NAT Gateway\n",
- "pgVerified": true,
- "description": "Configure monitoring and alerting for NAT gateway",
- "potentialBenefits": "Enhanced network performance and health",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/natGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "d2976d3e-294b-4b49-a1f0-c42566a3758f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-monitor/essentials/diagnostic-settings",
- "name": "Diagnostic settings in Azure Monitor"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Resource Logs are not collected and stored until you create a diagnostic setting and route them to one or more locations.\n",
- "pgVerified": true,
- "description": "Configure Diagnostic Settings for all network security groups",
- "potentialBenefits": "Enhanced monitoring and security insights",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/networkSecurityGroups",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "8bb4a57b-55e4-d24e-9c19-2679d8bc779f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-monitor/essentials/activity-log?tabs=powershell",
- "name": "Azure Monitor activity log"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Create Alerts with Azure Monitor for operations like creating or updating Network Security Group rules to catch unauthorized/undesired changes to resources and spot attempts to bypass firewalls or access resources from the outside.\n",
- "pgVerified": true,
- "description": "Monitor changes in Network Security Groups with Azure Monitor",
- "potentialBenefits": "Enhanced security and change monitoring",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/networkSecurityGroups",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Network Security Groups without alerts for modification configured.\r\nresources\r\n| where type =~ \"Microsoft.Network/networkSecurityGroups\"\r\n| project name, id, tags, lowerCaseNsgId = tolower(id)\r\n| join kind = leftouter (\r\n resources\r\n | where type =~ \"Microsoft.Insights/activityLogAlerts\" and properties.enabled == true\r\n | mv-expand scope = properties.scopes\r\n | where scope has \"Microsoft.Network/networkSecurityGroups\"\r\n | project alertName = name, conditionJson = dynamic_to_json(properties.condition.allOf), scope\r\n | where conditionJson has '\"Administrative\"' and (\r\n // Create or Update Network Security Group\r\n (conditionJson has '\"Microsoft.Network/networkSecurityGroups/write\"') or\r\n // All administrative operations\r\n (conditionJson !has '\"Microsoft.Network/networkSecurityGroups/write\"' and conditionJson !has '\"Microsoft.Network/networkSecurityGroups/delete\"' and conditionJson !has '\"Microsoft.Network/networkSecurityGroups/join/action\"')\r\n )\r\n | project lowerCaseNsgIdOfScope = tolower(scope)\r\n )\r\n on $left.lowerCaseNsgId == $right.lowerCaseNsgIdOfScope\r\n| where isempty(lowerCaseNsgIdOfScope)\r\n| project recommendationId = \"8bb4a57b-55e4-d24e-9c19-2679d8bc779f\", name, id, tags, param1 = \"ModificationAlert: Not configured/Disabled\"\r\n\r\n"
- },
- {
- "aprlGuid": "52ac35e8-9c3e-f84d-8ce8-2fab955333d3",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-resource-manager/management/lock-resources?toc=%2Fazure%2Fvirtual-network%2Ftoc.json&tabs=json",
- "name": "Lock your resources to protect your infrastructure"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "As an administrator, you can lock an Azure subscription, resource group, or resource to protect them from accidental deletions and modifications. The lock overrides user permissions. Locks can prevent either deletions or modifications and are known as Delete and Read-only in the portal.\n",
- "pgVerified": true,
- "description": "Configure locks for Network Security Groups to avoid accidental changes and/or deletion",
- "potentialBenefits": "Prevents accidental edits/deletions",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/networkSecurityGroups",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "8291c1fa-650c-b44b-b008-4deb7465919d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/network-security-groups-overview#security-rules",
- "name": "Security rules"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Azure network security groups filter network traffic between resources in a virtual network, using security rules to allow or deny inbound or outbound traffic based on source, destination, port, and protocol.\n",
- "pgVerified": true,
- "description": "The NSG only has Default Security Rules, make sure to configure the necessary rules",
- "potentialBenefits": "Enhanced traffic control and security",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/networkSecurityGroups",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will return all NSGs that have NO security rules\r\nresources\r\n| where type =~ \"microsoft.network/networksecuritygroups\"\r\n| extend sr = string_size(properties.securityRules)\r\n| where sr <=2 or isnull(properties.securityRules)\r\n| project recommendationId = \"8291c1fa-650c-b44b-b008-4deb7465919d\", name, id\r\n\r\n"
- },
- {
- "aprlGuid": "4e133bd0-8762-bc40-a95b-b29142427d73",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/network-watcher/network-watcher-overview",
- "name": "What is Azure Network Watcher?"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Azure Network Watcher offers tools for monitoring, diagnosing, viewing metrics, and managing logs for IaaS resources. It helps maintain the health of VMs, VNets, application gateways, load balancers, but not for PaaS or Web analytics.\n",
- "pgVerified": true,
- "description": "Deploy Network Watcher in all regions where you have networking services",
- "potentialBenefits": "Enhanced monitoring and diagnostics for Azure IaaS",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/networkWatchers",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "22a769ed-0ecb-8b49-bafe-8f52e6373d9c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/network-watcher/nsg-flow-logging",
- "name": "Manage NSG flow logs using the Azure portal"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Network security group flow logging is a feature of Azure Network Watcher that logs IP traffic info through a network security group. If in Failed state, monitoring data from the associated resource is not collected.\n",
- "pgVerified": true,
- "description": "Fix Flow Log configurations in Failed state or Disabled Status",
- "potentialBenefits": "Ensures IP traffic logging",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/networkWatchers",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will return all Network Watcher Flow Logs that are not enabled or not in a succeeded state\r\nresources\r\n| where type =~ \"microsoft.network/networkwatchers/flowlogs\" and isnotnull(properties)\r\n| extend targetResourceId = tostring(properties.targetResourceId)\r\n| extend status = iff(properties.enabled =~ 'true', \"Enabled\", \"Disabled\")\r\n| extend provisioningState = tostring(properties.provisioningState)\r\n| extend flowLogType = iff(properties.targetResourceId contains \"Microsoft.Network/virtualNetworks\", 'Virtual network', 'Network security group')\r\n| where provisioningState != \"Succeeded\" or status != \"Enabled\"\r\n| project recommendationId = \"22a769ed-0ecb-8b49-bafe-8f52e6373d9c\", name, id, tags, param1 = strcat(\"provisioningState:\", provisioningState), param2=strcat(\"Status:\", status), param3=strcat(\"targetResourceId:\",targetResourceId), param4=strcat(\"flowLogType:\",flowLogType)\r\n\r\n"
- },
- {
- "aprlGuid": "1e28bbc1-1eb7-486f-8d7f-93943f40219c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/network-watcher/connection-monitor-overview",
- "name": "Connection monitor overview"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Improves monitoring for Azure and Hybrid connectivity\n",
- "pgVerified": true,
- "description": "Configure Network Watcher Connection monitor",
- "potentialBenefits": "Improves monitoring for Azure and Hybrid connectivity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/networkWatchers",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "bf0b7dbd-016d-458c-af99-70fcb03ad451",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/network-watcher/traffic-analytics",
- "name": "Network Watcher traffic analytics"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Improves monitoring, security and troubleshooting for Azure and Hybrid connectivity\n",
- "pgVerified": true,
- "description": "Enable traffic analytics in Virtual Network Flow Logs configuration",
- "potentialBenefits": "Improves monitoring, security and troubleshooting.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/networkWatchers",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// Azure Resource Graph Query\r\n// This query will return all Flow Logs where Flow Analytics Configuration is disabled\r\nresources\r\n| where type =~ \"microsoft.network/networkwatchers/flowlogs\"\r\n| where properties.targetResourceId contains \"microsoft.network/virtualNetworks\"\r\n| where not(properties.flowAnalyticsConfiguration.networkWatcherFlowAnalyticsConfiguration.enabled)\r\n| project recommendationId = \"bf0b7dbd-016d-458c-af99-70fcb03ad451\", name, id, tags, param1= \"Flow Analytics Configuration is disabled\",param2=strcat(\"Vnet Name : \", properties.targetResourceId)\r\n"
- },
- {
- "aprlGuid": "fd43ea32-2ccf-49a8-ada4-9a78794e3ff1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-wan/monitoring-best-practices#point-to-site-vpn-gateway",
- "name": "Virtual WAN Monitoring Best Practices"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Set up monitoring and alerts for Point-to-Site VPN gateways. Create alert rule for ensuring promptly response to critical events such as Gateway over utilization, connection count limits and User VPN route limits. Mission Critical workloads should use dual ExpressRoutes instead of VPN.\n",
- "pgVerified": false,
- "description": "Monitor health for v-Hub's Point-to-Site VPN gateways",
- "potentialBenefits": "Detection and mitigation to avoid disruptions.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/p2sVpnGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "2820f6d6-a23c-7a40-aec5-506f3bd1aeb6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/dns/dns-protect-private-zones-recordsets",
- "name": "Protecting private DNS Zones and Records - Azure DNS"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Assign the built-in Private DNS Zone Contributor role to specific authorized users, groups, and entities to protect against unauthorized or accidental changes to Private DNS Zones and records. Restrict access by granting Private DNS Zone Contributor permission to all zones.\n",
- "pgVerified": true,
- "description": "Protect private DNS zones and records",
- "potentialBenefits": "Prevents DNS outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/privateDnsZones",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "ab896e8c-49b9-2c44-adec-98339aff7821",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://azure.github.io/azure-monitor-baseline-alerts/services/Network/privateDnsZones/",
- "name": "Azure Monitor Baseline Alerts - privateDnsZones"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Use Azure Monitor to monitor Private DNS Zone query volume, record set count, and capacity metrics for Record Set, Virtual Network Link, and Virtual Network Link with auto-registration. Create alerts based on Azure Monitor Baseline Alerts for these metrics that exceed specific thresholds.\n",
- "pgVerified": true,
- "description": "Monitor Private DNS Zones health and set up alerts",
- "potentialBenefits": "Enhanced DNS reliability and alerting",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/privateDnsZones",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1e02335c-1f90-fd4e-a5a5-d359c7b22d70",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/private-link-and-dns-integration-at-scale",
- "name": "Private Link and DNS integration at scale"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "For business continuity scenarios with a low recovery time objective (RTO), ensure that distinct regional production and disaster recovery (DR) Private DNS Zones are configured and have identical workload and resource DNS entries. This keeps DNS resolution consistent across both zones.\n",
- "pgVerified": true,
- "description": "Use regional Private DNS Zones when there is a low recovery time objective (RTO) requirement",
- "potentialBenefits": "Ensures seamless failover for DNS during a regional outage",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/privateDnsZones",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "3538aa48-c40b-455b-a93b-269fe6e65be2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/reliability/reliability-dns",
- "name": "Reliability in Azure DNS"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Azure Private DNS allows the Time-To-Live (TTL) for record sets in the zone to be set to a value between 1 and 2147483647 seconds. You should ensure that the TTL for the DNS record sets in your DNS Zones are set appropriately to meet your RTO targets.\n",
- "pgVerified": false,
- "description": "Ensure Time-To-Live (TTL) is set appropriately to ensure RTOs can be met",
- "potentialBenefits": "Ensures that no cached DNS records exist past RTO targets",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/privateDnsZones",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "b89c9acc-0aba-fb44-9ff2-3dbfcf97dce7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/private-link/manage-private-endpoint?tabs=manage-private-link-powershell#private-endpoint-connections",
- "name": "Private endpoint connections"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "A private endpoint has two custom properties, static IP address and the network interface name, which must be set at creation. If not in Succeeded state, there may be issues with the endpoint or associated resource.\n",
- "pgVerified": true,
- "description": "Resolve issues with Private Endpoints in non Succeeded connection state",
- "potentialBenefits": "Ensure connection availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/privateEndpoints",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will return all Private Endpoints that are not in a Succeeded state\r\nresources\r\n| where type =~ \"microsoft.network/privateendpoints\"\r\n| where (properties.provisioningState =~ \"Succeeded\" and (properties.privateLinkServiceConnections[0].properties.provisioningState =~ \"Succeeded\" or properties.manualPrivateLinkServiceConnections[0].properties.provisioningState =~ \"Succeeded\")) == false\r\n| project recommendationId = \"b89c9acc-0aba-fb44-9ff2-3dbfcf97dce7\", name, id, tags, param1 = strcat(\"provisioningState: \", tostring(properties.provisioningState)), param2 = strcat(\"provisioningState: \", tostring(properties.privateLinkServiceConnections[0].properties.provisioningState)), param3 = strcat(\"manualProvisioningState: \", tostring(properties.manualPrivateLinkServiceConnections[0].properties.provisioningState))\r\n"
- },
- {
- "aprlGuid": "c63b81fb-7afc-894c-a840-91bb8a8dcfaf",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/ip-services/public-ip-addresses#availability-zone",
- "name": "Public IP addresses - Availability Zones"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Public IP addresses in Azure can be of standard SKU, available as non-zonal, zonal, or zone-redundant. Zone-redundant IPs are accessible across all zones, resisting any single zone failure, thereby providing higher resilience.\n",
- "pgVerified": true,
- "description": "Use Standard SKU and Zone-Redundant IPs when applicable",
- "potentialBenefits": "Enhanced resilience with zone redundancy",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/publicIPAddresses",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph query\r\n// List public IP addresses that are not Zone-Redundant\r\nResources\r\n| where type =~ \"Microsoft.Network/publicIPAddresses\" and sku.tier =~ \"Regional\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where isempty(zones) or array_length(zones) <= 1\r\n| extend az = case(isempty(zones), \"Non-zonal\", array_length(zones) <= 1, strcat(\"Zonal (\", strcat_array(zones, \",\"), \")\"), zones)\r\n| project recommendationId = \"c63b81fb-7afc-894c-a840-91bb8a8dcfaf\", name, id, tags, param1 = strcat(\"sku: \", sku.name), param2 = strcat(\"availabilityZone: \", az)\r\n\r\n"
- },
- {
- "aprlGuid": "1adba190-5c4c-e646-8527-dd1b2a6d8b15",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/advisor/advisor-reference-reliability-recommendations#use-nat-gateway-for-outbound-connectivity",
- "name": "Use NAT GW for outbound connectivity"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Prevent connectivity failures due to SNAT port exhaustion by employing NAT gateway for outbound traffic from virtual networks, ensuring dynamic scaling and secure internet connections.\n",
- "pgVerified": true,
- "description": "Use NAT gateway for outbound connectivity to avoid SNAT Exhaustion",
- "potentialBenefits": "Avoids SNAT port exhaustion risks",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/publicIPAddresses",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph query\r\n// Lists VMs with PIPs\r\nresources\r\n| where type =~ 'Microsoft.Network/publicIPAddresses'\r\n| where tostring(properties.ipConfiguration.id) contains \"microsoft.network/networkinterfaces\"\r\n| project recommendationId=\"1adba190-5c4c-e646-8527-dd1b2a6d8b15\", name, id, tags, param1=strcat(\"Migrate from instance IP to NAT Gateway\")\r\n\r\n"
- },
- {
- "aprlGuid": "5cea1501-6fe4-4ec4-ac8f-f72320eb18d3",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-network/ip-services/public-ip-basic-upgrade-guidance",
- "name": "Upgrading a basic public IP address to Standard SKU - Guidance"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Basic SKU public IP addresses will be retired on September 30, 2025. Users are advised to upgrade to Standard SKU public IP addresses before this date to avoid service disruptions.\n",
- "pgVerified": true,
- "description": "Upgrade Basic SKU public IP addresses to Standard SKU",
- "potentialBenefits": "Avoids service disruption",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/publicIPAddresses",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph query\r\n// List Basic SKU public IP addresses\r\nResources\r\n| where type =~ \"Microsoft.Network/publicIPAddresses\"\r\n| where sku.name =~ \"Basic\"\r\n| project recommendationId = \"5cea1501-6fe4-4ec4-ac8f-f72320eb18d3\", name, id, tags, param1 = strcat(\"sku: \", sku.name)\r\n\r\n"
- },
- {
- "aprlGuid": "c4254c66-b8a5-47aa-82f6-e7d7fb418f47",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/ddos-protection/ddos-protection-overview",
- "name": "Azure DDoS Protection"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "DDoS attacks can be targeted at any endpoint that is publicly reachable through the internet.\n",
- "pgVerified": true,
- "description": "Public IP addresses should have DDoS protection enabled",
- "potentialBenefits": "Avoids service disruption",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/publicIPAddresses",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph query\r\n// Public IP addresses should have DDoS protection enabled\r\nresources\r\n| where type =~ 'Microsoft.Network/publicIPAddresses'\r\n| where properties.ddosSettings.protectionMode !in~ (\"Enabled\", \"VirtualNetworkInherited\")\r\n| project recommendationId=\"c4254c66-b8a5-47aa-82f6-e7d7fb418f47\", name, id, tags, param1=strcat(\"Apply either DDoS Network protection or DDoS IP Protrection to the public IP address.\")\r\n"
- },
- {
- "aprlGuid": "23b2dfc7-7e5d-9443-9f62-980ca621b561",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-monitor/essentials/activity-log?tabs=powershell",
- "name": "Azure activity log - Azure Monitor | Microsoft Learn"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Create Alerts with Azure Monitor for operations like Create or Update Route Table to spot unauthorized/undesired changes in production resources. This setup aids in identifying improper routing changes, including efforts to evade firewalls or access resources from outside.\n",
- "pgVerified": true,
- "description": "Monitor changes in Route Tables with Azure Monitor",
- "potentialBenefits": "Enhanced security and change detection",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/routeTables",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Route Tables without alerts for modification configured.\r\nresources\r\n| where type =~ \"Microsoft.Network/routeTables\"\r\n| project name, id, tags, lowerCaseRouteTableId = tolower(id)\r\n| join kind = leftouter (\r\n resources\r\n | where type =~ \"Microsoft.Insights/activityLogAlerts\" and properties.enabled == true\r\n | mv-expand scope = properties.scopes\r\n | where scope has \"Microsoft.Network/routeTables\"\r\n | project alertName = name, conditionJson = dynamic_to_json(properties.condition.allOf), scope\r\n | where conditionJson has '\"Administrative\"' and (\r\n // Create or Update Route Table\r\n (conditionJson has '\"Microsoft.Network/routeTables/write\"') or\r\n // All Administrative operations\r\n (conditionJson !has '\"Microsoft.Network/routeTables/write\"' and conditionJson !has '\"Microsoft.Network/routeTables/delete\"' and conditionJson !has '\"Microsoft.Network/routeTables/join/action\"')\r\n )\r\n | project lowerCaseRouteTableIdOfScope = tolower(scope)\r\n )\r\n on $left.lowerCaseRouteTableId == $right.lowerCaseRouteTableIdOfScope\r\n| where isempty(lowerCaseRouteTableIdOfScope)\r\n| project recommendationId = \"23b2dfc7-7e5d-9443-9f62-980ca621b561\", name, id, tags, param1 = \"ModificationAlert: Not configured/Disabled\"\r\n\r\n"
- },
- {
- "aprlGuid": "89d1166a-1a20-0f46-acc8-3194387bf127",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/lock-resources?toc=%2Fazure%2Fvirtual-network%2Ftoc.json&tabs=json",
- "name": "Protect your Azure resources with a lock - Azure Resource Manager | Microsoft Learn"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "As an administrator, you can protect Azure subscriptions, resource groups, or resources from accidental deletions and modifications by setting locks.\n",
- "pgVerified": true,
- "description": "Configure locks for Route Tables to avoid accidental changes or deletion",
- "potentialBenefits": "Prevents accidental edits/deletions",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/routeTables",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "f05a3e6d-49db-2740-88e2-2b13706c1f67",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/traffic-manager/traffic-manager-monitoring",
- "name": "Azure Traffic Manager endpoint monitoring"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Monitor status should be online to ensure failover for application workload. If Traffic Manager's health shows Degraded, one or more endpoints may also be Degraded.\n",
- "pgVerified": true,
- "description": "Traffic Manager Monitor Status Should be Online",
- "potentialBenefits": "Ensures failover functionality",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/trafficManagerProfiles",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find traffic manager profiles that have an endpoint monitor status of not 'Online'\r\nresources\r\n| where type == \"microsoft.network/trafficmanagerprofiles\"\r\n| mv-expand properties.endpoints\r\n| where properties_endpoints.properties.endpointMonitorStatus != \"Online\"\r\n| project recommendationId = \"f05a3e6d-49db-2740-88e2-2b13706c1f67\", name, id, tags, param1 = strcat('Profile name: ',properties_endpoints.name), param2 = strcat('endpointMonitorStatus: ', properties_endpoints.properties.endpointMonitorStatus)\r\n\r\n"
- },
- {
- "aprlGuid": "5b422a7f-8caa-3d48-becb-511599e5bba9",
- "recommendationTypeId": "6cd70072-c45c-4716-bf7b-b35c18e46e72",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/traffic-manager/traffic-manager-endpoint-types",
- "name": "Traffic Manager Endpoint Types"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "When configuring the Azure traffic manager, provision at least two endpoints to ensure workloads can fail-over to another instance, enhancing reliability and availability.\n",
- "pgVerified": true,
- "description": "Traffic manager profiles should have more than one endpoint",
- "potentialBenefits": "Enhances failover capabilities",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/trafficManagerProfiles",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find traffic manager profiles that have less than 2 endpoints\r\nresources\r\n| where type == \"microsoft.network/trafficmanagerprofiles\"\r\n| where array_length(properties.endpoints) < 2\r\n| project recommendationId = \"5b422a7f-8caa-3d48-becb-511599e5bba9\", name, id, tags, param1 = strcat('EndpointCount: ', array_length(properties.endpoints))\r\n\r\n"
- },
- {
- "aprlGuid": "1ad9d7b7-9692-1441-a8f4-93792efbe97a",
- "recommendationTypeId": "0db76759-6d22-4262-93f0-2f989ba2b58e",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/advisor/advisor-reference-reliability-recommendations#add-at-least-one-more-endpoint-to-the-profile-preferably-in-another-azure-region",
- "name": "Reliability recommendations"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Profiles should have multiple endpoints to ensure availability in case an endpoint fails. It's also advised to distribute these endpoints across different regions for enhanced reliability.\n",
- "pgVerified": true,
- "description": "Configure at least one endpoint within a another region",
- "potentialBenefits": "Enhances availability across regions",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/trafficManagerProfiles",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find traffic manager profiles that do not have at least two endpoints in different regions\r\nresources\r\n| where type == \"microsoft.network/trafficmanagerprofiles\"\r\n| extend endpoints = properties.endpoints\r\n| mv-expand endpoint = endpoints\r\n| extend endpointLocation = endpoint.properties.endpointLocation\r\n| summarize\r\n regions = makeset(endpointLocation),\r\n tags = any(tags),\r\n name = any(name)\r\n by id\r\n| extend regionCount = array_length(regions)\r\n| where regionCount <= 1\r\n| project recommendationId = \"1ad9d7b7-9692-1441-a8f4-93792efbe97a\", name, id, tags, param1 = regions\r\n"
- },
- {
- "aprlGuid": "c31f76a0-48cd-9f44-aa43-99ee904db9bc",
- "recommendationTypeId": "0bbe0a49-3c63-49d3-ab4a-aa24198f03f7",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/advisor/advisor-reference-reliability-recommendations#add-an-endpoint-configured-to-all-world",
- "name": "Add an endpoint configured to \"All (World)\""
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "For geographic routing, traffic is directed to endpoints based on specific regions. If a region fails, without a predefined failover, configuring an endpoint to \"All (World)\" for geographic profiles can prevent traffic black holes, ensuring service remains available.\n",
- "pgVerified": true,
- "description": "Ensure endpoint configured to (All World) for geographic profiles",
- "potentialBenefits": "Avoids traffic black holing, ensures availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/trafficManagerProfiles",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Traffic Manager resources that are not confirgured for all-World access\r\nResources\r\n| where type == 'microsoft.network/trafficmanagerprofiles'\r\n| where properties.trafficRoutingMethod =~ \"Geographic\"\r\n| extend endpoints = properties.endpoints\r\n| mv-expand endpoint = endpoints\r\n| where endpoint.properties.geoMapping !contains \"WORLD\"\r\n| extend endpointName = endpoint.name\r\n| project recommendationId=\"c31f76a0-48cd-9f44-aa43-99ee904db9bc\", name, id, tags, param1=strcat(\"endpointName:\",endpointName), param2=strcat(\"GeoMapping:\", tostring(endpoint.properties.geoMapping))\r\n"
- },
- {
- "aprlGuid": "9437634c-d69e-2747-b13e-631c13182150",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/guide/technology-choices/load-balancing-overview",
- "name": "Azure Load Balancing Options"
- }
- ],
- "recommendationControl": "BusinessContinuity",
- "longDescription": "For most solutions, choose either Azure Front Door for content caching, CDN, TLS termination, and WAF, or Traffic Manager for simple global load balancing.\n",
- "pgVerified": true,
- "description": "Avoid combining Traffic Manager and Front Door",
- "potentialBenefits": "Optimized network routing and security",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/trafficManagerProfiles",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Avoid combining Traffic Manager and Front Door\r\nresources\r\n| where type == \"microsoft.network/trafficmanagerprofiles\"\r\n| mvexpand(properties.endpoints)\r\n| extend endpoint=tostring(properties_endpoints.properties.target)\r\n| project name, trafficmanager=id, matchname=endpoint, tags\r\n| join (\r\n resources\r\n | where type =~ \"microsoft.cdn/profiles/afdendpoints\"\r\n | extend matchname= tostring(properties.hostName)\r\n | extend splitid=split(id, \"/\")\r\n | extend frontdoorid=tolower(strcat_array(array_slice(splitid, 0, 8), \"/\"))\r\n | project name, id, matchname, frontdoorid, type\r\n | union\r\n (cdnresources\r\n | where type =~ \"Microsoft.Cdn/Profiles/CustomDomains\"\r\n | extend matchname= tostring(properties.hostName)\r\n | extend splitid=split(id, \"/\")\r\n | extend frontdoorid=tolower(strcat_array(array_slice(splitid, 0, 8), \"/\"))\r\n | project name, id, matchname, frontdoorid, type)\r\n )\r\n on matchname\r\n| project\r\n recommendationId = \"9437634c-d69e-2747-b13e-631c13182150\",\r\n name=split(trafficmanager, \"/\")[-1],\r\n id=trafficmanager,\r\n tags,\r\n param1=strcat(\"hostname:\", matchname),\r\n param2=strcat(\"frontdoorid:\", frontdoorid)\r\n\r\n"
- },
- {
- "aprlGuid": "30ec8a5e-46de-4323-87e9-a7c56b72813b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-wan/monitoring-best-practices#virtual-hub",
- "name": "Virtual WAN Monitoring Best Practices"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Set up monitoring and alerts for v-Hubs. Create alert rule for ensuring promptly response to changes in BGP status and Data processed by v-Hubs.\n",
- "pgVerified": false,
- "description": "Monitor health for v-Hubs",
- "potentialBenefits": "Detection and mitigation to avoid disruptions.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualHubs",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "d37db635-157f-584d-9bce-4f6fc8c65ce5",
- "recommendationTypeId": "8d61a7d4-5405-4f43-81e3-8c6239b844a6",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering",
- "name": "Designing for disaster recovery with ExpressRoute private peering"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For improved reliability, each ExpressRoute gateway should connect to at least two circuits, with each circuit sourced from a different peering location. This setup ensures diverse connectivity paths, enhancing resilience and minimizing service disruption risks.\n",
- "pgVerified": true,
- "description": "Connect ExpressRoute gateway with circuits from diverse peering locations",
- "potentialBenefits": "Enhanced resilience through diverse connectivity paths",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of ExpressRoute Gateways that are not connected to two or more ExpressRoute Circuits. Baremetal circuits are excluded from consideration\r\n//This query assumes that the running entity has visibilty to the gateway, connection, and circuit scopes.\r\n//Start with a full list of gateways\r\n(resources\r\n| where type == \"microsoft.network/virtualnetworkgateways\"\r\n| where properties.gatewayType == \"ExpressRoute\"\r\n| extend exrGatewayId = tolower(tostring(id))\r\n| join kind=inner(\r\nresources\r\n| where type == \"microsoft.network/virtualnetworkgateways\"\r\n| where properties.gatewayType == \"ExpressRoute\"\r\n| extend exrGatewayId = tolower(tostring(id))\r\n| join kind=leftouter(\r\n//connections joined with circuit peer info\r\nresources\r\n| where type == \"microsoft.network/connections\"\r\n| extend connectionType = properties.connectionType\r\n| extend exrGatewayId = tolower(tostring(properties.virtualNetworkGateway1.id))\r\n| extend peerId = tolower(tostring(properties.peer.id))\r\n| extend connectionId = tolower(tostring(id))\r\n| where connectionType == \"ExpressRoute\"\r\n| join kind=leftouter(\r\n resources\r\n | where type == \"microsoft.network/expressroutecircuits\"\r\n //should this be location instead of peeringLocation\r\n | extend circuitId = tolower(tostring(id))\r\n | extend peeringLocation = tostring(properties.serviceProviderProperties.peeringLocation)\r\n | extend peerId = tolower(id)\r\n) on peerId ) on exrGatewayId\r\n//remove bare metal services connections/circuits\r\n| where not(isnotnull(connectionId) and isnull(sku1))\r\n//group by gateway ID's and peering locations\r\n| summarize by exrGatewayId, peeringLocation\r\n//summarize to connections with fewer than two unique connections\r\n| summarize connCount = count() by exrGatewayId\r\n| where connCount < 2) on exrGatewayId\r\n| project recommendationId = \"d37db635-157f-584d-9bce-4f6fc8c65ce5\", name, id, tags, param1 = \"twoOrMoreCircuitsConnectedFromDifferentPeeringLocations: false\")\r\n| union\r\n(\r\nresources\r\n| where type == \"microsoft.network/virtualnetworkgateways\"\r\n| where properties.gatewayType == \"ExpressRoute\"\r\n| extend exrGatewayId = tolower(tostring(id))\r\n| join kind=leftouter(\r\n//connections joined with circuit peer info\r\nresources\r\n| where type == \"microsoft.network/connections\"\r\n| extend connectionType = properties.connectionType\r\n| extend exrGatewayId = tolower(tostring(properties.virtualNetworkGateway1.id))\r\n| extend peerId = tolower(tostring(properties.peer.id))\r\n| extend connectionId = tolower(tostring(id))\r\n| where connectionType == \"ExpressRoute\") on exrGatewayId\r\n| where isnull(connectionType)\r\n| project recommendationId = \"d37db635-157f-584d-9bce-4f6fc8c65ce5\", name, id, tags, param1 = \"twoOrMoreCircuitsConnectedFromDifferentPeeringLocations: false\", param2 = \"noConnectionsOnGateway: true\"\r\n)\r\n\r\n"
- },
- {
- "aprlGuid": "bbe668b7-eb5c-c746-8b82-70afdedf0cae",
- "recommendationTypeId": "c9af1ef6-55bc-48af-bfe4-2c80490159f8",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways#zrgw",
- "name": "About ExpressRoute virtual network gateways - Zone-redundant gateway SKUs"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure ExpressRoute gateway offers variable SLAs based on deployment in single or multiple availability zones. To deploy virtual network gateways across zones automatically, use zone-redundant gateways for accessing critical, scalable services with increased resilience.\n",
- "pgVerified": true,
- "description": "Use Zone-redundant ExpressRoute gateway SKUs",
- "potentialBenefits": "Enhanced SLA and resilience",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// For all VNGs of type ExpressRoute, show all that are not zone redundant (Zonal or Regional)\r\nadvisorresources\r\n| where properties.recommendationTypeId =~ 'c9af1ef6-55bc-48af-bfe4-2c80490159f8' // RecommendationID from Advisor\r\n| mv-expand resId = properties.resourceMetadata.resourceId\r\n| extend resId = tostring(resId)\r\n| project recId = properties.recommendationTypeId, resId\r\n| join kind=leftouter (\r\n resources\r\n | extend id = tostring(id)\r\n | project id, name, tags, location, properties\r\n) on $left.resId == $right.id\r\n| project recommendationId = \"bbe668b7-eb5c-c746-8b82-70afdedf0cae\", name , id = resId, tags, param1 = strcat(\"sku-tier: \", properties.sku.tier), param2 = location,param3 = \"Non Zone-Redundant GW\"\r\n"
- },
- {
- "aprlGuid": "c0f23a92-d322-4d4d-97e9-a238b5e3bbb8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/lock-resources?tabs=json",
- "name": "Protect your Azure resources with a lock - Azure Resource Manager | Microsoft Learn"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Configuring an Azure Resource lock for ExpressRoute gateway prevents accidental deletion by enabling administrators to lock an Azure subscription, resource group, or resource, thereby protecting them from unintended user deletions and modifications, with the lock overriding all user permissions.\n",
- "pgVerified": true,
- "description": "Configure an Azure Resource lock for ExpressRoute gateway to prevent accidental deletion",
- "potentialBenefits": "Prevents accidental deletions",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1c34faa8-8b99-974c-adbf-71922eae943c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/expressroute-monitoring-metrics-alerts#expressroute-gateways",
- "name": "ExpressRoute monitoring, metrics, and alerts | ExpressRoute gateways"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Use Network Insights for monitoring ExpressRoute Gateway's health, including availability, performance, and scalability.\n",
- "pgVerified": true,
- "description": "Monitor health for ExpressRoute gateway",
- "potentialBenefits": "Enhanced monitoring and alerting",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "194c14ac-0d7a-5a48-ae32-75fa450ee564",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/expressroute-about-virtual-network-gateways#vnet-to-vnet-connectivity",
- "name": "About ExpressRoute virtual network gateways - VNet-to-VNet connectivity"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "While multiple VNets can connect via the same ExpressRoute gateway, Microsoft recommends using alternatives like VNet peering, Azure Firewall, NVA, Azure Route Server, site-to-site VPN, virtual WAN, or SD-WAN for VNet-to-VNet communication to optimize network performance and management.\n",
- "pgVerified": true,
- "description": "Avoid using ExpressRoute circuits for VNet to VNet communication",
- "potentialBenefits": "Enhanced VNet integration efficiency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "3e115044-a3aa-433e-be01-ce17d67e50da",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/expressroute/customer-controlled-gateway-maintenance#azure-portal-steps",
- "name": "Configure customer-controlled maintenance for your virtual network gateway - ExpressRoute | Microsoft Learn"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "ExpressRoute gateways are updated for improved functionality, reliability, performance, and security. Customer-controlled maintenance configuration and scheduling minimize update impact and align with your maintenance windows.\n",
- "pgVerified": true,
- "description": "Configure customer-controlled ExpressRoute gateway maintenance",
- "potentialBenefits": "Minimizes update impact",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Virtual Network Gateways without Maintenance Configurations\r\n\r\nresources\r\n| where type =~ \"Microsoft.Network/virtualNetworkGateways\"\r\n| extend resourceId = tolower(id)\r\n| join kind=leftouter (\r\n maintenanceresources\r\n | where type =~ \"Microsoft.Maintenance/configurationAssignments\"\r\n | project JsonData = parse_json(properties)\r\n | extend maintenanceConfigurationId = tolower(tostring(JsonData.maintenanceConfigurationId))\r\n | join kind=inner (\r\n resources\r\n | where type =~ \"Microsoft.Maintenance/maintenanceConfigurations\"\r\n | project maintenanceConfigurationId=tolower(id)\r\n ) on maintenanceConfigurationId\r\n | project maintenanceConfigurationId, resourceId=tolower(tostring(JsonData.resourceId))\r\n) on resourceId\r\n| where isempty(maintenanceConfigurationId)\r\n| project recommendationId = \"3e115044-a3aa-433e-be01-ce17d67e50da\", name, id, tags, param1= strcat(\"sku-tier: \" , properties.sku.tier), param2=location\r\n\r\n"
- },
- {
- "aprlGuid": "5b1933a6-90e4-f642-a01f-e58594e5aab2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/vpn-gateway/about-zone-redundant-vnet-gateways",
- "name": "Zone redundant Virtual network gateway in availability zone"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Deploying zone-redundant virtual network gateways across availability zones ensures zone-resiliency, improving access to mission-critical, scalable services on Azure. Mission Critical workloads should use dual ExpressRoutes instead of VPN.\n",
- "pgVerified": true,
- "description": "Choose a Zone-redundant VPN gateway",
- "potentialBenefits": "Enhanced reliability and scalability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// For all VNGs of type Vpn, show any that do not have AZ in the SKU tier\r\nresources\r\n| where type =~ \"Microsoft.Network/virtualNetworkGateways\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where properties.gatewayType == \"Vpn\"\r\n| where properties.sku.tier !contains 'AZ'\r\n| project recommendationId = \"5b1933a6-90e4-f642-a01f-e58594e5aab2\", name, id, tags, param1= strcat(\"sku-tier: \" , properties.sku.tier), param2=location\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "281a2713-c0e0-3c48-b596-19f590c46671",
- "recommendationTypeId": "c249dc0e-9a17-423e-838a-d72719e8c5dd",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/vpn-gateway/active-active-portal#gateway",
- "name": "Active-active VPN gateway"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "The active-active mode is available for all SKUs except Basic, allowing for two Gateway IP configurations and two public IP addresses, enhancing redundancy and traffic handling. Mission Critical workloads should use dual ExpressRoutes instead of VPN.\n",
- "pgVerified": true,
- "description": "Enable Active-Active VPN Gateways for redundancy",
- "potentialBenefits": "Enhanced reliability and network capacity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Identifies non-active-active VPN type virtual network gateways\r\nresources\r\n| where type =~ 'Microsoft.Network/virtualNetworkGateways'\r\n| where properties.gatewayType =~ \"vpn\"\r\n| extend gatewayType = properties.gatewayType, vpnType = properties.vpnType, connections = properties.connections, activeactive=properties.activeActive\r\n| where activeactive == false\r\n| project recommendationId = \"281a2713-c0e0-3c48-b596-19f590c46671\", name, id, tags\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "af11fc4c-c06c-4f4c-b98d-6eee6d5c4c70",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/vpn-gateway/vpn-gateway-highlyavailable#dual-redundancy-active-active-vpn-gateways-for-both-azure-and-on-premises-networks",
- "name": "Dual-redundancy active-active VPN gateways for both Azure and on-premises networks"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Deploying active-active VPN concentrators and Azure VPN Gateways maximizes resilience and availability using a fully-meshed topology with four IPSec tunnels. Mission Critical workloads should use dual ExpressRoutes instead of VPN.\n",
- "pgVerified": true,
- "description": "Deploy active-active VPN concentrators on your premises",
- "potentialBenefits": "Maximizes resilience and availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "9eab120e-f6d3-ee49-ba0d-766562ce7df1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/vpn-gateway/monitor-vpn-gateway-reference",
- "name": "VPN gateway data reference"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Set up monitoring and alerts for Virtual Network Gateway health to utilize a variety of metrics for ensuring operational efficiency and prompt response to any disruptions. Mission Critical workloads should use dual ExpressRoutes instead of VPN.\n",
- "pgVerified": true,
- "description": "Monitor VPN gateway connections and health",
- "potentialBenefits": "Improved uptime and issue awareness",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "9186dae0-7ddc-8f4b-bea5-55538cea4893",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/vpn-gateway/monitor-vpn-gateway-reference#metrics",
- "name": "Monitor VPN gateway"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "VPN gateway leverages service health to inform users about both planned and unplanned maintenance, ensuring they are notified about modifications to their VPN connectivity. Mission Critical workloads should use dual ExpressRoutes instead of VPN.\n",
- "pgVerified": true,
- "description": "Enable VPN gateway service health",
- "potentialBenefits": "Improves VPN maintenance alerts",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "4bae5a28-5cf4-40d9-bcf1-623d28f6d917",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/vpn-gateway/about-zone-redundant-vnet-gateways",
- "name": "About zone-redundant virtual network gateway in Azure availability zones"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For zone-redundant VPN gateways, always use zone-redundant Standard SKU public IPs to avoid deploying all instances in one zone. This ensures the gateway's reliability. Mission Critical workloads should use dual ExpressRoutes instead of VPN.\n",
- "pgVerified": true,
- "description": "Deploy VPN gateways with zone-redundant Public IPs",
- "potentialBenefits": "Enhanced reliability and disaster recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworkGateways",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of zone-redundant Azure VPN gateways associated with non-zone-redundant Public IPs\r\nresources\r\n| where type =~ \"Microsoft.Network/virtualNetworkGateways\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where properties.gatewayType == \"Vpn\"\r\n| where properties.sku.tier contains 'AZ'\r\n| mv-expand ipconfig = properties.ipConfigurations\r\n| extend pipId = tostring(ipconfig.properties.publicIPAddress.id)\r\n| join kind=inner (\r\n resources\r\n | where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n | where type == \"microsoft.network/publicipaddresses\"\r\n | where isnull(zones) or array_length(zones) < 3 )\r\n on $left.pipId == $right.id\r\n| project recommendationId = \"4bae5a28-5cf4-40d9-bcf1-623d28f6d917\", name, id, tags, param1 = strcat(\"PublicIpAddressName: \", name1), param2 = strcat (\"PublicIpAddressId: \",id1), param3 = strcat (\"PublicIpAddressTags: \",tags1)\r\n\r\n"
- },
- {
- "aprlGuid": "f0bf9ae6-25a5-974d-87d5-025abec73539",
- "recommendationTypeId": "eade5b56-eefd-444f-95c8-23f29e5d93cb",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/concepts-and-best-practices",
- "name": "Azure Virtual Network - Concepts and best practices | Microsoft Learn"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Network security groups and application security groups allow filtering of inbound and outbound traffic by IP, port, and protocol, adding a security layer at the Subnet level.\n",
- "pgVerified": true,
- "description": "All Subnets should have a Network Security Group associated",
- "potentialBenefits": "Enhanced subnet security and traffic control",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworks",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Subnets without NSG associated\r\nresources\r\n| where type =~ 'Microsoft.Network/virtualnetworks'\r\n| mv-expand subnets = properties.subnets\r\n| extend sn = string_size(subnets.properties.networkSecurityGroup)\r\n| where sn == 0 and subnets.name !in (\"GatewaySubnet\", \"AzureFirewallSubnet\", \"AzureFirewallManagementSubnet\", \"RouteServerSubnet\")\r\n| project recommendationId = \"f0bf9ae6-25a5-974d-87d5-025abec73539\", name, id, tags, param1 = strcat(\"SubnetName: \", subnets.name), param2 = \"NSG: False\"\r\n\r\n"
- },
- {
- "aprlGuid": "69ea1185-19b7-de40-9da1-9e8493547a5c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/framework/services/networking/azure-virtual-network/reliability",
- "name": "Reliability and Azure Virtual Network - Microsoft Azure Well-Architected Framework | Microsoft Learn"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Azure DDoS Protection offers enhanced mitigation features against DDoS attacks and is auto-tuned to protect specific resources in a virtual network, combined with application design best practices.\n",
- "pgVerified": true,
- "description": "Shield public endpoints in Azure VNets with Azure DDoS Standard Protection Plans",
- "potentialBenefits": "Enhanced DDoS attack mitigation",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworks",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find virtual networks without DDoS Protection\r\nresources\r\n| where type =~ 'Microsoft.Network/virtualNetworks'\r\n| where isnull(properties.enableDdosProtection) or properties.enableDdosProtection contains \"false\"\r\n| project recommendationId = \"69ea1185-19b7-de40-9da1-9e8493547a5c\", name, id, tags, param1 = strcat(\"EnableDdosProtection: \", properties.enableDdosProtection)\r\n\r\n"
- },
- {
- "aprlGuid": "24ae3773-cc2c-3649-88de-c9788e25b463",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/virtual-networks-faq",
- "name": "Azure Virtual Network FAQ | Microsoft Learn"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Use VNet service endpoints only if Private Link isn't available and no data movement concerns. This feature restricts Azure service access to specified VNet and subnet, enhancing network security and isolating service traffic.\n",
- "pgVerified": true,
- "description": "When available, use Private Endpoints instead of Service Endpoints for PaaS Services",
- "potentialBenefits": "Enhanced security and data isolation",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworks",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find Subnets with Service Endpoint enabled for services that offer Private Link\r\nresources\r\n| where type =~ 'Microsoft.Network/virtualnetworks'\r\n| mv-expand subnets = properties.subnets\r\n| extend se = array_length(subnets.properties.serviceEndpoints)\r\n| where se >= 1\r\n| project name, id, tags, subnets, serviceEndpoints=todynamic(subnets.properties.serviceEndpoints)\r\n| mv-expand serviceEndpoints\r\n| project name, id, tags, subnetName=subnets.name, serviceName=tostring(serviceEndpoints.service)\r\n| where serviceName in (parse_json('[\"Microsoft.CognitiveServices\",\"Microsoft.AzureCosmosDB\",\"Microsoft.DBforMariaDB\",\"Microsoft.DBforMySQL\",\"Microsoft.DBforPostgreSQL\",\"Microsoft.EventHub\",\"Microsoft.KeyVault\",\"Microsoft.ServiceBus\",\"Microsoft.Sql\", \"Microsoft.Storage\",\"Microsoft.StorageSync\",\"Microsoft.Synapse\",\"Microsoft.Web\"]'))\r\n| project recommendationId = \"24ae3773-cc2c-3649-88de-c9788e25b463\", name, id, tags, param1 = strcat(\"subnet=\", subnetName), param2=strcat(\"serviceName=\",serviceName), param3=\"ServiceEndpoints=true\"\r\n\r\n"
- },
- {
- "aprlGuid": "06b77be9-56a3-4d41-b362-8b295c5a283d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/network-watcher/vnet-flow-logs-overview",
- "name": "Virtual network flow logs"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Improves monitoring and security for Azure and Hybrid connectivity\n",
- "pgVerified": true,
- "description": "Enable Virtual Network Flow Logs",
- "potentialBenefits": "Improves monitoring and security for Azure connectivity",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualNetworks",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will return all Vnets missing Flow Logs configuration\r\nresources\r\n| where type =~ \"Microsoft.Network/virtualNetworks\"\r\n| extend vnetId = tolower(tostring(id)),vnetName = name,vnetTags = tags,vnetLocation = location\r\n| join kind = leftouter (\r\n resources\r\n | where type =~ \"microsoft.network/networkwatchers/flowlogs\"\r\n | extend flowLogType = iff(\r\n properties.targetResourceId contains \"Microsoft.Network/virtualNetworks\",\r\n 'Virtual network',\r\n 'Virtual network'\r\n )\r\n | extend flowLogTargetVnet = tolower(properties.targetResourceId)\r\n) on $left.vnetId == $right.flowLogTargetVnet\r\n| where strlen(flowLogTargetVnet) == 0\r\n| project recommendationId = \"06b77be9-56a3-4d41-b362-8b295c5a283d\",name=vnetName,id=vnetId,tags,param1 = \"Missing Vnet Flow Log configuration\"\r\n"
- },
- {
- "aprlGuid": "2226d069-de5b-4ec1-ad26-3249f4ab1741",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/route-server/route-server-faq#do-i-need-to-peer-each-nva-with-both-azure-route-server-instances",
- "name": "Azure Route Server frequently asked questions (FAQ)"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "To ensure that routes are successfully advertised to Route Server and to configure high availability, peer two NVA instances with both instances of Route Server. Advertise the same routes to both Route Server instances.\n",
- "pgVerified": false,
- "description": "Peer two NVA instances with both Azure Route Server instances",
- "potentialBenefits": "Connectivity will remain active during maintenance events",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualRouters",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "b8ff662a-ab74-4b6a-8301-d4dae002bc14",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/route-server/monitor-route-server",
- "name": "Monitor Azure Route Server"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Monitor Azure Route Server for BGP Peer Status, Count of Routes Advertised to Peer, and Count of Routes Learned from Peer. Create alerts for these metrics to ensure that you are notified of any issues.\n",
- "pgVerified": false,
- "description": "Monitor and create alerting for Azure Route Server",
- "potentialBenefits": "Be alerted to connectivity issues with Azure Route Server",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/virtualRouters",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "f0d4f766-ac19-48c4-b228-4601cc038baa",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-wan/monitoring-best-practices#virtual-wan-gateways",
- "name": "Virtual WAN Monitoring Best Practices"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Set up monitoring and alerts for v-Hub's VPN Gateway. Create alert rule for ensuring promptly response to critical events such as packet drop counts, BGP status, Gateway over utilization. Mission Critical workloads should use dual ExpressRoutes instead of VPN.\n",
- "pgVerified": false,
- "description": "Monitor gateway for Site-to-site v-Hub's VPN gateway",
- "potentialBenefits": "Detection and mitigation to avoid disruptions.",
- "tags": null,
- "recommendationResourceType": "Microsoft.Network/vpnGateways",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "1ceea4b5-1d8b-4be0-9bbe-9594557be51a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/expressroute/traffic-collector",
- "name": "Azure ExpressRoute Traffic Collector"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "ExpressRoute Traffic Collector samples network flows over ExpressRoute Direct or Service-Provider based circuits, sending flow logs to a Log Analytics workspace for analysis or export to visualization tools/SIEM.\n",
- "pgVerified": true,
- "description": "Ensure ExpressRoute Traffic Collector is enabled and configured for Direct or Provider circuits",
- "potentialBenefits": "Enhanced network flow analysis and DR readiness",
- "tags": null,
- "recommendationResourceType": "Microsoft.NetworkFunction/azureTrafficCollectors",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "b36fd2ac-dd83-664a-ab48-ff7b8d3b189d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-monitor/logs/logs-data-export",
- "name": "Log Analytics workspace data export in Azure Monitor"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Data export in a Log Analytics workspace to an Azure Storage account enhances data protection against regional failures by using geo-redundant (GRS) or geo-zone-redundant storage (GZRS), mainly for compliance and integration with other Azure services and tools.\n",
- "pgVerified": true,
- "description": "Enable Log Analytics data export to GRS or GZRS",
- "potentialBenefits": "Enhances compliance and regional fault tolerance",
- "tags": null,
- "recommendationResourceType": "Microsoft.OperationalInsights/workspaces",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "4b77191c-cc3c-8c4e-844b-0f56d0927890",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-monitor/logs/log-analytics-workspace-health",
- "name": "Monitor Log Analytics workspace health"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "A health status alert will proactively notify you if a workspace becomes unavailable because of a datacenter or regional failure.\n",
- "pgVerified": true,
- "description": "Create a health status alert rule for your Log Analytics workspace",
- "potentialBenefits": "Early alert for workspace failure",
- "tags": null,
- "recommendationResourceType": "Microsoft.OperationalInsights/workspaces",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "e93bb813-b356-48f3-9bdf-a06a0a6ba039",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/site-recovery/azure-to-azure-network-mapping#set-up-ip-addressing-for-target-vms",
- "name": "Setup network mapping for site recovery"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Ensure VM failover settings' static IP addresses are available in the failover subnet to maintain consistent IP assignment during failover, with the target VM receiving the same static IP if it's available or the next available IP otherwise. IP adjustments can be made in VM Network settings.\n",
- "pgVerified": true,
- "description": "Ensure static IP addresses in Site Recovery VM failover settings are available in failover subnet",
- "potentialBenefits": "Smooth failover IP management",
- "tags": null,
- "recommendationResourceType": "Microsoft.RecoveryServices/vaults",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "17e877f7-3a89-4205-8a24-0670de54ddcd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/site-recovery/azure-to-azure-tutorial-dr-drill#run-a-test-failover",
- "name": "Run a test failover"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Perform a test failover to validate your BCDR strategy and ensure that your applications are functioning correctly in the target region without impacting your production environment. Test your Disaster Recovery plan periodically without any data loss or downtime, using test failovers.\n",
- "pgVerified": true,
- "description": "Validate VM functionality with a Site Recovery test failover to check performance at target",
- "potentialBenefits": "Ensures BCDR plan accuracy and VM performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.RecoveryServices/vaults",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all VMs where replication has been enabled but Test Failover was never performed\r\nrecoveryservicesresources\r\n| where type == \"microsoft.recoveryservices/vaults/replicationfabrics/replicationprotectioncontainers/replicationprotecteditems\"\r\n| where properties.providerSpecificDetails.dataSourceInfo.datasourceType == 'AzureVm' and isnull(properties.lastSuccessfulTestFailoverTime)\r\n| project recommendationId=\"17e877f7-3a89-4205-8a24-0670de54ddcd\" , name = properties.providerSpecificDetails.recoveryAzureVMName, id=properties.providerSpecificDetails.dataSourceInfo.resourceId\r\n\r\n"
- },
- {
- "aprlGuid": "2912472d-0198-4bdc-aa90-37f145790edc",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/backup/move-to-azure-monitor-alerts",
- "name": "Move to Azure monitor Alerts"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Classic alerts for Recovery Services vaults in Azure Backup will be retired on 31 March 2026.\n",
- "pgVerified": true,
- "description": "Migrate from classic alerts to built-in Azure Monitor alerts for Azure Recovery Services Vaults",
- "potentialBenefits": "Enhanced, scalable, and consistent alerting.",
- "tags": null,
- "recommendationResourceType": "Microsoft.RecoveryServices/vaults",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// Azure Resource Graph Query\r\n// This Resource Graph query will return all Recovery services vault with Classic alerts enabled.\r\nresources\r\n| where type in~ ('microsoft.recoveryservices/vaults')\r\n| extend monitoringSettings = parse_json(properties).monitoringSettings\r\n| extend isUsingClassicAlerts = case(isnull(monitoringSettings),'Enabled',monitoringSettings.classicAlertSettings.alertsForCriticalOperations)\r\n| extend isUsingJobsAlerts = case(isnull(monitoringSettings), 'Enabled', monitoringSettings.azureMonitorAlertSettings.alertsForAllJobFailures)\r\n| where isUsingClassicAlerts == 'Enabled'\r\n| project recommendationId = \"2912472d-0198-4bdc-aa90-37f145790edc\", name, id, tags, param1=strcat(\"isUsingClassicAlerts: \", isUsingClassicAlerts), param2=strcat(\"isUsingJobsAlerts: \", isUsingJobsAlerts)\r\n"
- },
- {
- "aprlGuid": "1549b91f-2ea0-4d4f-ba2a-4596becbe3de",
- "recommendationTypeId": "9b1308f1-4c25-4347-a061-7cc5cd6a44ab",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/backup/backup-create-recovery-services-vault#set-cross-region-restore",
- "name": "Set Cross Region Restore"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Cross Region Restore enables the restoration of Azure VMs in a secondary, Azure paired region, facilitating drills for audit or compliance and allowing recovery of VMs or disks in the event of a primary region disaster. It is an opt-in feature available exclusively for GRS vaults.\n",
- "pgVerified": true,
- "description": "Enable Cross Region Restore for your GRS Recovery Services Vault",
- "potentialBenefits": "Enhances disaster recovery capabilities",
- "tags": null,
- "recommendationResourceType": "Microsoft.RecoveryServices/vaults",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Displays all recovery services vaults that do not have cross region restore enabled\r\nresources\r\n| where type =~ \"Microsoft.RecoveryServices/vaults\" and\r\n properties.redundancySettings.standardTierStorageRedundancy =~ \"GeoRedundant\" and\r\n properties.redundancySettings.crossRegionRestore !~ \"Enabled\"\r\n| extend\r\n param1 = strcat(\"CrossRegionRestore: \", properties.redundancySettings.crossRegionRestore),\r\n param2 = strcat(\"StorageReplicationType: \", properties.redundancySettings.standardTierStorageRedundancy)\r\n| project recommendationId = \"1549b91f-2ea0-4d4f-ba2a-4596becbe3de\", name, id, tags, param1, param2\r\n"
- },
- {
- "aprlGuid": "9e39919b-78af-4a0b-b70f-c548dae97c25",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/backup/backup-azure-security-feature-cloud?tabs=azure-portal",
- "name": "Soft Delete for Azure Backup"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "With soft delete, if backup data is deleted, the backup data is retained for 14 additional days, allowing the recovery of that backup item with no data loss with no cost to you. Soft delete is enabled by default. Disabling this feature isn't recommended.\n",
- "pgVerified": false,
- "description": "Enable Soft Delete for Recovery Services Vaults in Azure Backup",
- "potentialBenefits": "Enhances disaster recovery capabilities",
- "tags": null,
- "recommendationResourceType": "Microsoft.RecoveryServices/vaults",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Azure Recovery Services vaults that do not have soft delete enabled\r\nresources\r\n| where type == \"microsoft.recoveryservices/vaults\"\r\n| mv-expand issoftDelete=properties.securitySettings.softDeleteSettings.softDeleteState\r\n| where issoftDelete == 'Disabled'\r\n| project recommendationId = \"9e39919b-78af-4a0b-b70f-c548dae97c25\", name, id, tags, param1=strcat(\"Soft Delete: \",issoftDelete)\r\n"
- },
- {
- "aprlGuid": "20057905-262c-49fe-a9be-49f423afb359",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/services/messaging/service-bus/reliability",
- "name": "Service Bus and reliability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Availability zones are now enabled by default on new namespaces where possible. Existing namespaces are being migrated to availability zones where possible. The property zoneRedundant might still show as false, even when availability zones has been enabled.\n",
- "pgVerified": false,
- "description": "Enable Availability Zones for Service Bus namespaces",
- "potentialBenefits": "Enhances fault tolerance and uptime",
- "tags": null,
- "recommendationResourceType": "Microsoft.ServiceBus/namespaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "d810e3a8-600f-4be1-895b-1a93e61d37fd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/service-bus-messaging/automate-update-messaging-units",
- "name": "Service Bus auto-scaling"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use Service Bus with auto-scale for high availability. The Premium SKU supports auto-scale, ensuring that the resources are automatically scaled based on the load.\n",
- "pgVerified": false,
- "description": "Enable auto-scale for production workloads on Service Bus namespaces",
- "potentialBenefits": "Ensures high availability and performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.ServiceBus/namespaces",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "f075a1bd-de9e-4819-9a1d-1ac41037a74f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/service-bus-messaging/transport-layer-security-configure-minimum-version",
- "name": "Configure the minimum TLS version for a Service Bus namespace"
- }
- ],
- "recommendationControl": "ServiceUpgradeAndRetirement",
- "longDescription": "As of 31 October 2024, TLS 1.0 and TLS 1.1 will no longer be supported on Azure including Service Bus to enhance security and provide best-in-class encryption for your data. Change the minimum TLS version for your Service Bus namespace to TLS v1.2 or higher.\n",
- "pgVerified": false,
- "description": "Configure the minimum TLS version for Service Bus namespaces to TLS v1.2 or higher",
- "potentialBenefits": "Avoids service disruption",
- "tags": null,
- "recommendationResourceType": "Microsoft.ServiceBus/namespaces",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Service Bus Namespace resources that have the lower minimum TLS version.\r\nresources\r\n| where type =~ \"Microsoft.ServiceBus/namespaces\"\r\n| where properties.minimumTlsVersion in (\"1.0\", \"1.1\")\r\n| project\r\n recommendationId = \"f075a1bd-de9e-4819-9a1d-1ac41037a74f\",\r\n name,\r\n id,\r\n tags,\r\n param1 = strcat(\"minimumTlsVersion: \", properties.minimumTlsVersion)\r\n"
- },
- {
- "aprlGuid": "6a8b3db9-5773-413a-a127-4f7032f34bbd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-signalr/availability-zones",
- "name": "Availability zones support in Azure SignalR Service"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use SignalR with zone redundancy for production to improve uptime. This feature, available in the Premium tier, is activated upon creating or upgrading to Premium. Standard can upgrade to Premium without downtime.\n",
- "pgVerified": false,
- "description": "Enable zone redundancy for SignalR",
- "potentialBenefits": "Enhances reliability and uptime",
- "tags": null,
- "recommendationResourceType": "Microsoft.SignalRService/SignalR",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find SignalR instances that are not configured with the Premium tier\r\nresources\r\n| where type == \"microsoft.signalrservice/signalr\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where sku.tier != \"Premium\"\r\n| project recommendationId = \"6a8b3db9-5773-413a-a127-4f7032f34bbd\", name, id, tags, param1 = \"AvailabilityZones: Single Zone\"\r\n| order by id asc\r\n\r\n"
- },
- {
- "aprlGuid": "f8f834a9-c761-4e84-b2cb-ac55494d0c37",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-sql/managed-instance/high-availability-sla-local-zone-redundancy?view=azuresql-mi#zone-redundant-availability",
- "name": "High availability through zone-redundancy"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure SQL Managed Instance offers built-in availability by deploying multiple replicas in the same zone. For higher availability, use a zone-redundant configuration that spreads replicas across three Azure availability zones, each with independent power, cooling, and networking.\n",
- "pgVerified": false,
- "description": "Enable zone redundancy for Azure SQL Managed Instance to improve high availability and resiliency",
- "potentialBenefits": "Enhanced availability and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/managedInstances",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Managed Instance zone redundancy check – any server that is not configured for ZR\r\nresources\r\n| where type =~ 'Microsoft.Sql/managedInstances'\r\n| extend InstanceName = properties.fullyQualifiedDomainName\r\n| extend ServiceTier = sku.tier\r\n| extend zoneRedundant=properties.zoneRedundant\r\n| where zoneRedundant == 'false'\r\n| project recommendationId='f8f834a9-c761-4e84-b2cb-ac55494d0c37', name, id, tags, param1=strcat('Service Tier:', ServiceTier), param2=strcat('Zone Redundant:', zoneRedundant)\r\n"
- },
- {
- "aprlGuid": "15e2712c-f3ea-4a8d-9081-11e822b1ccfb",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-sql/managed-instance/automated-backups-overview?view=azuresql-mi&preserve-view=true#backup-storage-redundancy",
- "name": "Backup storage redundancy"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Configuring zone redundancy option for backups copies your backup file synchronously across three Azure availability zones in the primary region. If Geo is selected, then it copies your data asynchronously three times to a single physical location in the paired secondary region.\n",
- "pgVerified": false,
- "description": "Use Zone-redundant or Geo-zone-redundant Backup storage redundancy",
- "potentialBenefits": "Enhanced availability and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/managedInstances",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Managed Instance storage backup redundancy check – any server that is not configured for GZRS\r\nresources\r\n| where type =~ 'Microsoft.Sql/managedInstances'\r\n| extend backupredundancy=properties.storageAccountType\r\n| extend ServiceTier = sku.tier\r\n| where backupredundancy != 'GeoZone'\r\n| project recommendationId='15e2712c-f3ea-4a8d-9081-11e822b1ccfb', name, id, param1=strcat('Service Tier:', ServiceTier), param2=strcat('Backup Redundancy:', backupredundancy)\r\n"
- },
- {
- "aprlGuid": "c14de326-2729-4be7-a91f-4ea185d24b10",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-sql/managed-instance/connection-types-overview?view=azuresql#connection-types",
- "name": "Connection types"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Redirect mode enables direct connectivity to the instance bypassing the local gateway component and resulting in improved latency and throughput. Redirect mode applies to the VNet-local endpoint only, while the public and private endpoint will always operate in Proxy connection mode.\n",
- "pgVerified": false,
- "description": "Use Redirect connection type to accelerate application access",
- "potentialBenefits": "Improved latency and throughput",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/managedInstances",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Use Redirect connection type to accelerate application access\r\nresources\r\n| where type =~ 'Microsoft.Sql/managedInstances'\r\n| extend connectionpolicy=properties.proxyOverride\r\n| where connectionpolicy != 'Redirect'\r\n| project recommendationId='c14de326-2729-4be7-a91f-4ea185d24b10', name, id, tags, param1=strcat('Connection Policy:', connectionpolicy)\r\n"
- },
- {
- "aprlGuid": "257cd903-700f-4a79-bd37-7dce2b511df4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-sql/managed-instance/failover-group-sql-mi?view=azuresql",
- "name": "Failover groups overview and best practices"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "During an outage on the managed instance, use the failover group to switch all databases to a secondary region, either manually or automatically. Route connections to the failover group’s listener instead of the primary instance to avoid changing the connection string after geo-failover.\n",
- "pgVerified": false,
- "description": "Configure a secondary instance and a Failover group to enable failover to another region",
- "potentialBenefits": "Ensure seamless service with cross-region failover",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/managedInstances",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "c9afeb1e-e706-4809-be4e-75d9fac708f2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-sql/managed-instance/monitoring-sql-managed-instance-azure-monitor?view=azuresql-mi",
- "name": "Azure SQL Managed Instance monitoring options"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Monitoring and alerting are an important part of database operations. When working with Azure SQL Managed Instance, make use of Azure Monitor and Database watcher to ensure that you capture relevant database metrics.\n",
- "pgVerified": false,
- "description": "Monitor your Azure SQL MI Managed Instance in near-real time to detect reliability incidents",
- "potentialBenefits": "Quick incident detection and response",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/managedInstances",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "9fad5392-b852-4807-9b6d-3f700ff9771a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-sql/database/always-encrypted-landing?view=azuresql",
- "name": "Overview of Always Encrypted"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "It is highly recommended to use Azure Key Vault (AKV) to store encryption keys related to Always Encrypted configurations, however it is not required. If you are not using AKV, then ensure that your keys are properly backed up and stored in a secure manner.\n",
- "pgVerified": false,
- "description": "Back Up Your Keys",
- "potentialBenefits": "Enhanced security and data recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/managedInstances",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "74c2491d-048b-0041-a140-935960220e20",
- "recommendationTypeId": "2ea11bcb-dfd0-48dc-96f0-beba578b989a",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-sql/database/active-geo-replication-overview",
- "name": "Active Geo Replication"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Active Geo Replication ensures business continuity by utilizing readable secondary database replicas. In case of primary database failure, manually failover to secondary database. Secondaries, up to four, can be in same/different regions, used for read-only access.\n",
- "pgVerified": true,
- "description": "Use Active Geo Replication to Create a Readable Secondary in Another Region",
- "potentialBenefits": "Enhanced disaster recovery and read scalability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/servers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of SQL databases that are not part of Geo Replication.\r\nresources\r\n| where type == \"microsoft.sql/servers/databases\" and name != \"master\"\r\n| summarize secondaryTypeCount = countif(isnotempty(properties.secondaryType)) by name\r\n| where secondaryTypeCount == 0\r\n| join kind=inner (\r\n resources\r\n | where type == \"microsoft.sql/servers/databases\" and name != \"master\"\r\n) on name\r\n| extend param1 = \"Not part of Geo Replication\"\r\n| project recommendationId = \"74c2491d-048b-0041-a140-935960220e20\", name, id, tags, param1\r\n"
- },
- {
- "aprlGuid": "943c168a-2ec2-a94c-8015-85732a1b4859",
- "recommendationTypeId": "2ea11bcb-dfd0-48dc-96f0-beba578b989a",
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-sql/database/auto-failover-group-overview?tabs=azure-powershell",
- "name": "AutoFailover Groups"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Failover Groups facilitate disaster recovery by configuring databases on one logical server to replicate to another region's logical server. This streamlines geo-replicated database management, offering a single endpoint for connection routing to replicated databases if the primary server fails.\n",
- "pgVerified": true,
- "description": "Auto Failover Groups can encompass one or multiple databases, usually used by the same app.",
- "potentialBenefits": "Improves load balancing and disaster recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/servers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of SQL databases that are not configured to use a failover-group.\r\nresources\r\n| where type =~'microsoft.sql/servers/databases' and name !~ \"master\"\r\n| where isnull(properties['failoverGroupId'])\r\n| project recommendationId = \"943c168a-2ec2-a94c-8015-85732a1b4859\", name, id, tags, param1= strcat(\"databaseId=\", properties['databaseId'])\r\n"
- },
- {
- "aprlGuid": "c0085c32-84c0-c247-bfa9-e70977cbf108",
- "recommendationTypeId": "807e58d0-e385-41ad-987b-4a4b3e3fb563",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-sql/database/high-availability-sla",
- "name": "Zone Redundant Databases"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "By default, Azure SQL Database premium tier provisions multiple copies within the same region. For geo redundancy, databases can be set as Zone Redundant, distributing copies across Azure Availability Zones to maintain availability during regional outages.\n",
- "pgVerified": true,
- "description": "Enable zone redundancy for Azure SQL Database to achieve high availability and resiliency",
- "potentialBenefits": "Enhanced reliability, no extra cost",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/servers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Finds non-zone redundant SQL databases and lists them\r\nResources\r\n| where type =~ 'microsoft.sql/servers/databases'\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where tolower(tostring(properties.zoneRedundant))=~'false'\r\n|project recommendationId = \"c0085c32-84c0-c247-bfa9-e70977cbf108\", name, id, tags\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "cbb17a29-64fb-c943-95d0-8df814a37c40",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-sql/database/troubleshoot-common-connectivity-issues",
- "name": "How to Implement Retry Logic"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "During transient failures, the application should handle connection retries effectively with Azure SQL Database. No Database layer configuration is needed; instead, the application must be set up for graceful retrying.\n",
- "pgVerified": true,
- "description": "Implement Retry Logic",
- "potentialBenefits": "Enhanced connectivity stability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/servers",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "7e7daec9-6a81-3546-a4cc-9aef72fec1f7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-monitor/insights/azure-sql#analyze-data-and-create-alerts",
- "name": "Azure Monitor"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Monitoring and alerting are an important part of database operations. When working with Azure SQL Database, make use of Azure Monitor and SQL Insights to ensure that you capture relevant database metrics.\n",
- "pgVerified": true,
- "description": "Monitor your Azure SQL Database in Near Real-Time to Detect Reliability Incidents",
- "potentialBenefits": "Quick incident detection and response",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/servers",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of SQL databases that are not configured for monitoring.\r\nresources\r\n| where type == \"microsoft.insights/metricalerts\"\r\n| mv-expand properties.scopes\r\n| mv-expand properties.criteria.allOf\r\n| project databaseid = properties_scopes, monitoredMetric = properties_criteria_allOf.metricName\r\n| where databaseid contains 'databases'\r\n| summarize monitoredMetrics=make_list(monitoredMetric) by databaseid=tolower(tostring(databaseid))\r\n| join kind=fullouter (\r\n resources\r\n | where type =~ 'microsoft.sql/servers/databases'\r\n | project databaseid = tolower(id), name, tags\r\n) on databaseid\r\n| where isnull(monitoredMetrics)\r\n| project recommendationId = \"7e7daec9-6a81-3546-a4cc-9aef72fec1f7\", name, id=databaseid1, tags, param1=strcat(\"MonitoringMetrics=false\" )\r\n\r\n"
- },
- {
- "aprlGuid": "d6ef87aa-574e-584e-a955-3e6bb8b5425b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/key-vault/general/overview",
- "name": "Azure Key Vault"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "It is highly recommended to use Azure Key Vault (AKV) to store encryption keys related to Always Encrypted configurations, however it is not required. If you are not using AKV, then ensure that your keys are properly backed up and stored in a secure manner.\n",
- "pgVerified": true,
- "description": "Back Up Your Keys",
- "potentialBenefits": "Enhanced security and data recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/servers",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "de266d8a-a9f3-4cb9-be95-9306001fceea",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/azure-sql/database/failover-group-sql-db?view=azuresql#endpoint-redirection",
- "name": "Failover Group endpoint redirection"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "When using Failover Groups, it is recommended to connect to the Failover Group endpoint instead of individual database endpoints. This allows for automatic redirection to the secondary database in case of a failover, ensuring high availability.\n",
- "pgVerified": false,
- "description": "Use Failover Group endpoints for database connections",
- "potentialBenefits": "Enhanced disaster recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.Sql/servers",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "e6c7e1cc-2f47-264d-aa50-1da421314472",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/storage/common/storage-redundancy",
- "name": "Azure Storage redundancy"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Redundancy ensures storage accounts meet availability and durability targets amidst failures, weighing lower costs against higher availability. Locally redundant storage offers the least durability at the lowest cost.\n",
- "pgVerified": true,
- "description": "Ensure that storage accounts are zone or region redundant",
- "potentialBenefits": "High availability and durability for storage",
- "tags": null,
- "recommendationResourceType": "Microsoft.Storage/storageAccounts",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This query will return all storage accounts that are not using Zone or Region replication\r\nResources\r\n| where type =~ \"Microsoft.Storage/storageAccounts\"\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| where sku.name in~ (\"Standard_LRS\", \"Premium_LRS\")\r\n| project recommendationId = \"e6c7e1cc-2f47-264d-aa50-1da421314472\", name, id, tags, param1 = strcat(\"sku: \", sku.name)\r\n\r\n"
- },
- {
- "aprlGuid": "5587ef77-7a05-a74d-9c6e-449547a12f27",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/storage/blobs/storage-blob-block-blob-premium",
- "name": "Premium block blob storage accounts"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Use premium performance block blob storage instead of standard performance storage for workloads that require fast storage response times and/or high transaction rates.\n",
- "pgVerified": true,
- "description": "Use premium performance block blob storage for high performance workloads",
- "potentialBenefits": "Optimized cost and performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Storage/storageAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "03263c57-c869-3841-9e0a-3dbb9ef3e28d",
- "recommendationTypeId": "42dbf883-9e4b-4f84-9da4-232b87c4b5e9",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/storage/blobs/soft-delete-blob-enable?tabs=azure-portal",
- "name": "Soft delete detail docs"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "The soft delete option enables data recovery if mistakenly deleted, while the Lock feature prevents the accidental deletion of the storage account itself, ensuring additional security and data integrity measures.\n",
- "pgVerified": true,
- "description": "Enable Soft Delete to protect your data",
- "potentialBenefits": "Prevents accidental data/account loss",
- "tags": null,
- "recommendationResourceType": "Microsoft.Storage/storageAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "8ebda7c0-e0e1-ed45-af59-2d7ea9a1c05d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/storage/blobs/versioning-overview",
- "name": "Blob versioning"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Consider enabling versioning for Azure Storage Accounts to recover from accidental modifications or deletions and manage blob operation latency. Microsoft advises maintaining fewer than 1000 versions per blob to optimize performance. Lifecycle management can help delete old versions automatically.\n",
- "pgVerified": true,
- "description": "Enable versioning for accidental modification and keep the number of versions below 1000",
- "potentialBenefits": "Recover data, manage latency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Storage/storageAccounts",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1b965cb9-7629-214e-b682-6bf6e450a100",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/storage/blobs/point-in-time-restore-overview",
- "name": "Point-in-time restore for block blobs"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Consider enabling point-in-time restore for standard general purpose v2 accounts with flat namespace to protect against accidental deletion or corruption by restoring block blob data to an earlier state.\n",
- "pgVerified": true,
- "description": "Enable point-in-time restore for GPv2 accounts to safeguard against data loss",
- "potentialBenefits": "Protects data from loss/corruption",
- "tags": null,
- "recommendationResourceType": "Microsoft.Storage/storageAccounts",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "96cb8331-6b06-8242-8ce8-4e2f665dc679",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/storage/blobs/monitor-blob-storage",
- "name": "Monitor Azure Blob Storage"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "For critical applications and business processes relying on Azure, monitoring and alerts are crucial. Resource logs are only stored after creating a diagnostic setting to route logs to specified locations, requiring selection of log categories to collect.\n",
- "pgVerified": true,
- "description": "Monitor all blob storage accounts",
- "potentialBenefits": "Enhanced alerting and log analysis",
- "tags": null,
- "recommendationResourceType": "Microsoft.Storage/storageAccounts",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "2ad78dec-5a4d-4a30-8fd1-8584335ad781",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/storage/common/storage-account-upgrade",
- "name": "Upgrade to a general-purpose v2 storage account"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "General-purpose v2 accounts are recommended for most storage scenarios offering the latest features or the lowest per-gigabyte pricing. Legacy accounts like Standard general-purpose v1 and Blob Storage aren't advised by Microsoft but may fit specific scenarios.\n",
- "pgVerified": true,
- "description": "Consider upgrading legacy storage accounts to v2 storage accounts",
- "potentialBenefits": "Latest features, lowest cost",
- "tags": null,
- "recommendationResourceType": "Microsoft.Storage/storageAccounts",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Azure Storage Accounts, that upgradeable to General purpose v2.\r\nResources\r\n| where type =~ \"Microsoft.Storage/storageAccounts\" and kind in~ (\"Storage\", \"BlobStorage\")\r\n| extend\r\n param1 = strcat(\"AccountKind: \", case(kind =~ \"Storage\", \"Storage (general purpose v1)\", kind =~ \"BlobStorage\", \"BlobStorage\", kind)),\r\n param2 = strcat(\"Performance: \", sku.tier),\r\n param3 = strcat(\"Replication: \", sku.name)\r\n| project recommendationId = \"2ad78dec-5a4d-4a30-8fd1-8584335ad781\", name, id, tags, param1, param2, param3\r\n\r\n"
- },
- {
- "aprlGuid": "dc55be60-6f8c-461e-a9d5-a3c7686ed94e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/azure-virtual-desktop/networking#private-endpoints-private-link",
- "name": "Private Link"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Leverage Azure Private Link Service for secure access to Azure Storage and services via Private Endpoint in your VNet. Eliminate the need for public IPs, ensuring data privacy. Enjoy granular access control for enhanced security.\n",
- "pgVerified": true,
- "description": "Enable Azure Private Link service for storage accounts",
- "potentialBenefits": "Secure, private access to storage with no public IPs",
- "tags": null,
- "recommendationResourceType": "Microsoft.Storage/storageAccounts",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This resource graph query will return all storage accounts that does not have a Private Endpoint Connection or where a private endpoint exists but public access is enabled\r\nresources\r\n| where type =~ \"Microsoft.Storage/StorageAccounts\"\r\n| where isnull(properties.privateEndpointConnections) or properties.privateEndpointConnections[0].properties.provisioningState != (\"Succeeded\") or (isnull(properties.networkAcls) and properties.publicNetworkAccess == 'Enabled')\r\n| extend param1 = strcat('Private Endpoint: ', iif(array_length(properties.privateEndpointConnections) != 0,split(properties.privateEndpointConnections[0].properties.privateEndpoint.id,'/')[8],'No Private Endpoint'))\r\n| extend param2 = strcat('Access: ', iif(properties.publicNetworkAccess == 'Disabled', 'Public Access Disabled', iif(isnotnull(properties.networkAcls), 'NetworkACLs in place','Public Access Enabled')))\r\n| project recommendationId = \"dc55be60-6f8c-461e-a9d5-a3c7686ed94e\", name, id, tags, param1, param2\r\n"
- },
- {
- "aprlGuid": "e48a7227-5ec7-463a-b955-ee7cb598ded4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/stream-analytics/cluster-overview",
- "name": "Overview of Azure Stream Analytics Cluster"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Stream Analytics cluster (dedicated) offers more reliable performance guarantees. All the jobs running on your cluster belong only to you. You can also have access to important features like private endpoints, Auto-Scaling, Vnet Support, etc.\n",
- "pgVerified": false,
- "description": "Run jobs in your own dedicated Stream Analytics cluster for increased reliability and security",
- "potentialBenefits": "Enhanced reliability and security",
- "tags": null,
- "recommendationResourceType": "Microsoft.StreamAnalytics/streamingjobs",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Azure Stream Analytics jobs that are not associated with a dedicated cluster\r\nresources\r\n| where type =~ \"Microsoft.StreamAnalytics/streamingjobs\"\r\n| where isnull(properties.cluster.id)\r\n| project recommendationId = \"e48a7227-5ec7-463a-b955-ee7cb598ded4\", name, id, tags\r\n"
- },
- {
- "aprlGuid": "5d40d3d4-179d-4cf5-ac24-901210f512e7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/stream-analytics/stream-analytics-streaming-unit-consumption",
- "name": "Understand and adjust streaming units"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Configure Autoscale to allow your job to dynamically change the allocated number of Streaming Units (SU) based on load, metrics, and/or schedule.\n",
- "pgVerified": false,
- "description": "Migrate Stream Analytics jobs to StandardV2 SKU",
- "potentialBenefits": "Enhanced reliability and security",
- "tags": null,
- "recommendationResourceType": "Microsoft.StreamAnalytics/streamingjobs",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all Azure Stream Analytics jobs that are not using the latest version of the service.\r\nresources\r\n| where type =~ \"Microsoft.StreamAnalytics/streamingjobs\"\r\n| where properties.sku.name !~ \"StandardV2\"\r\n| project recommendationId = \"5d40d3d4-179d-4cf5-ac24-901210f512e7\", name, id, tags\r\n"
- },
- {
- "aprlGuid": "c041d596-6c97-4c5f-b4b3-9cd37628f2e2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://docs.citrix.com/en-us/citrix-daas-azure/limits",
- "name": "Citrix Limits"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "A Citrix Managed Azure subscription supports VMs with VDA for app/desktop delivery, excluding other machines like Cloud Connectors. When close to the limit, signaled by a dashboard notification, and with sufficient licenses, request another subscription. Can't exceed the given limits for catalogs.\n",
- "pgVerified": true,
- "description": "Do not create more than 2000 Citrix VDA servers per subscription",
- "potentialBenefits": "Avoids hitting limit, ensures reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Count VM instances with a tag that contains \"Citrix VDA\" and create output if that count is >2000 for each subscription.\r\n// The Citrix published limit is 2500. This query runs an 80% check.\r\n\r\nresources\r\n| where type == 'microsoft.compute/virtualmachines'\r\n| where tags contains 'Citrix VDA'\r\n| summarize VMs=count() by subscriptionId\r\n| where VMs > 2000\r\n| join (resourcecontainers| where type =='microsoft.resources/subscriptions' | project subname=name, subscriptionId) on subscriptionId\r\n| project recommendationId='c041d596-6c97-4c5f-b4b3-9cd37628f2e2', name= subname, id = subscriptionId, param1='Too many instances.', param2= VMs\r\n\r\n"
- },
- {
- "aprlGuid": "5ada5ffa-7149-4e49-9fbf-e67be7c2594c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/cloud-adoption-framework/ready/landing-zone/design-area/resource-org-management-groups#management-group-recommendations",
- "name": "Management group recommendations"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "The root management group in Azure is designed for organizational hierarchy, allowing for all management groups and subscriptions to fold into it.\n",
- "pgVerified": true,
- "description": "Subscriptions should not be placed under the Tenant Root Management Group",
- "potentialBenefits": "Enhanced security, compliance, and management",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure Subscriptions that are placed under the Tenant Root Management Group\r\nresourcecontainers\r\n| where type == 'microsoft.resources/subscriptions'\r\n| extend mgParentSize = array_length(properties.managementGroupAncestorsChain)\r\n| where mgParentSize == 1\r\n| project recommendationId=\"5ada5ffa-7149-4e49-9fbf-e67be7c2594c\", name, id, tags\r\n\r\n"
- },
- {
- "aprlGuid": "9729c89d-8118-41b4-a39b-e12468fa872b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/service-health/alerts-activity-log-service-notifications-portal",
- "name": "Configure alerts for service health events"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Service health gives a personalized health view of Azure services and regions used, offering the best place for notifications on outages, planned maintenance, and health advisories by knowing the services used.\n",
- "pgVerified": true,
- "description": "Configure Service Health Alerts",
- "potentialBenefits": "Proactive outage and maintenance alerts",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This resource graph query will return all subscriptions without Service Health alerts configured AND subscriptions with Service Health alerts only configured with specific configuration (which requires manual verification regarding the scope being covered by this rule)\r\nresourcecontainers\r\n| where type == 'microsoft.resources/subscriptions'\r\n| project subscriptionId = id, subscriptionName = name, tags\r\n| join kind=leftouter (\r\n resources\r\n | where type == \"microsoft.insights/activitylogalerts\" and properties.condition contains \"ServiceHealth\"\r\n | extend shaRuleType = iff(array_length(properties.condition.allOf) > 1, 'Explicit','All')\r\n | project subscriptionId = strcat('/subscriptions/',subscriptionId), name, shaRuleType\r\n | summarize shaAllRuleCount = countif(shaRuleType == 'All'), shaExplicitRuleCount = countif(shaRuleType == 'Explicit') by subscriptionId\r\n) on subscriptionId\r\n| extend shaStatus = iff(isnull(shaAllRuleCount) and isnull(shaExplicitRuleCount), 'Not configured',iff(shaAllRuleCount >= 1, 'Configured', 'Explicit'))\r\n| where shaStatus != 'Configured'\r\n| project recommendationId = \"9729c89d-8118-41b4-a39b-e12468fa872b\", name = subscriptionName, id= subscriptionId, tags, param1 = iff(shaStatus == 'Explicit', 'Explicit only Service Health Alert Rule(s) found. Please verify that the expected scope is covered by these rule(s).','No Service Health Alert Rule found.')\r\n"
- },
- {
- "aprlGuid": "98bd7098-49d6-491b-86f1-b143d6b1a0ff",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/overview#resource-group-location-alignment",
- "name": "Azure Resource Manager Overview"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Ensure resource locations align with their resource group to manage resources during regional outages. ARM stores resource data, which if in an unavailable region, could halt updates, rendering resources read-only.\n",
- "pgVerified": true,
- "description": "Ensure Resource Group and its Resources are located in the same Region",
- "potentialBenefits": "Improves outage management",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure Resource Groups that have resources deployed in a region different than the Resource Group region\r\nresourcecontainers\r\n| where type =~ \"Microsoft.Resources/subscriptions/resourceGroups\"\r\n| project resourceGroupId = tolower(id), resourceGroupLocation = location\r\n| join kind = inner (\r\n resources\r\n | where location !~ \"Global\" and // Exclude global resources\r\n resourceGroup !~ \"NetworkWatcherRG\" and // Exclude resources in the NetworkWatcherRG\r\n id has \"/resourceGroups/\" // Exclude resources not in a resource group\r\n | project id, name, tags, resourceGroup, location, resourceGroupId = tolower(strcat_array(array_slice(split(id, \"/\"), 0, 4), \"/\"))\r\n )\r\n on resourceGroupId\r\n| where resourceGroupLocation !~ location\r\n| project\r\n recommendationId = \"98bd7098-49d6-491b-86f1-b143d6b1a0ff\",\r\n name,\r\n id,\r\n tags,\r\n param1 = strcat(\"resourceLocation: \", location),\r\n param2 = strcat(\"resourceGroupLocation: \", resourceGroupLocation),\r\n param3 = strcat(\"resourceGroup: \", resourceGroup)\r\n"
- },
- {
- "aprlGuid": "19b6df57-f6b5-3e4f-843a-273daa087cb0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/generation-2#features-and-capabilities",
- "name": "Generation 1 vs generation 2 virtual machines"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "When building Image Templates, use sources for gen 2 VMs. Gen 2 offers more memory, supports >2TB disks, uses UEFI for faster boot/installation, has Intel SGX, and virtualized persistent memory (vPMEM), unlike gen 1's BIOS-based architecture.\n",
- "pgVerified": true,
- "description": "Use Generation 2 virtual machine source image",
- "potentialBenefits": "More memory, supports >2TB disks, faster boot",
- "tags": null,
- "recommendationResourceType": "Microsoft.VirtualMachineImages/imageTemplates",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "21fb841b-ba70-1f4e-a460-1f72fb41aa51",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/reliability/reliability-image-builder?toc=%2Fazure%2Fvirtual-machines%2Ftoc.json&bc=%2Fazure%2Fvirtual-machines%2Fbreadcrumb%2Ftoc.json&tabs=graph#disaster-recovery",
- "name": "Image Template resiliency"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "The Azure Image Builder service lacks availability zones support. Replicating Image Templates to a secondary region will enable the build of new images in secondary region.\n",
- "pgVerified": true,
- "description": "Replicate your Image Templates to a secondary region",
- "potentialBenefits": "Enhances disaster recovery capability",
- "tags": null,
- "recommendationResourceType": "Microsoft.VirtualMachineImages/imageTemplates",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// List all Image Templates that are not replicated to another region\r\nresources\r\n| where type =~ \"microsoft.virtualmachineimages/imagetemplates\"\r\n| mv-expand distribution=properties.distribute\r\n| where array_length(parse_json(distribution).replicationRegions) == 1\r\n| project recommendationId = \"21fb841b-ba70-1f4e-a460-1f72fb41aa51\", name, id, param1=strcat(\"replicationRegions:\",parse_json(distribution).replicationRegions)\r\n\r\n"
- },
- {
- "aprlGuid": "88cb90c2-3b99-814b-9820-821a63f600dd",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/reliability/migrate-app-service",
- "name": "Migrate App Service to availability zone support"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure's feature of deploying App Service plans across availability zones enhances resiliency and reliability by ensuring operation during datacenter failures, providing redundancy without needing different regions, thus minimizing downtime and maintaining uninterrupted services.\n",
- "pgVerified": false,
- "description": "Migrate App Service to availability Zone Support",
- "potentialBenefits": "Enhances app resiliency and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/serverFarms",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// The query filters the qualified App Service Plans that do not have Zone Redundancy enabled.\r\n// Its important to check regions that support availability zones for Azure App Services running on multi-tenant and App Service Environments https://learn.microsoft.com/en-us/azure/reliability/reliability-app-service?tabs=graph%2Ccli#:~:text=The%20following%20regions%20support%20Azure%20App%20Services%20running%20on%20multi%2Dtenant%20environments%3A\r\n\r\nresources\r\n| where type =~ 'microsoft.web/serverfarms'\r\n| where location in~ (\"australiaeast\", \"brazilsouth\", \"canadacentral\", \"centralindia\", \"centralus\", \"eastasia\", \"eastus\", \"eastus2\", \"francecentral\", \"germanywestcentral\", \"israelcentral\", \"italynorth\", \"japaneast\", \"japanwest\", \"koreacentral\", \"mexicocentral\", \"newzealandnorth\", \"northeurope\", \"norwayeast\", \"polandcentral\", \"qatarcentral\", \"southafricanorth\", \"southcentralus\", \"southeastasia\", \"spaincentral\", \"swedencentral\", \"switzerlandnorth\", \"uaenorth\", \"uksouth\", \"westeurope\", \"westus2\", \"westus3\", \"usgovvirginia\", \"chinanorth3\")\r\n| extend zoneRedundant = tobool(properties.zoneRedundant)\r\n| extend sku_tier = tostring(sku.tier)\r\n| where (tolower(sku_tier) contains \"isolated\" or tolower(sku_tier) contains \"premium\") and zoneRedundant == false\r\n| project recommendationId=\"88cb90c2-3b99-814b-9820-821a63f600dd\", name, id, tags, param1=sku_tier, param2=\"Not Zone Redundant\"\r\n\r\n"
- },
- {
- "aprlGuid": "b2113023-a553-2e41-9789-597e2fb54c31",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/architecture/checklist/resiliency-per-service#app-service",
- "name": "Resiliency checklist for specific Azure services"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Choose Standard/Premium Azure App Service Plan for robust apps with advanced scaling, high availability, better performance, and multiple slots, ensuring resilience and continuous operation.\n",
- "pgVerified": false,
- "description": "Use Standard or Premium tier",
- "potentialBenefits": "Enhanced scaling and reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/serverFarms",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure App Service Plans that are not in the \"Standard\", \"Premium\", or \"IsolatedV2\" SKU tiers.\r\n\r\nresources\r\n| where type =~ 'microsoft.web/serverfarms'\r\n| extend sku_tier = tostring(sku.tier)\r\n| where tolower(sku_tier) !contains \"standard\" and\r\n tolower(sku_tier) !contains \"premium\" and\r\n tolower(sku_tier) !contains \"isolatedv2\"\r\n| project recommendationId=\"b2113023-a553-2e41-9789-597e2fb54c31\", name, id, tags, param1= strcat(\"SKU=\",sku_tier)\r\n\r\n"
- },
- {
- "aprlGuid": "07243659-4643-d44c-a1c6-07ac21635072",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/architecture/checklist/resiliency-per-service#app-service",
- "name": "Resiliency checklist for specific Azure services"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Avoid frequent scaling up/down of Azure App Service instances to prevent service disruptions. Choose the right tier and size for the workload and scale out for traffic changes, as scaling adjustments can trigger application restarts.\n",
- "pgVerified": false,
- "description": "Avoid scaling up or down",
- "potentialBenefits": "Minimizes restarts, enhances stability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/serverFarms",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure App Service Plans and the number of changes that was made to the pricing tier, if the count is higher that 3 it means you need to avoid scaling up and down that often\r\n\r\nresourcechanges\r\n| extend changeTime = todatetime(properties.changeAttributes.timestamp), targetResourceId = tostring(properties.targetResourceId),\r\nchangeType = tostring(properties.changeType), correlationId = properties.changeAttributes.correlationId,\r\nchangedProperties = properties.changes, changeCount = properties.changeAttributes.changesCount\r\n| where changeTime > ago(14d)\r\n| join kind=inner (resources | project resources_Name = name, resources_Type = type, resources_Subscription= subscriptionId, resources_ResourceGroup= resourceGroup, id) on $left.targetResourceId == $right.id\r\n| where resources_Type contains \"microsoft.web/serverfarms\"\r\n| where changedProperties['sku.name'].propertyChangeType == 'Update' or changedProperties['sku.tier'].propertyChangeType == 'Update'\r\n| summarize count() by targetResourceId, resources_Name ,tostring(changedProperties['sku.name'].previousValue), tostring(changedProperties['sku.tier'].newValue)\r\n| project recommendationId=\"07243659-4643-d44c-a1c6-07ac21635072\", name=resources_Name, id=targetResourceId, tags=\"\", param1=['changedProperties_sku.name_previousValue'], param2=['changedProperties_sku.tier_newValue'], param3=count_\r\n\r\n"
- },
- {
- "aprlGuid": "dbe3fd66-fb2a-9d46-b162-1791e21da236",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/architecture/checklist/resiliency-per-service#app-service",
- "name": "Resiliency checklist for specific Azure services"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "It is strongly recommended to create separate App Service plans for production and test environments to avoid using slots within your production deployment for testing purposes.\n",
- "pgVerified": false,
- "description": "Create separate App Service plans for production and test",
- "potentialBenefits": "Protects prod performance; avoids test impact",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/serverFarms",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "6320abf6-f917-1843-b2ae-4779c35985ae",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/app-service/manage-automatic-scaling?tabs=azure-portal",
- "name": "Automatic scaling in Azure App Service"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Enabling Autoscale/Automatic Scaling for your Azure App Service ensures sufficient resources for incoming requests. Autoscaling is rule-based, whereas Automatic Scaling, a newer feature, automatically adjusts resources based on HTTP traffic.\n",
- "pgVerified": true,
- "description": "Enable Autoscale/Automatic scaling to ensure adequate resources are available to service requests",
- "potentialBenefits": "Optimizes resources for traffic",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/serverFarms",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "855ca19a-6518-4f2e-9e5a-01796fbca9f8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://azure.github.io/AppService/2020/05/15/Robust-Apps-for-the-cloud.html",
- "name": "Ultimate guide to running healthy apps in the cloud"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "App Service should be configured with a minimum of two instances for production workloads. If apps have a longer warmup time a minimum of three instances should be used.\n",
- "pgVerified": true,
- "description": "Set minimum instance count to 2 for app service",
- "potentialBenefits": "Improves app performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/serverFarms",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of App services that do not have minimum instance count of 2\r\n\r\nresources\r\n| where type == \"microsoft.web/serverfarms\"\r\n| where sku.capacity < 2\r\n| project recommendationId = \"855ca19a-6518-4f2e-9e5a-01796fbca9f8\", name, id, tags, param1 = \"Instance count is less than 2\"\r\n\r\n"
- },
- {
- "aprlGuid": "493f6079-3bb6-4a56-96ba-ab3248474cb1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/app-service/troubleshoot-diagnostic-logs",
- "name": "Enable diagnostics logging for apps in Azure App Service"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Enabling diagnostics logging for your Azure App Service is crucial for monitoring and diagnostics, including both application logging and web server logging.\n",
- "pgVerified": false,
- "description": "Enable diagnostics logging",
- "potentialBenefits": "Monitoring and Alerting",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "a7e8bb3d-8ceb-442d-b26f-007cd63f9ffc",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/application-insights/app-insights-overview",
- "name": "Application Insights"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Use Application Insights to monitor app performance and load behavior, offering real-time insights, issue diagnosis, and root-cause analysis. It supports ASP.NET, ASP.NET Core, Java, and Node.js on Azure App Service, now with built-in monitoring.\n",
- "pgVerified": true,
- "description": "Monitor Performance",
- "potentialBenefits": "Real-time insights and issue diagnosis",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "78a5c033-ff51-4332-8a71-83464c34494b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/checklist/resiliency-per-service#app-service",
- "name": "Resiliency checklist for specific Azure services"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "If your solution includes both a web front end and a web API, decomposing them into separate App Service apps facilitates solution decomposition by workload, allowing for independent scaling. Initially, you can deploy both in the same plan and separate them for independent scaling when necessary.\n",
- "pgVerified": false,
- "description": "Separate web apps from web APIs",
- "potentialBenefits": "Independent scaling, easier management",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "3f9ddb59-0bb3-4acb-9c9b-99aa1776f0ab",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/checklist/resiliency-per-service#app-service",
- "name": "Resiliency checklist"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Creating a separate storage account for logs and not using the same one for application data prevents logging activities from reducing application performance by ensuring that the resources dedicated to handling application data are not burdened by logging processes.\n",
- "pgVerified": true,
- "description": "Create a separate storage account for logs",
- "potentialBenefits": "Improves app performance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "a1d91661-32d4-430b-b3b6-5adeb0975df7",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/app-service-web/web-sites-staged-publishing",
- "name": "Set up staging environments in Azure App Service"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Create a deployment slot for staging to deploy updates, verify them, and ensure all instances are warmed up before production swap, reducing bad update chances. An LKG slot allows easy rollback to a previous good deployment if issues arise later, enhancing reliability.\n",
- "pgVerified": false,
- "description": "Deploy to a staging slot",
- "potentialBenefits": "Safer updates and easy rollback",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Display App Service with the count of deployment slots for Apps under eligible App service plans and it shows if deployment slot is enabled or not\r\n\r\nresources\r\n| where type =~ 'microsoft.web/sites' or type =~ 'microsoft.web/sites/slots'\r\n| extend isSlot = iff(type =~ 'microsoft.web/sites/slots', 1, 0)\r\n| extend AspName = iff(isSlot == 1, split(name, '/')[0], name)\r\n| extend Sku = tostring(properties.sku)\r\n| where tolower(Sku) contains \"standard\" or tolower(Sku) contains \"premium\" or tolower(Sku) contains \"isolatedv2\"\r\n| project id, name, AspName, isSlot, Sku\r\n| summarize Slots = countif(isSlot == 1) by id, name, AspName, Sku\r\n| extend DeploymentSlotEnabled = iff(Slots > 1, true, false)\r\n| where DeploymentSlotEnabled = false\r\n| project recommendationId=\"a1d91661-32d4-430b-b3b6-5adeb0975df7\", name, id, tags=\"\", param1=Sku, param2=Slots, param3=\"DeploymentSlotEnabled=false\"\r\n\r\n"
- },
- {
- "aprlGuid": "0b80b67c-afbe-4988-ad58-a85a146b681e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/app-service-web/web-sites-configure",
- "name": "Configure web apps in Azure App Service"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Use app settings for configuration and define them in Resource Manager templates or via PowerShell to facilitate part of an automated deployment/update process for improved reliability.\n",
- "pgVerified": true,
- "description": "Store configuration as app settings",
- "potentialBenefits": "Enhanced reliability via automation",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure App Service resources that don't have App Settings configured\r\n\r\nappserviceresources\r\n| where type == \"microsoft.web/sites/config\"\r\n| extend AppSettings = iif(isempty(properties.AppSettings), true, false)\r\n| where AppSettings == false\r\n| extend id = replace(@\"/config/web$\", \"\", id)\r\n| project recommendationId=\"0b80b67c-afbe-4988-ad58-a85a146b681e\", id, name, tags=\"\", param1=\"AppSettings is not configured\"\r\n"
- },
- {
- "aprlGuid": "fd049c28-ae6d-48f0-a641-cc3ba1a3fe1d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/app-service/monitor-instances-health-check?tabs=dotnet#enable-health-check",
- "name": "Monitor the health of App Service instances"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Use Health Check for production workloads. Health check increases your application's availability by rerouting requests away from unhealthy instances, and replacing instances if they remain unhealthy. The Health check path should check critical components of your application.\n",
- "pgVerified": true,
- "description": "Enable Health check for App Services",
- "potentialBenefits": "Enhanced reliability via automation",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Check if Health Check is enabled for App Service\r\n\r\nresources\r\n| where type =~ 'microsoft.web/sites'\r\n| where properties.kind has 'app'\r\n| join kind = inner\r\n (\r\n appserviceresources\r\n | where isnull(properties.HealthCheckPath) == true\r\n | project name\r\n ) on name\r\n| project recommendationId = \"fd049c28-ae6d-48f0-a641-cc3ba1a3fe1d\", name, id, tags, param1 = \"Healthcheckpath = not set\"\r\n"
- },
- {
- "aprlGuid": "aab6b4a4-9981-43a4-8728-35c7ecbb746d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/app-service/app-service-ip-restrictions?tabs=azurecli",
- "name": "Set up Azure App Service access restrictions"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Use network access restrictions to define a priority-ordered allow/deny list that controls network access to your app. Web application firewalls, such as the one available in Application Gateway, are recommended for protection of public-facing web applications.\n",
- "pgVerified": true,
- "description": "Configure network access restrictions",
- "potentialBenefits": "Enhanced security",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Medium",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Check if Network access restrictions defined for App service\r\n\r\nresources\r\n| where type =~ 'microsoft.web/sites'\r\n| where properties.kind has 'app'\r\n| join kind = inner\r\n (\r\n appserviceresources\r\n | mv-expand IpSecurityRestrictions = properties.IpSecurityRestrictions\r\n | where isnotnull(IpSecurityRestrictions) == true\r\n | project name\r\n ) on name\r\n| project recommendationId = \"aab6b4a4-9981-43a4-8728-35c7ecbb746d\", name, id, tags, param1 = \"No network restrictions set\"\r\n"
- },
- {
- "aprlGuid": "c6c4b962-5af4-447a-9d74-7b9c53a5dff5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://azure.github.io/AppService/2018/09/10/Announcing-the-New-Auto-Healing-Experience-in-App-Service-Diagnostics.html",
- "name": "Announcing the New Auto Healing Experience in App Service Diagnostics - Azure App Service"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Auto Heal allows you to mitigate your apps when it runs into unexpected situations like HTTP server errors, resource exhaustion, etc. You can configure different triggers based on your need and choose to recycle the app to recover it from a bad state.\n",
- "pgVerified": false,
- "description": "Enable auto heal for Functions App",
- "potentialBenefits": "Improved app availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Low",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Provides a list of Azure Function App resources that do not have auto heal enabled\r\n\r\nResources\r\n| where type =~ 'microsoft.web/sites'\r\n| where properties.kind contains 'functionapp'\r\n| join kind=inner\r\n (appserviceresources\r\n | where type == \"microsoft.web/sites/config\"\r\n | where properties.AutoHealEnabled == 'false'\r\n | project id, name, tenantId, location, resourceGroup, properties.AutoHealEnabled\r\n ) on name\r\n| project recommendationID = \"c6c4b962-5af4-447a-9d74-7b9c53a5dff5\", name, id, type, kind, param1=\"AutoHealEnabled =false\"\r\n"
- },
- {
- "aprlGuid": "52f368ee-1d77-4b34-92db-64be269642d0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-warmup?tabs=in-process%2Cnodejs-v4&pivots=programming-language-csharp#trigger",
- "name": "Azure Functions Warmup Trigger"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Add a warmup trigger to pre-load custom dependencies during the pre-warming process so that your functions are ready to start processing requests immediately.\n",
- "pgVerified": false,
- "description": "No warmup trigger added to Function App",
- "potentialBenefits": "Improved app availability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "0b06a688-0dd6-4d73-9f72-6666ff853ca9",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-name-rules",
- "name": "Resource naming restrictions - Azure Resource Manager"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "A host ID must be between 1 and 32 characters, contain only lowercase letters, numbers, and dashes, not start or end with a dash, and not contain consecutive dashes. The host ID value should be unique for all apps/slots you're running.\n",
- "pgVerified": false,
- "description": "Ensure unique hostid set for Function App",
- "potentialBenefits": "Easier management",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "c9a278b7-024b-454b-bd54-41587c512b74",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-functions/migrate-version-3-version-4?tabs=net6-in-proc%2Cazure-cli%2Cwindows&pivots=programming-language-csharp",
- "name": "Migrate version 3.x to 4.x"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Beginning on December 13, 2022, function apps running on versions 2.x and 3.x of the Azure Functions runtime have reached the end of life (EOL) of extended support. We highly recommend you migrating your function apps to version 4.x of the Functions runtime.\n",
- "pgVerified": false,
- "description": "Ensure Function App runs a supported version",
- "potentialBenefits": "Better governance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "7c608f46-46b2-4cc0-bbd6-1d457c16671c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-functions/functions-app-settings#functions_worker_runtime",
- "name": "FUNCTIONS_WORKER_RUNTIME"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "The FUNCTIONS_WORKER_RUNTIME setting in the Function App configuration should be set to the appropriate value based on the language you are using. This setting is used to determine the language worker that will be used to execute your functions.\n",
- "pgVerified": false,
- "description": "Ensure FUNCTIONS_WORKER_RUNTIME is set properly",
- "potentialBenefits": "Better governance",
- "tags": null,
- "recommendationResourceType": "Microsoft.Web/sites",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "47176883-2602-455b-97f0-6c6a371bf928",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/machine-learning/how-to-monitor-online-endpoints?view=azureml-api-2#using-application-insights",
- "name": "Monitor online endpoints using Application Insights"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Azure Machine Learning uses integration with Azure Monitor to monitor metrics and logs for online endpoints. Use the built-in features of Application Insights (such as Live metrics, Transaction search, Failures, and Performance) for further analysis.\n",
- "pgVerified": false,
- "description": "Enable Application insights to monitor online endpoints for Azure Machine learning",
- "potentialBenefits": "Monitoring endpoints gives visibility into metrics and logs",
- "tags": "AI",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "89928e61-bba8-4c25-99c5-a06a09849ecc",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-monitor/logs/data-retention-configure?tabs=portal-3%2Cportal-1%2Cportal-2",
- "name": "Data collection, retention, and storage in Application Insights"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Create Application Insights for machine learning workspace in both regions. To adjust the data-retention period, update and manage data retention in a Log Analytics workspace.\n",
- "pgVerified": false,
- "description": "Create Application insights for Machine learning workspace in both the regions",
- "potentialBenefits": "Provides monitoring and data retention in DR region",
- "tags": "AI",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "0bf1a2bb-7617-4ab2-a784-e7ea40c5f01b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Disabled",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/azure-virtual-desktop/monitoring#resource-health",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Set up Service Health alerts so that you stay aware of service issues, planned maintenance, or other changes that might affect your Azure Virtual Desktop resources. Use Resource Health to monitor your VMs and storage solutions.\n",
- "pgVerified": true,
- "description": "Monitor service health and resource health for AVD",
- "potentialBenefits": "Enhanced AVD error tracking and resolution",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// This resource graph query, will return rows if service health alerts haven't been configured for AVD service\r\nresourcecontainers\r\n| where type == 'microsoft.resources/subscriptions'\r\n| project subscriptionAlerts=tostring(id),name,tags\r\n| join kind=leftouter (\r\n resources\r\n | where type == 'microsoft.insights/activitylogalerts' and properties.condition contains \"ServiceHealth\"\r\n | extend subscriptions = properties.scopes\r\n | project subscriptions\r\n | mv-expand subscriptions\r\n | project subscriptionAlerts = tostring(subscriptions)\r\n) on subscriptionAlerts\r\n| where isempty(subscriptionAlerts1)\r\n| project-away subscriptionAlerts1\r\n| project recommendationId = \"0bf1a2bb-7617-4ab2-a784-e7ea40c5f01b\",id=subscriptionAlerts,name,tags, param1 = \"AVDServiceHealthAlertsConfigured: False\"\r\n"
- },
- {
- "aprlGuid": "0cf72d91-644d-4591-9bb7-84ba3f705a41",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/insights?tabs=monitor",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Configure AVD insights workbook template to monitor and troubleshoot AVD workloads across metrics, logs, events, and more. Both Production and DR workloads should be enabled with AVD Insights.\n",
- "pgVerified": true,
- "description": "Configure AVD Insights workbook",
- "potentialBenefits": "Enhanced AVD monitoring and troubleshooting",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "89b4d8f6-6345-4d66-9012-c3fc2aef94e8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/diagnostics-log-analytics",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Having separate Log Analytics ensures that your DR environment is fully operational for visibility of the metrics, performance, and other auditing tools your workload teams will rely on in the event of an incident.\n",
- "pgVerified": true,
- "description": "Ensure separate log analytics workspaces for Prod and DR",
- "potentialBenefits": "Improved DR visibility and operation",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "204b56b0-9710-4c16-b506-bafb5fb318ed",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cloud-adoption-framework/scenarios/azure-virtual-desktop/enterprise-scale-landing-zone",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Follow AVD Landing Zone best practices using multiple resource groups based on resource type and associated shared resources for AVD workloads.\n",
- "pgVerified": true,
- "description": "Organize AVD resources using the AVD scale unit model described by the AVD landing zone methodology",
- "potentialBenefits": "Enhanced organization and scalability",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "ef4b3561-c85f-47cf-8cb0-51fae9ddf929",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/azure-virtual-desktop/business-continuity#capacity-planning",
- "name": "Capacity Planning"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Monitor and plan for subscription limits and API throttling limits. Keep track of resource usage within your subscription. Consider scaling across multiple subscriptions if further scaling is required.\nTo handle a large number of users, consider scaling horizontally by creating multiple host pools.\n",
- "pgVerified": true,
- "description": "Monitor and plan capacity for AVD resources",
- "potentialBenefits": "Avoids limits, ensures smooth scaling",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "e1a34ac6-8761-4020-b537-d60c0be7514e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/example-scenario/azure-virtual-desktop/azure-virtual-desktop-multi-region-bcdr",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Active Directory Domain Services (AD DS) integrated DNS/other should target Secondary/Tertiary customer DNS across multi-region zones. If using custom DNS, ensure there are redundant DNS servers to avoid a single point of failure.\n",
- "pgVerified": true,
- "description": "Ensure DNS regions are replicated to avoid single point of failure",
- "potentialBenefits": "Improves uptime & resilience",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "0714d039-535e-468d-9732-e32b5c094faa",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/example-scenario/wvd/azure-virtual-desktop-multi-region-bcdr",
- "name": "Multi-region BCDR"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "It is recommended to adopt a multi-region deployment (active-active or active-passive) for AVD. Each region should contain at least identity, name resolution, AVD management resources, and session hosts in case of a primary region outage.\n",
- "pgVerified": true,
- "description": "Implement a multi-region BCDR Plan",
- "potentialBenefits": "Enhanced resilience and uptime",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "ed1f0327-0914-49e8-9518-16acb0d6b8d6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/storage/files/storage-files-scale-targets",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "To maximize capacity and performance scaling it is recommended to creat only one file share per Azure files storage account, with this approach the single file share will be able to grow to the maximum capacities of the storage account.\n",
- "pgVerified": true,
- "description": "Create only one FSLogix file share per Storage Account",
- "potentialBenefits": "Enhanced scaling and performance",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "ff916698-7507-4519-b545-c94dd81d73c5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/create-host-pools-user-profile",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "To maximize capacity and performance scaling of the file share service and avoid user's profile contention, it is recommended to create one file share target and FSLogix setup per host pool.\n",
- "pgVerified": true,
- "description": "Create a dedicated FSLogix file share and setup per host pool",
- "potentialBenefits": "Enhanced performance",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "0025ed2e-41f4-4ada-93c1-12484cef8b0c",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/fslogix/overview-what-is-fslogix",
- "name": "FSLogix"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "It is recommended to enable backup on the FSLogix Storage Account. Ensuring the user profiles are resilient will allow user data and experience to be consistent through outages.\n",
- "pgVerified": true,
- "description": "Enable Azure backup for FSLogix storage account file shares",
- "potentialBenefits": "Ensures data resilience and consistency",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "3835b4b3-0479-4be8-9ffd-34ae29fa33b9",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/rdp-shortpath?tabs=managed-networks",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "RDP Shortpath establishes a direct UDP-based connection between a client and the session host. By default, RDP tries to use UDP and falls back to TCP if needed. UDP transport offers better connection reliability and consistent latency.\n",
- "pgVerified": true,
- "description": "Implement RDP shortpath for public or managed networks",
- "potentialBenefits": "Better reliability and consistent latency",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "e718ac1a-ebab-4f75-9e4a-1a5ccef20d1f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/troubleshoot-rdp-shortpath",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Ensure AVD session hosts can communicate with the AVD control plane and that UDP ports are open if used. Validate VM connectivity to the AVD Control Plane and confirm UDP TURN port accessibility. Whitelist global URLs and ensure UDP/TURN ports are open for smooth user connections.\n",
- "pgVerified": true,
- "description": "Ensure AVD session hosts connect to control plane & allow UDP ports for RDP shortpath",
- "potentialBenefits": "Enhanced performance & user experience",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "d984eaf9-0fa1-4f8d-a326-bda751993c6f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/entra/identity/hybrid/connect/how-to-connect-install-multiple-domains",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Hybrid - Entra ID Connect best to run in Azure but can be hosted on-prem. Secondary or more VMs should be setup in staging mode in event of failover.\nSet up secondary server in staging mode for Entra Connect for syncing to Entra in case of primary server outage.\n",
- "pgVerified": true,
- "description": "Ensure secondary Entra ID connect synchronization server",
- "potentialBenefits": "Improved failover reliability",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "db1727d1-5c8e-4a01-a31e-f0d58cfd95b1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/expressroute/designing-for-disaster-recovery-with-expressroute-privatepeering#need-for-redundant-connectivity-solution",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For high availability connections back to on-premises data centers should consider backup paths across the regions that have been utilized. Ensure redundancy in routing by having a secondary route table in the secondary region.\n",
- "pgVerified": true,
- "description": "Ensure virtual networks have route tables/route server configured for all regions",
- "potentialBenefits": "Enhanced availability & routing",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "37d1091b-e599-4548-a067-a9286be16e45",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/cloud-adoption-framework/ready/azure-best-practices/plan-for-ip-addressing",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "BusinessContinuity",
- "longDescription": "NSG and ASG per AVD persona and IP space per Prod/DR regions. Plan IP addressing to avoid overlaps between on-premises and Azure regions, preventing major contention challenges.\n",
- "pgVerified": true,
- "description": "Ensure virtual networks isolation with separate IP space and NSGs for Prod and DR",
- "potentialBenefits": "Enhances security and prevents IP conflicts",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1c6c97d7-4d03-4f53-985d-fa239f715173",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-network/service-tags-overview",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Ensure Route Tables have static routes for session host traffic targeting the AVD control plane to go directly to the internet (next hop). This avoids delays from additional hops or inspections in trusted traffic communication.\n",
- "pgVerified": true,
- "description": "Configure static routes for session hosts to directly access the AVD control plane subnet",
- "potentialBenefits": "Enhanced performance and Disaster Recovery",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "2831dab9-6a43-44a1-8aec-90a8e84894bc",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/training/modules/create-manage-session-host-image/",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Establish a process for handling image updates in your AVD environment. Instead of updating session hosts directly, create a new version of the updated image. This involves creating and configuring a golden image with the necessary updates and configurations.\n",
- "pgVerified": true,
- "description": "Create updated image version and replace session hosts rather than updating host directly",
- "potentialBenefits": "Ensures consistency; minimizes drift",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "c15b2b73-52a1-4db2-88dd-d592424ff4e4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/fslogix/reference-configuration-settings?tabs=profiles",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Ensure all session hosts have the standard FSLogix configuration deployed. Regularly validate settings for consistency and alignment with best practices.\n",
- "pgVerified": true,
- "description": "Ensure the standard FSLogix configuration is deployed",
- "potentialBenefits": "Optimized session reliability and performance",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "7b170ddd-5770-4945-9bc3-cd1ccf5f8672",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/fslogix/how-to-configure-storage-permissions",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Verify user permissions are correctly set on SMB shares so that users have appropriate access to only their own profile and not other user profiles, while administrators have full access at the root volume. Also ensure secondary storage path permissions are set in case of a DR event.\n",
- "pgVerified": true,
- "description": "Ensure user permissions are set correctly on FSLogix SMB shares",
- "potentialBenefits": "Enhanced security & disaster recovery",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n\r\n"
- },
- {
- "aprlGuid": "483f5a00-84a0-49f7-903b-ef6f1fc0c389",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/fslogix/troubleshooting-events-logs-diagnostics",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Configure diagnostic settings on FSLogix storage and regularly monitor its metrics and logs for errors. While events can be reviewed locally on the Session Host, it is recommended to use AVD insights workbook to consolidate this information into a Log Analytics workspace.\n",
- "pgVerified": true,
- "description": "Configure Diagnostic Settings on FSLogix storage and capture session hosts FSLogix events",
- "potentialBenefits": "Enhanced AVD error tracking and resolution",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "d51e0a70-8b50-4be3-af8a-7c9065e47360",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/fslogix/how-to-install-fslogix",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Governance",
- "longDescription": "Ensure a process to regularly check and update FSLogix agent. Upgrade to the latest version promptly to address bugs and meet support requirements. FSLogix releases hotfixes to resolve issues impacting deployments. Keeping FSLogix updated is crucial for support and reliability.\n",
- "pgVerified": true,
- "description": "Manually install FSLogix updates",
- "potentialBenefits": "Enhanced reliability & support",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Low",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "9b2301af-9cac-4f1a-871a-f17475d01812",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/app-attach-overview?pivots=msix-app-attach",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Turn on Continuous Availability if using Azure Netapp Files.\nVerify the number of users connecting to each file share to make sure the SMB path can handle the number of file connections.\n",
- "pgVerified": true,
- "description": "Turn on continuous availability for ANF",
- "potentialBenefits": "Enhanced stability & user limit checks",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "7d9c96a6-1ce5-4cf0-ad1b-638a37f753cb",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/virtual-desktop/app-attach-overview?pivots=msix-app-attach",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "App Attach packages should be on a separate share from profiles and backed up. Requirements vary based on the number of packaged applications. Test your applications to understand your needs. Ensure the file share is in the same Azure region as your session hosts.\n",
- "pgVerified": true,
- "description": "Use dedicated file share for App attach and include the storage in the disaster recovery plan",
- "potentialBenefits": "Enhances performance and scalability",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1f57434f-f884-41f3-b818-129bbe3c5d3b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/key-vault/general/disaster-recovery-guidance",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "To ensure continuous availability and disaster recovery readiness, provision a secondary Key Vault in a secondary region. In case of a primary region failure, the secondary Key Vault will ensure critical secrets remain accessible for deployments in the secondary region.\n",
- "pgVerified": true,
- "description": "Ensure resilient deployment of key vaults for AVD Host Pools",
- "potentialBenefits": "Ensures DR readiness and access",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "d61f6ee8-de1b-4fd9-9ce3-316cfe11ee05",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/example-scenario/azure-virtual-desktop/azure-virtual-desktop-multi-region-bcdr",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Deploy multiple domain controllers on Azure VMs across availability zones with AVD session hosts. This removes on-premises dependencies and improves performance with a shorter authentication path. This doesn't apply to Microsoft Entra ID or Entra Domain Services joined session hosts.\n",
- "pgVerified": true,
- "description": "Deploy multiple domain controllers across availability zones in each region with AVD session hosts.",
- "potentialBenefits": "Enhanced identity resilience",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "99bf5c94-aa68-4bb3-8b7f-45d1c5f09b5d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/architecture/example-scenario/identity/adds-extend-domain#reliability",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Deploy custom DNS servers on Azure VMs across availability zones in the same region as session hosts. This removes on-premises dependencies and improves performance by shortening the name resolution path.\n",
- "pgVerified": true,
- "description": "Deploy two or more DNS servers across availability zones in each region with AVD session hosts.",
- "potentialBenefits": "Enhanced reliability and performance",
- "tags": "AVD",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n"
- },
- {
- "aprlGuid": "726abfe3-adae-4a6d-8eb8-4b27a7214ca1",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/connect-multiple-private-clouds-same-region",
- "name": "Connect Private Clouds in the same region"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use the Interconnect feature for direct communication between private clouds in different availability zones, enabling connectivity between the private clouds management and workload networks.\n",
- "pgVerified": true,
- "description": "Use the AVS Interconnect feature to connect private clouds in different availability zones",
- "potentialBenefits": "Enhanced private cloud connectivity",
- "tags": "AVS",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "c2794660-ffd7-4da3-96ba-5d546b70b1c6",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/configure-identity-source-vcenter",
- "name": "Set an external identity source for vCenter"
- }
- ],
- "recommendationControl": "Security",
- "longDescription": "Ensure two external identity sources are configured for NSX and vCenter Server. The VMware vCenter Server and NSX Manager use these for authentication with external identities.\n",
- "pgVerified": true,
- "description": "Integrate LDAPS Identity with dual sources for enhanced NSX and vCenter security",
- "potentialBenefits": "Continuous login access during maintenances",
- "tags": "AVS",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "bce16eee-0933-4baa-ab4d-8d1bb5653fc2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/configure-hcx-network-extension-high-availability",
- "name": "HCX Network extension high availability"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Enable Network Extension High Availability for appliance failure tolerance in HCX service. It pairs selected appliances for Active Standby configuration, ensuring high availability and quick recovery, keeping configurations in-service despite failures.\n",
- "pgVerified": true,
- "description": "Use HCX Network Extension High Availability",
- "potentialBenefits": "Improves HCX service continuity",
- "tags": "AVS",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "6be9a543-cf82-4926-82ea-7e1f1ffaad80",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://docs.vmware.com/en/VMware-HCX/4.8/hcx-user-guide/GUID-0C746416-850E-46F7-85DD-4D4326A23785.html",
- "name": "Requirements for Network Extension"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Do not extend the network used by the HCX Management devices to ensure the network's security and stability.\n",
- "pgVerified": true,
- "description": "Verify Management Networks are not extended with HCX Network Extension",
- "potentialBenefits": "Enhanced network safety and performance",
- "tags": "AVS",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "0943aa90-e3db-4c61-aef1-782b6a6a3881",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/azure-vmware/application-platform#use-fault-domains",
- "name": "Use fault domains"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "The Azure VMware Solution's service SLA is influenced by vSAN storage policies, which change based on cluster size. For clusters over 6 hosts, an FTT-2 policy (RAID-1 or RAID-6) is advised. FTT refers to the Fault Tolerance feature.\n",
- "pgVerified": true,
- "description": "Verify vSAN FTT configuration aligns with the cluster size",
- "potentialBenefits": "Enhanced cluster reliability",
- "tags": "AVS",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "6f573d60-be93-4f18-8016-42e923e3c05e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://azure.github.io/Azure-Proactive-Resiliency-Library/services/networking/expressroute-circuits",
- "name": "APRL guidance for ExpressRoute circuits"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Microsoft suggests using two or more ExpressRoute circuits at distinct peering locations for critical workloads. Connect these circuits and your Azure VMware Solutions private clouds using Global Reach.\n",
- "pgVerified": true,
- "description": "Align ExpressRoute configuration with best practices for circuit resilience",
- "potentialBenefits": "Enhanced circuit resilience for Azure VMware",
- "tags": "AVS",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "91c84596-1c41-48fe-8d5e-3f817e6a273b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/deploy-vsan-stretched-clusters#deploy-a-stretched-cluster-private-cloud",
- "name": "Deploy vSAN streched cluster"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Azure VMware Solution vSAN stretched clusters cover 2 Availability Zones plus a third for witness. Use ExpressRoute for added resilience by deploying two circuits in different locations. With Global Reach, create a mesh topology by connecting on-premises circuits to Azure's managed circuits.\n",
- "pgVerified": true,
- "description": "Deploy two or more circuits in different peering locations when using stretched clusters",
- "potentialBenefits": "Enhanced resilience and connectivity",
- "tags": "AVS",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "bdac462a-2eda-4a67-887d-46d58f141afe",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/azure-vmware/move-azure-vmware-solution-across-regions",
- "name": "Private Clouds in two regions"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Two Azure VMware Solution private clouds can be deployed in different regions for business continuity, implementing a mesh network topology based on ExpressRoute Gateway Connections and Global Reach Connections.\n",
- "pgVerified": true,
- "description": "Deploy dual Azure VMware Solution clouds in different regions for disaster recovery",
- "potentialBenefits": "Enhanced disaster recovery",
- "tags": "AVS",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// cannot-be-validated-with-arg\r\n"
- },
- {
- "aprlGuid": "4c78fab4-845a-495d-ab14-3ad51de53a2a",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/powershell/high-performance-computing/hpcpack-ha-cloud?view=hpc19-ps#hpc-pack-cluster-shares",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Currently in all HPC Pack ARM templates we create the cluster share on one of the head node which is not highly available.\n",
- "pgVerified": false,
- "description": "Ensure File shares that stores jobs metadata are accessible from all head nodes",
- "potentialBenefits": "Enhances job metadata availability",
- "tags": "HPC",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "b02b5a0e-3770-44da-a099-5dd4d9f8cd70",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/powershell/high-performance-computing/hpcpack-auto-grow-shrink?view=hpc19-ps",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "By deploying Azure \"burst\" nodes (both Windows and Linux) in your HPC Pack cluster or creating your HPC Pack cluster in Azure, you can automatically grow or shrink the cluster's resources such as nodes or cores according to the workload on the cluster.\n",
- "pgVerified": false,
- "description": "Automatically grow and shrink HPC Pack cluster resources",
- "potentialBenefits": "Efficient, uninterrupted execution",
- "tags": "HPC",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "a48b1be6-77a3-4e3c-8205-dda2ba010a99",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/powershell/high-performance-computing/hpcpack-ha-cloud?view=hpc19-ps#dealing-with-head-node-failure",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Establish a cluster with a minimum of two head nodes. In the event of a head node failure, the active HPC Service will be automatically transferred from the affected head node to another functioning one.\n",
- "pgVerified": false,
- "description": "Use multiple head nodes for HPC Pack",
- "potentialBenefits": "Enhanced reliability for HPC",
- "tags": "HPC",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "37eec891-7880-4759-b597-7cd925512fe3",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/powershell/high-performance-computing/hpcpack-ha-cloud?view=hpc19-ps#dealing-with-ad-failure",
- "name": "Learn More"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "When HPC failed to connect to the Domain controller, admin and user will not be able to connect to the HPC Service thus not able to manage and submit jobs to the cluster.\n",
- "pgVerified": false,
- "description": "Use HPC Pack Azure AD Integration or other highly available AD configuration",
- "potentialBenefits": "Enhanced reliability and job management",
- "tags": "HPC",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "a9b649a5-2bfe-40ca-9b8f-34f9c71dfa12",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/sap-high-availability-architecture-scenarios#high-availability-deployment-options-for-sap-workload",
- "name": "High Availability Deployment Options for SAP"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use Azure Availability Zones to protect SAP systems against data center failures. Ensure high availability by deploying across multiple zones. If deployment across zones isn't possible, refer to Microsoft's guidance for high availability options for SAP workloads.\n",
- "pgVerified": true,
- "description": "Ensure that each SAP production system is designed for high availability across availability zones",
- "potentialBenefits": "High availability for SAP systems",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "49bd34ab-d117-4b0e-99f8-34cc8a5394bc",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/virtual-machine-scale-set-sap-deployment-guide",
- "name": "Virtual machine Scale Set SAP Deployment Guide"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use VMSS Flex to distribute VMs across zones and fault domains. Follow Microsoft's SAP workload recommendations for settings. If not using VMSS Flex or Availability Sets, consider migrating to VMSS Flex for improved resiliency. Refer to the provided blog post for migration details.\n",
- "pgVerified": true,
- "description": "Run SAP application servers on two or more VMs using VMSS Flex",
- "potentialBenefits": "Enhanced resiliency for SAP on Azure",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "b60ae773-9917-4bca-8a42-7cb45365a917",
- "recommendationTypeId": "58d6648d-32e8-4346-827c-4f288dd8ca24",
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/planning-guide-storage",
- "name": "SAP Storage Planning Guide"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For single-instance VMs, both OS and data disks must be either Premium SSD or Ultra Disk to achieve the single-instance SLA of 99.9% availability.\n",
- "pgVerified": true,
- "description": "If using single-instance VMs all OS and data disks must be Premium SSD or Ultra Disk",
- "potentialBenefits": "Higher SLA of 99.9% with SSDs",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": true,
- "query": "// Azure Resource Graph Query\r\n// Find all single instance VMs that have an attached disk that is not in the Premium or Ultra sku tier.\r\n\r\nresources\r\n| where type =~ 'Microsoft.Compute/virtualMachines'\r\n| where isnull(properties.virtualMachineScaleSet.id)\r\n| where isnotnull(properties.availabilitySet)\r\n| extend lname = tolower(name)\r\n| join kind=leftouter(resources\r\n | where type =~ 'Microsoft.Compute/disks'\r\n | where not(sku.tier =~ 'Premium') and not(sku.tier =~ 'Ultra')\r\n | extend lname = tolower(tostring(split(managedBy, '/')[8]))\r\n | project lname, name\r\n | summarize disks = make_list(name) by lname) on lname\r\n| where isnotnull(disks)\r\n| project recommendationId = \"b60ae773-9917-4bca-8a42-7cb45365a917\", name, id, tags, param1=strcat(\"AffectedDisks: \", disks)\r\n"
- },
- {
- "aprlGuid": "094400a5-f112-408d-a334-afd68873ff0f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://github.com/Azure/SAP-on-Azure-Scripts-and-Utilities/tree/main/QualityCheck",
- "name": "OpenSource Quality Checks"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "High availability for databases should be implemented using database native replication technologies and the data should be replicated synchronously that is in SYNC mode from primary database to a stand-by node.\n",
- "pgVerified": true,
- "description": "Ensure synchronous data replication (SYNC mode) between primary and secondary VM nodes",
- "potentialBenefits": "Ensures high availability for SAP data",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "e09ca960-20b7-4831-b85b-83ec84c1390e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://aka.ms/ACESInventoryCheckSAP",
- "name": "OpenSource Inventory Checks"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "SAP shared file systems such as /sapmnt, /usr/trans, interfaces should be made highly available.\nIn case of Azure File Shares, we recommend that you use ZRS (Zone-redundant storage) and for Azure NetApp Files use Zonal replication for your volumes.\n",
- "pgVerified": true,
- "description": "Design SAP shared file systems for high availability, utilizing availability zones when possible",
- "potentialBenefits": "Enhanced data availability for SAP",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "5663a808-56be-49ea-8d5c-c5dfc6925f76",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/sap-hana-high-availability?tabs=lb-portal#test-the-cluster-setup",
- "name": "Test Cases"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Test high availability solutions thoroughly, including kernel panic in Linux VMs and fail-back. Ensure zonal failure scenarios for each SAP layer (database, central services, application servers, shared file systems) are zone redundant, meet RPO = 0, and fail over automatically within your RTO.\n",
- "pgVerified": true,
- "description": "Test high availability solutions thoroughly to ensure fail overs work as expected",
- "potentialBenefits": "Ensures SAP Azure's failover reliability",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "1b8a3051-dfd4-4780-bfb7-446296774029",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://aka.ms/ACESInventoryCheckSAP",
- "name": "OpenSource Inventory Checks"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Use the migrate command in a Linux Pacemaker cluster to create a temporary \"prefer\" location constraint, moving a resource to a specified node for maintenance or testing. This constraint is temporary and should be removed after the task to revert to the original cluster configuration.\n",
- "pgVerified": true,
- "description": "Remove unwanted location constraints from Linux Pacemaker clusters",
- "potentialBenefits": "Enhanced maintenance and failover handling",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "820b4c0c-8a74-442a-8ba7-b0cb840cd983",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/capacity-reservation-overview",
- "name": "Capacity Reservation"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Ensure compute resource availability for critical VM roles in a DR region using a warm standby approach or Azure's On-demand Capacity Reservation. Warm standby keeps VMs running in the DR region, while On-demand Capacity Reservation reserves compute capacity without running VMs.\n",
- "pgVerified": true,
- "description": "Secure compute resource capacity for critical VM roles in DR region",
- "potentialBenefits": "Guarantees DR region availability",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n\r\n"
- },
- {
- "aprlGuid": "fb8bdcee-d88f-408d-8572-a76a4aaa733b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows",
- "name": "SAP Disaster Recovery Guide"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Replicate production databases (ASYNC) to the DR location using the database vendor's replication technology.\n",
- "pgVerified": true,
- "description": "Replicate production databases to DR location (ASYNC) using the vendor's replication technology",
- "potentialBenefits": "Enhanced DR resilience",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "41f0d88e-7866-4444-aac4-ef5fee3e6874",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/center-sap-solutions/get-quality-checks-insights",
- "name": "SAP ACSS Insights"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "SAP components such as (A)SCS, application servers, WebDispatchers, etc are backed up to DR location using an appropriate backup tool or ASR.\n",
- "pgVerified": true,
- "description": "SAP components are backed up to DR location using an appropriate backup tool or ASR",
- "potentialBenefits": "Ensures SAP data safety and recovery",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "ee4dc309-00a1-49fe-92fa-1724baf5f103",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows",
- "name": "DR Guidance"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Implement robust monitoring and alerting for DR in SAP on Azure to cover its complex, multi-layer architecture. This is crucial for databases, services, applications, and shared systems.\n",
- "pgVerified": true,
- "description": "SAP shared files systems are replicated or backed up to DR location",
- "potentialBenefits": "Enhances SAP DR oversight",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "0fabc52e-cdbb-4acd-8626-c4c637061e2d",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows",
- "name": "DR Guidance"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Automate the build of disaster recovery (DR) infrastructure (or pre-deploy DR resources) and streamline SAP service recovery as much as possible.\n",
- "pgVerified": true,
- "description": "Automate DR infrastructure build or pre-deploy DR resources",
- "potentialBenefits": "Faster SAP recovery, reduced downtime",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "c300e949-528d-4ac9-889b-cacf8b4a6e90",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows",
- "name": "DR Guidance"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Document DR procedures for each SAP layer: database, central services, application servers, and shared file systems. Include configuration, failover mechanisms, and recovery steps. Test various failure scenarios to ensure the DR strategy meets RPO/RTO targets and provides seamless failover.\n",
- "pgVerified": true,
- "description": "Document and test DR procedure ensure it meets RPO and RTO targets",
- "potentialBenefits": "Ensures robust DR, meets RPO/RTO",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "c27134b7-6917-4852-8276-3dbef5c71578",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/disaster-recovery-sap-guide?tabs=windows",
- "name": "DR Guidance"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Implement robust monitoring and alerting for SAP on Azure, covering DR for databases, central services, applications, and shared file systems. Given SAP's complexity, a comprehensive monitoring strategy is crucial for effective DR replication and rapid issue response.\n",
- "pgVerified": true,
- "description": "Ensure there is a robust monitoring and alerting solution in place for the entire DR solution",
- "potentialBenefits": "Improved DR oversight and rapid issue response",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "6b589ce6-c847-4cee-af35-f6e8eb1cf983",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/virtual-machines/linux/scheduled-events",
- "name": "VM Scheduled Events"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Scheduled events notify about upcoming maintenance (e.g., reboot) to limit disruption. Configure for all critical Azure VMs. Use the azure-events-az resource agent in Pacemaker clusters to monitor and react to events like Reboot and Redeploy, ensuring high availability.\n",
- "pgVerified": true,
- "description": "Configure scheduled events notification",
- "potentialBenefits": "Proactive maintenance awareness",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "9d8f6678-694c-4da4-8384-415201f65194",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://docs.microsoft.com/en-us/azure/advisor/advisor-reference-reliability-recommendations",
- "name": "ASCS-Pacemaker - Central Server Instance"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For the ASCS-Pacemaker (Central Server Instance), ensure that the Pacemaker cluster configuration parameters are correctly set up for SAP ASCS high availability.\n",
- "pgVerified": true,
- "description": "Configure a Pacemaker cluster for SAP ASCS high availability",
- "potentialBenefits": "Enhances SAP ASCS uptime",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "5c2e52d0-25be-4b1c-833c-b98b5ef1a26b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://docs.microsoft.com/en-us/azure/advisor/advisor-reference-reliability-recommendations",
- "name": "ASCS-LB - Central Server Instance"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For the ASCS-LB (Central Server Instance), ensure that the load balancer is configured correctly for SAP ASCS high availability.\n",
- "pgVerified": true,
- "description": "Ensure the load balancer is configured correctly for SAP ASCS High availability",
- "potentialBenefits": "Enhanced HA for SAP ASCS",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "6648fe61-880d-4a96-8d2d-190a23d5580b",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://docs.microsoft.com/en-us/azure/advisor/advisor-reference-reliability-recommendations",
- "name": "DBHANA-Pacemaker - Database Instance"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For the DBHANA-Pacemaker (Database Instance), ensure that the Pacemaker cluster configuration parameters are correctly set up for SAP HANA database high availability.\n",
- "pgVerified": true,
- "description": "Ensure the Pacemaker cluster has been setup for SAP HANA DB high availability",
- "potentialBenefits": "Enhances SAP HANA DB uptime",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "2e4c2171-a83f-4238-a8e3-b51c90d86a99",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://docs.microsoft.com/en-us/azure/advisor/advisor-reference-reliability-recommendations",
- "name": "DBHANA-LB- Database Instance"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "For the DBHANA-LB (Database Instance), make sure the load balancer is configured correctly for SAP HANA database high availability.\n",
- "pgVerified": true,
- "description": "Ensure the load balancer is configured correctly for SAP HANA DB High availability",
- "potentialBenefits": "Enhanced DB availability",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "4884cada-b9c7-42d5-8153-3853e4a6f6c4",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/planning-guide-storage#azure-netapp-files",
- "name": "SAP on Azure NetApp Planning Guide"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Ensure high availability of SAP with Azure NetApp Files by setting proper timeout values to prevent disruptions. Review the documentation to confirm your configuration meets the recommended timeout values.\n",
- "pgVerified": true,
- "description": "Review SAP configuration for timeout values used with Azure NetApp Files",
- "potentialBenefits": "Improve resiliency and performance of SAP on Azure",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "697deb1d-d398-4989-9734-9e6c18f7e0ad",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/sap/workloads/high-availability-guide-suse-nfs-simple-mount?tabs=lb-portal%2Censa1",
- "name": "High-availability SAP NetWeaver with simple mount and NFS on SLES for SAP Applications VMs"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Ensure optimal disk types and configurations for data and log volumes, meeting IOPS and throughput requirements. Follow Microsoft's recommendations for disk caching, WriteAccelerator, stripe size, and Linux I/O Scheduler. Use SAP on Azure QualityCheck tool to identify deviations.\n",
- "pgVerified": true,
- "description": "Provision recommended storage configuration on database VMs",
- "potentialBenefits": "Improve reliability, performance and optimize costs",
- "tags": "SAP",
- "recommendationResourceType": "Microsoft.Subscription/subscriptions",
- "recommendationImpact": "High",
- "automationAvailable": false,
- "query": "// under-development\r\n\r\n"
- },
- {
- "aprlGuid": "8c0a0a4c-9e34-41af-9f6d-89d8dc00370e",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/simplify",
- "name": "RE:01 Simplicity and efficiency"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Design your workload to align with business objectives and avoid unnecessary complexity or overhead. Use a practical and balanced approach to make design decisions that deliver the desired results. Contain your design to the necessities to reduce inefficiencies and potential problems.\n",
- "pgVerified": true,
- "description": "RE:01 Design your workload to align with business objectives",
- "potentialBenefits": "Meet business requirements",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "74415e66-7baf-43f3-8def-164bc7b48215",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/identify-flows",
- "name": "RE:02 Critical flows"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Identify and rate user and system flows. Use a criticality scale based on your business requirements to prioritize the flows.\n",
- "pgVerified": true,
- "description": "RE:02 Identify and rate user and system flows",
- "potentialBenefits": "Align architecture with reliability goals",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "f5fbe3d4-7196-46b8-9b09-0e29e7cf43ac",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/failure-mode-analysis",
- "name": "RE:03 Failure mode analysis"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Use failure mode analysis (FMA) to identify and prioritize potential failures in your solution components. Perform FMA to help you assess the risk and effect of each failure mode. Determine how the workload responds and recovers.\n",
- "pgVerified": true,
- "description": "RE:03 Use failure mode analysis to identify and prioritize potential failures",
- "potentialBenefits": "Reduce risk of unpredicted behavior",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "2c41b97c-af27-47b5-aafb-81bbf95fe8ba",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/metrics",
- "name": "RE:04 Target metrics"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Define reliability and recovery targets for the components, the flows, and the overall solution. Use the defined targets to build the health model. The health model defines what healthy, degraded, and unhealthy states look like.\n",
- "pgVerified": true,
- "description": "RE:04 Define reliability and recovery targets",
- "potentialBenefits": "Communicate reliability expectations with stakeholders",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "e404ef3f-e427-4e43-a1df-09da987e744f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/redundancy",
- "name": "RE:05 Redundancy"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Add redundancy at different levels, especially for critical flows. Apply redundancy to the compute, data, network, and other infrastructure tiers in accordance with the identified reliability targets.\n",
- "pgVerified": true,
- "description": "RE:05 Design for redundancy",
- "potentialBenefits": "Optimize for resiliency",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "df93ae26-260e-408f-860c-42cd189f8bf8",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/en-us/azure/well-architected/reliability/highly-available-multi-region-design",
- "name": "RE:05 High-availability multi-region design"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "High availability is a foundational tenet of designing for reliability. A highly available architecture can help you avoid downtime as much as possible and recover efficiently if downtime does occur.\n",
- "pgVerified": true,
- "description": "RE:05 Design for multi-region high availability",
- "potentialBenefits": "Minimize downtime from regional outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "3d6adb0a-042f-47f7-a7ea-db2e360903d5",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/regions-availability-zones",
- "name": "Regions and availability zones"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "High availability is a foundational tenet of designing for reliability. A highly available architecture can help you avoid downtime as much as possible and recover efficiently if downtime does occur.\n",
- "pgVerified": true,
- "description": "RE:05 Design for high availability with availability zones",
- "potentialBenefits": "Minimize downtime from zonal outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "7f0b9ea3-0159-4ea7-b854-a4313fe76d7f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/partition-data",
- "name": "RE:06 Data partitioning"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Partitioning data improves scalability, reduces contention, and optimizes performance. Implement data partitioning to divide data by usage pattern.\n",
- "pgVerified": true,
- "description": "RE:06 Design for data partitioning",
- "potentialBenefits": "Improve data estate reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "340fe5c3-d599-448a-8e52-15e96771a3f0",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/scaling",
- "name": "RE:06 Scaling"
- }
- ],
- "recommendationControl": "Scalability",
- "longDescription": "Implement a timely and reliable scaling strategy at the application, data, and infrastructure levels.\n",
- "pgVerified": true,
- "description": "RE:06 Design for reliable scaling",
- "potentialBenefits": "Dynamically handle increased load",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "4e1094dd-2d85-4a1a-8ca8-1e6ea21206fb",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/background-jobs",
- "name": "RE:07 Background jobs"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Background jobs help minimize the load on the application UI, which improves availability and reduces interactive response time.\n",
- "pgVerified": true,
- "description": "RE:07 Use background jobs",
- "potentialBenefits": "Minimize application load",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "7b5008cf-1853-44c4-827d-bca091678c3f",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/self-preservation",
- "name": "RE:07 Self-preservation"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Strengthen the resiliency and recoverability of your workload by implementing self-preservation and self-healing measures. Self-healing capabilities help you avoid downtime by building in failure detection and automatic corrective actions to respond to different failure types.\n",
- "pgVerified": true,
- "description": "RE:07 Implement self-preservation and self-healing measures",
- "potentialBenefits": "Reduce the likelihood of outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "66ae4a5c-7f58-4293-bed8-5caa4f9f34e2",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/handle-transient-faults",
- "name": "RE:07 Transient faults"
- }
- ],
- "recommendationControl": "HighAvailability",
- "longDescription": "Build capabilities into the solution by using infrastructure-based reliability patterns and software-based design patterns to handle component failures and transient errors.\n",
- "pgVerified": true,
- "description": "RE:07 Handle transient faults",
- "potentialBenefits": "Reduce the likelihood of outages",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "7db74a6a-4062-46a8-a0cd-18684fb0ec08",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/testing-strategy",
- "name": "RE:08 Testing"
- }
- ],
- "recommendationControl": "OtherBestPractices",
- "longDescription": "Test resiliency and availability scenarios by applying the principles of chaos engineering in your test and production environments. Use testing to ensure that your graceful degradation implementation and scaling strategies are effective by performing active malfunction and simulated load testing.\n",
- "pgVerified": true,
- "description": "RE:08 Design a reliability testing strategy",
- "potentialBenefits": "Validate and optimize workload reliability",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "5f95df03-cae2-4761-90b7-7afd657ac124",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/disaster-recovery",
- "name": "RE:09 Disaster recovery"
- }
- ],
- "recommendationControl": "DisasterRecovery",
- "longDescription": "Implement structured, tested, and documented business continuity and disaster recovery (BCDR) plans that align with the recovery targets. Plans must cover all components and the system as a whole.\n",
- "pgVerified": true,
- "description": "RE:09 Implement business continuity and disaster recovery plan",
- "potentialBenefits": "Reliable disaster recovery",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- },
- {
- "aprlGuid": "90adebf7-bc90-4939-9aa8-119c46bee0fc",
- "recommendationTypeId": null,
- "recommendationMetadataState": "Active",
- "learnMoreLink": [
- {
- "url": "https://learn.microsoft.com/azure/well-architected/reliability/monitoring-alerting-strategy",
- "name": "RE:10 Monitoring and alerting"
- }
- ],
- "recommendationControl": "MonitoringAndAlerting",
- "longDescription": "Measure and publish the solution's health indicators. Continuously capture uptime and other reliability data from across the workload and also from individual components and key flows.\n",
- "pgVerified": true,
- "description": "RE:10 Design a reliable monitoring and alerting strategy",
- "potentialBenefits": "Observability into workload health",
- "tags": null,
- "recommendationResourceType": "Microsoft.Subscription/Subscriptions",
- "recommendationImpact": "Medium",
- "automationAvailable": false,
- "query": null
- }
-]