CCO Dashboards June 2020 Update (#99)
CCO Infrastructure Dashboard v8.0 CCO Governance Dashboard v2.0
114
README.md
|
@ -1,12 +1,11 @@
|
|||
|
||||
# Continuous Cloud Optimization Power BI Dashboards
|
||||
# Continuous Cloud Optimization Power BI Dashboards Project
|
||||
|
||||
## Content
|
||||
|
||||
- [Overview](README.md#overview)
|
||||
- [CCO Azure Governance Dashboard Governance Version 1.0](README.md#cco-azure-governance-dashboard-report-pages) ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- [CCO Azure Infrastructure Dashboard Version 7.1 updates](README.md#cco-azure-infrastructure-dashboard-version-71-updates)
|
||||
- [CCO Azure Infrastructure Dashboard Version 7.0 updates](README.md#cco-azure-infrastructure-dashboard-version-70-updates)
|
||||
- [CCO Azure Governance Dashboard Governance Version 2.0](README.md#cco-azure-governance-dashboard-report-pages) ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- [CCO Azure Infrastructure Dashboard Version 8.0](README.md#cco-azure-infrastructure-dashboard-version-80) ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- [List of resources](README.md#List-of-resources)
|
||||
- [CCO Azure Infrastructure Dashboard report pages](README.md#cco-azure-infrastructure-dashboard-report-pages)
|
||||
- [CCO Azure Infrastructure Dashboard with AKS add-on report pages](README.md#cco-azure-infrastructure-dashboard-with-aks-add-on-report-pages)
|
||||
|
@ -14,63 +13,94 @@
|
|||
|
||||
-------------------------------
|
||||
|
||||
|
||||
## Overview
|
||||
The Continuous Cloud Optimization Power BI Dashboards project is a set of Power BI Dashboards developed using Power Query M language and DAX, that pulls information directly from different Azure and Graph REST APIs and enables monitoring, operation and infrastructure teams to quickly gain insights about the existing Azure Platform footprint and resources.
|
||||
|
||||
The Continuous Cloud Optimization Power BI Dashboards project is a set of Power BI Desktop Reports developed using Power Query M language and DAX, that pulls information directly from different Azure REST APIs and enables monitoring, operation and infrastructure teams to quickly gain insights about the existing Azure Platform footprint and resources.
|
||||
The current set of CCO Dashboards includes 3 different Dashboards to discover information about different Azure critcal design areas:
|
||||
|
||||
- [**CCO Azure Infrastructure Dashboard**](/install/DeploymentGuide.md): Get insights about Azure Identity and RBAC, Security of your resoruces, Networking, Compute, Idle resources and Subcriptions Quotas and Limits
|
||||
- [**CCO Azure Governance Dashboard**](https://github.com/Azure/ccodashboard/blob/master/dashboards/CCODashboard-Governance/GovernanceDeploymentGuide.md): Get insights Azure Governance aspects like Management Groups and Subscriptions hierarchy, Azure Policies, Azure Blueprints and Azure resources Regulatory Standards Compliance
|
||||
- [**CCO Azure Infrastrucutre Dashboard with AKS**](/install/DeploymentGuide.md): Get all the insights from the infrastruture Dashboard plus AKS information
|
||||
|
||||
- [**CCO Azure Infrastructure Dashboard**](/dashboards/CCODashboard-Infra/InfraDeploymentGuide.md): Get insights about Azure advisor optimizations, Azure Security Center Alerts, Networking, Compute, RBAC, Idle resources and Subscriptions Quotas and Limits
|
||||
- [**CCO Azure Governance Dashboard**](/dashboards/CCODashboard-Governance/GovernanceDeploymentGuide.md): Get insights about Azure Governance aspects like Management Groups and Subscriptions hierarchy, resource tagging and naming standards, security controls, policies compliance, Regulatory Standards and Azure Blueprints
|
||||
- [**CCO Azure Infrastructure Dashboard with AKS**](/dashboards/CCODashboard-Infra/InfraDeploymentGuide.md): Get insights about AKS information
|
||||
|
||||
![OverviewImage](/install/images/OverviewImage.png)
|
||||
|
||||
## CCO Azure Governance Dashboard Version 2.0 Updates
|
||||
|
||||
- US Government region support <span style="color:green"><sup>NEW</sup></span>
|
||||
- Alignment with Azure Security Benchmarks and Azure Security Center Secure Scores
|
||||
- New Security & Compliance page <span style="color:green"><sup>NEW</sup></span>
|
||||
- New Regulatory Standards Forecast page <span style="color:green"><sup>NEW</sup></span>
|
||||
- Redesigned Azure Blueprints page
|
||||
- New UX design with latest Azure Portal Icons <span style="color:green"><sup>NEW</sup></span>
|
||||
- General Bug Fixes and code improvements
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 8.0 Updates**
|
||||
|
||||
- US Government and China Azure regions support <span style="color:green"><sup>NEW</sup></span>
|
||||
- Potential cost optimizations in Azure Advisor recommendations page <span style="color:green"><sup>NEW</sup></span>
|
||||
- Resource Tags page moved to the CCO Azure Governance dashboard.
|
||||
- Azure Security Recommendations moved to the CCO Azure Governance Dashboard as part of the Security & Compliance page content
|
||||
- All APIs calls updated to the last version.
|
||||
- New UX design with latest Azure Portal Icons <span style="color:green"><sup>NEW</sup></span>
|
||||
- General Bug Fixes and code improvements
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 7.1** Updates
|
||||
|
||||
- Bug fix [Issue #72](https://github.com/Azure/ccodashboard/issues/72):
|
||||
- Subscription IDs in **All Subscriptions** table must be uniques.
|
||||
- One tenant can be managed by one or more tenants (this data now is hidden but it will be used in future releases).
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 7.0** Updates
|
||||
|
||||
- **Multi tenant feature** ***<span style="color:green"><sup>NEW</sup></span>*** (requires Azure delegated resource management).
|
||||
- Tenant filtering in all pages.
|
||||
- Added subscription filtering in IaaS Usage and Limits and IaaS Idle Resources pages.
|
||||
|
||||
**IMPORTANT**: You must follow this [procedure](https://docs.microsoft.com/en-us/azure/lighthouse/how-to/onboard-customer) to implementent Azure delegated resource management.
|
||||
**IMPORTANT**: You must follow this [procedure](https://docs.microsoft.com/en-us/azure/lighthouse/how-to/onboard-customer) to implement Azure delegated resource management.
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 6.3** Updates
|
||||
|
||||
- Bug fixing ASC recommendation: Now all the Security Center Recommendations are defined in this [file](/docs/assets/SecRec.md). This file contains all the recommendations from docs.microsoft.com but will be updated by us for consolidating the model and avoid the issues when the official URL is updated.
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 6.2** Updates
|
||||
|
||||
- Bug fixing ASC recommendation URLs updated.
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 6.1** Updates
|
||||
|
||||
- Bug fixing ASC recommendation URLs updated.
|
||||
- Bug fixing IaaS Idle Resources data number color changed from black to white.
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 6.0** Updates
|
||||
|
||||
**Azure Resources Usage and Limits Page** ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
|
||||
- List Compute, Networking and Storage Azure Resources Usage and limits per subscription and region
|
||||
|
||||
**Azure Idle Resources identification Page** ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
|
||||
- List Idle Public IPs, Network Interfaces and Disks per Subscription
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 5.4** Updates
|
||||
|
||||
- NSGs bug fixing when NSGs configuration are empty
|
||||
- Bug fixing number of VNETs per subscription
|
||||
- Bug Fixing duplicated VNET Peerings count
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 5.3** Updates
|
||||
## **CCO Azure Infrastructure Dashboard Version 5.3** Updates
|
||||
|
||||
- Bug fixing issues with ASC Network Recommendations table load from docs.microsoft.com
|
||||
- Incorporating icons new feature from PowerBI Desktop
|
||||
|
||||
## **CCO Azure Infrastructure Dashboard Version 5.2:** New features and updates
|
||||
|
||||
**Overview Page**
|
||||
|
||||
- New Resource Groups tags counter
|
||||
- New Subscriptions, RG and Tags Search option
|
||||
|
||||
**Tags Overview** ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
|
||||
- Filter Resource Groups and Resources with Tags
|
||||
- Filter Resource Groups and Resources without Tags
|
||||
- Number of tagged resources by resource type
|
||||
|
@ -78,40 +108,48 @@ The current set of CCO Dashboards includes 3 different Dashboards to discover in
|
|||
- Search option for Resource Group and Resources tags
|
||||
|
||||
**Azure Advisor**
|
||||
|
||||
- Performance improvements and bugs fixes
|
||||
- Simplified recommendations images
|
||||
- Security recommendations
|
||||
|
||||
**Azure Security Center**
|
||||
|
||||
- Performance improvements and bugs fixes
|
||||
- Simplified recommendations images
|
||||
- Enhanced recommendation types filtering
|
||||
|
||||
**Security Alerts**
|
||||
|
||||
- Performance improvements and bugs fixes
|
||||
- Simplified recommendations images
|
||||
|
||||
**Compute**
|
||||
|
||||
- Performance improvements and bugs fixes
|
||||
|
||||
**Networking**
|
||||
|
||||
- Performance improvements and bugs fixes
|
||||
|
||||
**NSGs** ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
|
||||
- NSG rules overview across subscriptions (VMs and Subnets)
|
||||
- Filter NSGs by subscription, Resource Group, NSG name, Tags, Direction and Ports
|
||||
|
||||
**RBAC**
|
||||
|
||||
- Performance improvements and bugs fixes
|
||||
- Filtering RBAC permissions by object type (Users or Groups)
|
||||
- Search option for Resource Group and users
|
||||
|
||||
**RBAC Service Principals** ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
|
||||
- Filtering RBAC permissions by Service Principal Type
|
||||
- Search option for Users and Resource Groups
|
||||
|
||||
|
||||
## List of resources
|
||||
|
||||
This project includes the following resources:
|
||||
|
||||
1. **install folder**: Includes all the files required to successfully deploy the Dashboard in your environment. The [Deployment Guide](/install/DeploymentGuide.md) file contains a detailed guidance to install and setup your dashboard including the requirements, what REST APIs are in use, the resource providers that needs to be enabled or what tabs are included as part of the default Dashboard. The [Troubleshooting Guide](/install/TroubleshootingGuide.md) file contains guidance to solve potential issues that you might encounter during the Dashboard deployment. Errors like Power BI regional settings, or Privacy levels will be documented on this document.
|
||||
|
@ -121,21 +159,33 @@ This project includes the following resources:
|
|||
- ***CCODashboard folder*** has a more generic version of the Dashboard that includes information from Azure Advisor, Azure Security Center, Azure Networking REST APIs, Azure Compute REST APIs and Graph
|
||||
- ***CCODashboard-AKS folder*** has the add-on report to monitor Azure Kubernetes Services.
|
||||
|
||||
## CCO Azure Governance Dashboard Report Pages
|
||||
|
||||
The version 2.0 of the CCO Power BI Dashboard Governance includes the following information:
|
||||
|
||||
- Azure Management Groups and Subscriptions hierarchy
|
||||
- Resource Groups and Resources Tagging information
|
||||
- Regulatory Standards Compliance Overview ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- Azure Security and Compliance ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- Azure Policies
|
||||
- Azure Subscriptions Blueprints ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
|
||||
You can find more details about each page on the [Deployment Guide](https://github.com/Azure/ccodashboard/blob/master/dashboards/CCODashboard-Governance/GovernanceDeploymentGuide.md) file
|
||||
|
||||
## CCO Azure Infrastructure Dashboard report pages
|
||||
The version 7.1 of the CCO Power BI Dashboard includes 12 report pages. You will be able to navigate, filter and report the following information:
|
||||
|
||||
The version 8.0 of the CCO Power BI Dashboard includes 10 report pages. You will be able to navigate, filter and report the following information:
|
||||
|
||||
- Page 1: Overview
|
||||
- Page 2: Tags Overview
|
||||
- Page 3: Azure Advisor Recommendations
|
||||
- Page 4: Azure Security Center Task recommendations
|
||||
- Page 5: Azure Security Center Alerts
|
||||
- Page 6: Azure Compute information
|
||||
- Page 7: Azure Networking information
|
||||
- Page 8: Network Security Groups
|
||||
- Page 9: Azure RBAC permissions
|
||||
- Page 10: Azure Service Principals RBAC permissions
|
||||
- Page 11: IaaS Usage and Limits
|
||||
- Page 12: IaaS Idle Resources
|
||||
- Page 2: Azure Advisor Recommendations
|
||||
- Page 3: Azure Security Center Alerts
|
||||
- Page 4: Azure Compute information
|
||||
- Page 5 Azure Networking information
|
||||
- Page 6: Network Security Groups
|
||||
- Page 7: Azure RBAC permissions
|
||||
- Page 8: Azure Service Principals RBAC permissions
|
||||
- Page 9: IaaS Usage and Limits
|
||||
- Page 10: IaaS Idle Resources
|
||||
|
||||
You can find more details about each page on the [Deployment Guide](/install/DeploymentGuide.md) file
|
||||
|
||||
|
@ -151,20 +201,8 @@ The version 5.0 of the CCO Power BI Dashboard AKS add-on includes the following
|
|||
- Azure Container Intances information ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- Improved API Rest calls ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
|
||||
## CCO Azure Governance Dashboard Report Pages
|
||||
|
||||
The version 1.0 of the CCO Power BI Dashboard Governance includes the following information:
|
||||
|
||||
- Azure Management Groups and Subcriptions hierarchy ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- Resource Groups and Resources Tagging information
|
||||
- Azure Policies ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- Azure Subscriptions Blueprints ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- Regulatory Standards Compliance Overview ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
- Azure Resource Regulatory Standards Compliance ***<span style="color:green"><sup>NEW</sup></span>***
|
||||
|
||||
You can find more details about each page on the [Deployment Guide](https://github.com/Azure/ccodashboard/blob/master/dashboards/CCODashboard-Governance/GovernanceDeploymentGuide.md) file
|
||||
|
||||
## Call for contribution
|
||||
|
||||
This project welcomes contributions and suggestions. Most contributions require you to agree to a
|
||||
Contributor License Agreement (CLA) declaring that you have the right to, and actually do grant us
|
||||
the rights to use your contribution. For details, visit https://cla.microsoft.com.
|
||||
|
|
Двоичные данные
dashboards/CCODashboard-Governance/CCO Power BI Governance Dashboard v2.0.pbit
Normal file
|
@ -1,41 +1,44 @@
|
|||
# CCO Azure Governance Dashboard Governance Version 1.0
|
||||
# CCO Azure Governance Dashboard
|
||||
|
||||
<div style="text-align: justify">
|
||||
|
||||
- [CCO Azure Governance Dashboard Governance Version 1.0](#cco-azure-governance-dashboard-governance-version-10)
|
||||
- [CCO Azure Governance Dashboard](#cco-azure-governance-dashboard)
|
||||
- [Overview](#overview)
|
||||
- [Requirements](#requirements)
|
||||
- [APIs in use](#apis-in-use)
|
||||
- [Resource Providers requirements](#resource-providers-requirements)
|
||||
- [Installing the custom connector](#installing-the-custom-connector)
|
||||
- [Setting up the CCO Azure Governance Dashboard Governance](#setting-up-the-cco-azure-governance-dashboard-governance)
|
||||
- [Environment selection](#environment-selection)
|
||||
- [Credentials](#credentials)
|
||||
- [Clean Credentials on the Data Source](#clean-credentials-on-the-data-source)
|
||||
- [Refresh the dashboard](#refresh-the-dashboard)
|
||||
- [Credentials for <span>management.azure.com</span> REST API request:](#credentials-for-managementazurecom-rest-api-request)
|
||||
- [Credentials for <span>CCO Dashboard Custom Connector</span>:](#credentials-for-cco-dashboard-custom-connector)
|
||||
- [Credentials for management.azure.com</span> REST API request](#credentials-for-managementazurecomspan-rest-api-request)
|
||||
- [Credentials for CCO Dashboard Custom Connector](#credentials-for-cco-dashboard-custom-connector)
|
||||
- [Modify Privacy settings](#modify-privacy-settings)
|
||||
- [Report Pages](#report-pages)
|
||||
- [Management Groups and Subscriptions Hierarchy Overview page](#management-groups-and-subscriptions-hierarchy-overview-page)
|
||||
- [Tags and naming standards page](#tags-and-naming-standards-page)
|
||||
- [Azure Regulatory Standards Forecast](#azure-regulatory-standards-forecast)
|
||||
- [Azure Resources Security & Compliance page](#azure-resources-security--compliance-page)
|
||||
- [Azure Policies page](#azure-policies-page)
|
||||
- [Azure Subscription Blueprints page](#azure-subscription-blueprints-page)
|
||||
- [Azure Regulatory Compliance Overview tab](#azure-regulatory-compliance-overview-tab)
|
||||
- [Azure Resources Regulatory Compliance tab](#azure-resources-regulatory-compliance-tab)
|
||||
- [Azure Blueprints page](#azure-blueprints-page)
|
||||
|
||||
## Overview
|
||||
|
||||
The CCO Azure Governance Dashboard is aligned with the Microsoft Cloud Adoption Framework governance principles and will allow to get quick insights around Management Groups, Subscriptions, Blueprints, Polices, Naming Standards, Tagging and Regulatory Standards compliance. The information captured on this Power BI Dashboard can help Cloud Teams, Operations Teams or business decision makers to have a snapshot of the current Azure configuration in just few minutes.
|
||||
|
||||
### Requirements
|
||||
|
||||
- The CCO Azure Governance Dashboard is a Power BI Template that requires to download and install the Microsoft Power BI Desktop Edition from the Microsoft Store. Below you can find the minimum requirements to run the Dashboard
|
||||
- Windows 10 version **14393.0** or **higher**.
|
||||
- Internet access from the computer running Microsoft Power BI desktop.
|
||||
- An Azure account on the desired tenant space with permissions on the subscriptions to read from the Azure Services described above.
|
||||
- Install the custom connector and allow the use of any extension to load data without validation or warning.
|
||||
- Windows 10 version **14393.0** or **higher**.
|
||||
- Internet access from the computer running Microsoft Power BI desktop.
|
||||
- An Azure account on the desired tenant space with permissions on the subscriptions to read from the Azure Services described above.
|
||||
- Install the custom connector and allow the use of any extension to load data without validation or warning.
|
||||
|
||||
## APIs in use
|
||||
<div style="text-align: justify">
|
||||
The CCO Azure Governance Dashboard Governance pulls the information from several APIs. You can read the public documentation if you need further information about the calls and methods available:
|
||||
|
||||
<div style="text-align: justify">The CCO Azure Governance Dashboard Governance pulls the information from several APIs. You can read the public documentation if you need further information about the calls and methods available:
|
||||
<br><br>
|
||||
</div>
|
||||
|
||||
|
@ -43,16 +46,24 @@ The CCO Azure Governance Dashboard Governance pulls the information from several
|
|||
| --- | :---: | :---: |:---: |
|
||||
| [Resource Groups](https://docs.microsoft.com/en-us/rest/api/resources/resourcegroups) |2019-05-01 |2019-05-01|:heavy_check_mark:|
|
||||
| [Azure Resources](https://docs.microsoft.com/en-us/rest/api/resources/resources) |2019-05-01 |2019-05-01|:heavy_check_mark:|
|
||||
| [Azure Subscriptions](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions) |2019-05-01 |2019-05-01|:heavy_check_mark:|
|
||||
| [Azure Subscriptions](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions) |2020-01-01 |2020-01-01|:heavy_check_mark:|
|
||||
| [Azure Locations](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions/listlocations) |2019-05-01 |2019-05-01|:heavy_check_mark:|
|
||||
| [Azure Blueprints](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions/listlocations) |2018-11-01-preview |2018-11-01-preview|:heavy_check_mark:|
|
||||
| [Azure Policies](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions/listlocations) |2019-09-01 |2019-09-01|:heavy_check_mark:|
|
||||
| [Azure Regulatory Compliances](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions/listlocations) |2016-06-01 |2016-06-01|:heavy_check_mark:|
|
||||
|
||||
|
||||
| [Azure Regulatory Compliances](https://docs.microsoft.com/en-us/rest/api/securitycenter/regulatorycompliancestandards) |2019-01-01-preview |2019-01-01-preview|:heavy_check_mark:|
|
||||
| [Azure Assessments](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions/listlocations) |2020-01-01 |2020-01-01|:heavy_check_mark:|
|
||||
| [Azure Secure Scores](https://docs.microsoft.com/en-us/rest/api/securitycenter/securescores) |2020-01-01 |2020-01-01|:heavy_check_mark:|
|
||||
| [Azure Secure Scores Controls](https://docs.microsoft.com/en-us/rest/api/securitycenter/securescorecontrols) |2020-01-01-preview |2020-01-01-preview|:heavy_check_mark:|
|
||||
|
||||
<div style="text-align: justify">
|
||||
|
||||
API URLs by environment:
|
||||
|
||||
| API Name| API URL | Environment|
|
||||
|--- |--- |--- |
|
||||
| Management |https://management.azure.com/|Global|
|
||||
| Management |https://management.usgovcloudapi.net/|US Government|
|
||||
| Management |https://management.chinacloudapi.cn/|China|
|
||||
|
||||
## Resource Providers requirements
|
||||
|
||||
|
@ -67,77 +78,128 @@ Registering this Resource Provider has no cost or performance penalty on the sub
|
|||
|
||||
# Installing the custom connector
|
||||
|
||||
The new CCO Azure Governance Dashboard requires to install the Power BI Custom Connector that you will find in the same folder as the CCO Governance Dashboard ([CCoDashboardAzureConnector.mez]). This new Custom Connector allows us to leverage new information from Azure Management REST APIs required to put all the information together.
|
||||
The CCO Azure Governance Dashboard requires to install the Power BI Custom Connector located in the same folder as the CCO Governance Dashboard ([CCoDashboardAzureConnector.mez](/dashboards/CCODashboard-Governance/CcoDashboardAzureConnector.mez)). This Custom Connector allows us to leverage information from Azure Management REST APIs that requires POST methods and errors control
|
||||
|
||||
To install the custom connector you must copy the file [CCoDashboardAzureConnector.mez](https://github.com/josunefon/ccodashboard/blob/master/dashboards/CCODashboard-Governance/CcoDashboardAzureConnector.mez) from the **ccodashboard/dashboards/CCODashboard-Governance/** folder to the folder that Power BI creates by default in the Documents folder in your PC. If this folder doesn't exist, you can create a new one with this name.
|
||||
To install the custom connector you must copy the file [CCoDashboardAzureConnector.mez](/dashboards/CCODashboard-Governance/CcoDashboardAzureConnector.mez) from the **ccodashboard/dashboards/CCODashboard-Governance/** folder to the folder that Power BI creates by default in the Documents folder in your PC. If this folder doesn't exist, you can create a new one with this name.
|
||||
|
||||
The path should be **C:\Users\\%username%\Documents\Power BI Desktop\Custom Connectors**
|
||||
|
||||
![cc](/install/images/customconnectorfolder.PNG)
|
||||
|
||||
Then go to Power BI Options and under Global category in the Security section, select **(Not Recommended) Allow any extension to load without validation or warning** and click **OK**.
|
||||
Then go to Power BI Options and under Global category in the Security section, select **(Not Recommended) Allow any extension to load without validation or warning** and click **OK**.
|
||||
|
||||
![cc](/install/images/customconnectorsecurity.PNG)
|
||||
|
||||
# Setting up the CCO Azure Governance Dashboard Governance
|
||||
|
||||
## Environment selection
|
||||
|
||||
Before start loading data you need to select which type of environment you're using:
|
||||
|
||||
- Select "Global" for Microsoft Azure commercial environments. This is the default selection.
|
||||
- Select [US-Government](https://docs.microsoft.com/en-us/azure/azure-government/documentation-government-developer-guide) for Azure Us government services. Azure Government is a separate instance of the Microsoft Azure service. It addresses the security and compliance needs of United States federal agencies, state and local governments, and their solution providers.
|
||||
|
||||
![selector](/install/images/selectorGov.PNG)
|
||||
|
||||
## Credentials
|
||||
By default, the template doesn't have any Azure Account credentials preloaded. Hence, the first step to start showing subscriptions data is to sign-in with the right user credentials.
|
||||
|
||||
By default, the template doesn't have any Azure Account credentials preloaded. Hence, the first step to start loading subscriptions data is to sign-in with the right user credentials.
|
||||
|
||||
**IMPORTANT NOTE**: Power BI Desktop caches the credentials after the first logon. It is important to clear the credentials from Power BI desktop if you plan to switch between Azure GLobal and any other region like US Government or China. The same concept applies if you plan to switch between tenants. Otherwise, the staged credentials will be used again for the different Azure environments and the authentication or data load process will fail.
|
||||
|
||||
### Clean Credentials on the Data Source
|
||||
|
||||
In some cases, old credentials are cached by previous logins using Power BI Desktop and the dashboard might show errors or blank fields.
|
||||
|
||||
- Click on Data sources in **Current file/Global permissions**.
|
||||
- Click on Data sources in **Current file/Global permissions**
|
||||
- Click on **Clear Permissions**.
|
||||
- Click on **Clear All Permissions**.
|
||||
|
||||
![credentials1](/install/images/Credentials1.png) ![credentials2](/install/images/Credentials2.png)
|
||||
|
||||
### Refresh the dashboard
|
||||
|
||||
If the permissions and credentials are properly flushed it should ask you for credentials for each REST API and you will have to set the Privacy Levels for each of them.
|
||||
|
||||
- Click on **Refresh**.
|
||||
|
||||
![refreshgovernance](/install/images/refreshgovernance1.png)
|
||||
|
||||
### Credentials for <span>management.azure.com</span> REST API request:
|
||||
### Credentials for management.azure.com</span> REST API request
|
||||
|
||||
- Click on **Organizational Account**.
|
||||
- Click on **Sign in**.
|
||||
- Click on **Connect**.
|
||||
-
|
||||
|
||||
![credentials4](/install/images/Credentials4.png)
|
||||
|
||||
### Credentials for <span>CCO Dashboard Custom Connector</span>:
|
||||
### Credentials for CCO Dashboard Custom Connector
|
||||
|
||||
- Click on **Organizational Account**.
|
||||
- Click on **Sign in**.
|
||||
- Click on **Connect**.
|
||||
|
||||
![cc](/install/images/customconnector.PNG)
|
||||
|
||||
|
||||
### Modify Privacy settings
|
||||
|
||||
- Go to File -> Options -> Privacy and set to Always ignore privacy level settings.
|
||||
- Go to File -> Options -> Privacy and set to Always ignore privacy level settings.
|
||||
|
||||
![Privacy](https://user-images.githubusercontent.com/39730064/60920947-3e6d2580-a24e-11e9-9042-f799c9f6fc53.png)
|
||||
|
||||
# Report Pages
|
||||
|
||||
## Management Groups and Subscriptions Hierarchy Overview page
|
||||
|
||||
In this page, you will be able to identify easily the hierarchy within your environment with the view of the Management Groups and Subscriptions.
|
||||
It's important to mention that this page just gives you a quick view.
|
||||
It's important to mention that this page just gives you a quick view.
|
||||
|
||||
![overview](/install/images/GovernanceOverview.png)
|
||||
|
||||
## Tags and naming standards page
|
||||
|
||||
In this page you will be able to sort and filter all your Resources and Resource groups based on Tags. It will help you identify any missing Tag and if your naming standards and Tags classifications adheres to your organization guidelines or policies.
|
||||
|
||||
![Tagsoverview](/install/images/GovernanceTags.png)
|
||||
You can filter the information by:
|
||||
|
||||
- Management Group with subscriptions
|
||||
- Subscription
|
||||
|
||||
![Tagsoverview](/install/images/TagsOverview.png)
|
||||
|
||||
## Azure Regulatory Standards Forecast
|
||||
|
||||
In this page you can compare your current Azure resources compliance against selected Regulatory Standards, to understand how far from a given Regulatory Standard your current Azure footprint is today. For more information check the published [Regulatory Standards](https://docs.microsoft.com/en-us/azure/governance/blueprints/samples/).
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Subscription
|
||||
- Regulatory Compliance
|
||||
- Assessment Category
|
||||
|
||||
![regulatorycompliance](/install/images/regulatorycompliance.png)
|
||||
|
||||
## Azure Resources Security & Compliance page
|
||||
|
||||
In this page you can check the compliance status of your Azure resources based on the Azure Security Center Secure Score Controls and the corresponding Policy Set or Regulatory Standard.
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Subscription
|
||||
- Policy Set
|
||||
- Regulatory Standard Name
|
||||
- Secure Controls
|
||||
- Policy Category
|
||||
|
||||
![regulatorycomplianceresources](/install/images/regulatorycomplianceresources.png)
|
||||
|
||||
## Azure Policies page
|
||||
|
||||
In this page of the report, you will be able to identify the total amount of policies that are you applying in your environment. It will also give a high-level overview of which policies has less compliance level and which resources require more attention.
|
||||
|
||||
You can filter the information by:
|
||||
- Tenant
|
||||
- Management Group with subscriptions
|
||||
|
||||
- Management Group with subscriptions
|
||||
- Subscription
|
||||
- Policy scope
|
||||
|
||||
|
@ -145,40 +207,13 @@ If you navigate to a impacted resource you will see a quick description of the a
|
|||
|
||||
![policies](/install/images/governancePolicies.png)
|
||||
|
||||
## Azure Subscription Blueprints page
|
||||
## Azure Blueprints page
|
||||
|
||||
In this page of the report, you will be able to identify the total amount of blueprints that are you applying in your environment. It will also show which are the artifacts within the blueprints.
|
||||
|
||||
You can filter the information by:
|
||||
- Tenant
|
||||
- Management Group with subscriptions
|
||||
- Subscription
|
||||
|
||||
- Subscription with assigned blueprints
|
||||
- Blueprint Definition
|
||||
- Published blueprint
|
||||
- Blueprint Assignment
|
||||
|
||||
|
||||
![governanceSubsBlueprints](/install/images/governanceSubsBlueprints.png)
|
||||
|
||||
## Azure Regulatory Compliance Overview tab
|
||||
The fifth tab is used to show the Azure Regulatory Compliance controls level of the environment. It shows the status of the 4 built-in regulatory compliance controls that Azure applies by default to all the environments (SOC TSP, PCI-DSS-3.2, ISO 27001 and Azure CIS 1.1.0).
|
||||
|
||||
You can filter the information by:
|
||||
- Tenant
|
||||
- Management Group with subscriptions
|
||||
- Subscription
|
||||
- Resource Groups
|
||||
|
||||
![regulatorycompliance](/install/images/regulatorycompliance.png)
|
||||
|
||||
## Azure Resources Regulatory Compliance tab
|
||||
In this tab, you will be able to identify which resources are compliant with all the additional regulatory compliance controls. Also it shows how your environment complies with controls and requirements designated by specific regulatory standards and industry benchmarks and provides prescriptive recommendations for how to address these requirements.
|
||||
(Public preview release of additional supported standards: NIST SP 800-53 R4, SWIFT CSP CSCF v2020, Canada Federal PBMM and UK Official together with UK NHS).
|
||||
|
||||
You can filter the information by:
|
||||
- Tenant
|
||||
- Management Group with subscriptions
|
||||
- Subscription
|
||||
- Resource Groups
|
||||
- Regulatory Standard Name
|
||||
|
||||
![regulatorycomplianceresources](/install/images/regulatorycomplianceresources.png)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
# Continuous Cloud Optimization Power BI Dashboard
|
||||
# CCO Azure Infrastructure Dashboard
|
||||
|
||||
<div style="text-align: justify">
|
||||
|
||||
- [Continuous Cloud Optimization Power BI Dashboard](#continuous-cloud-optimization-power-bi-dashboard)
|
||||
- [CCO Azure Infrastructure Dashboard](#CCO-Azure-Infrastructure-Dashboard)
|
||||
- [Overview](#overview)
|
||||
- [Requirements](#requirements)
|
||||
- [APIs in use](#apis-in-use)
|
||||
|
@ -9,30 +10,30 @@
|
|||
- [Azure Advisor Recommendations](#azure-advisor-recommendations)
|
||||
- [Generating Azure Advisor recommendations manually](#generating-azure-advisor-recommendations-manually)
|
||||
- [Azure Security Center Recommendations](#azure-security-center-recommendations)
|
||||
- [Setting up the Continuous Optimization Power BI Dashboard](#setting-up-the-continuous-optimization-power-bi-dashboard)
|
||||
- [Setting up the Continuous Cloud Optimization Azure Infrastructure Power BI Dashboard](#setting-up-the-continuous-cloud-optimization-azure-infrastructure-power-bi-dashboard)
|
||||
- [Environment selection](#environment-selection)
|
||||
- [Credentials](#credentials)
|
||||
- [Clean Credentials on the Data Source](#clean-credentials-on-the-data-source)
|
||||
- [Refresh the dashboard](#refresh-the-dashboard)
|
||||
- [Credentials for <span>management.azure.com</span> REST API request:](#credentials-for-managementazurecom-rest-api-request)
|
||||
- [Credentials for <span>github.com</span> Web](#credentials-for-githubcom-web)
|
||||
- [Credentials for <span>graph.windows.net</span> API](#credentials-for-graphwindowsnet-api)
|
||||
- [Credentials for <span>api.loganalytics.io</span> API](#credentials-for-apiloganalyticsio-api)
|
||||
- [Credentials for management.azure.com</span> REST API request:](#credentials-for-managementazurecom-rest-api-request)
|
||||
- [Credentials for github.com</span> Web](#credentials-for-githubcom-web)
|
||||
- [Credentials for graph.windows.net</span> API](#credentials-for-graphwindowsnet-api)
|
||||
- [Credentials for api.loganalytics.io</span> API](#credentials-for-apiloganalyticsio-api)
|
||||
- [Enter Access Web content credentials](#enter-access-web-content-credentials)
|
||||
- [Modify Privacy settings](#modify-privacy-settings)
|
||||
- [Report Pages](#report-pages)
|
||||
- [CCO Dashboard overview page](#cco-dashboard-overview-page)
|
||||
- [Resource Tags overview page](#resource-tags-overview-page)
|
||||
- [CCO Azure Infrastructure Dashboard overview page](#cco-azure-infrastructure-dashboard-overview-page)
|
||||
- [Azure Advisor Recommendations Dashboard page](#azure-advisor-recommendations-dashboard-page)
|
||||
- [Azure Security Center Recommendations Dashboard page](#azure-security-center-recommendations-dashboard-page)
|
||||
- [Azure Security Center Alerts Dashboard tab](#azure-security-center-alerts-dashboard-tab)
|
||||
- [Azure VNETs and Subnets Recommendations Dashboard tab](#azure-vnets-and-subnets-recommendations-dashboard-tab)
|
||||
- [Azure Compute Dashboard tab](#azure-compute-dashboard-tab)
|
||||
- [Azure VNETs and Subnets Recommendations Dashboard tab](#azure-vnets-and-subnets-recommendations-dashboard-tab)
|
||||
- [Azure Network Security Groups Dashboard tab](#azure-network-security-groups-dashboard-tab)
|
||||
- [Role Based Access Control Dashboard tab](#role-based-access-control-dashboard-tab)
|
||||
- [Service Principal Role Based Access Control Dashboard tab](#service-principal-role-based-access-control-dashboard-tab)
|
||||
- [IaaS Usage and Limits Dashboard tab](#iaas-usage-and-limits-dashboard-tab)
|
||||
- [IaaS Idle Resources Dashboard tab](#iaas-idle-resources-dashboard-tab)
|
||||
- [Azure Kubernetes Service Dashboard Overview tab](#azure-kubernetes-service-dashboard-overview-tab)
|
||||
- [Azure Kubernetes Service Dashboard tab](#azure-kubernetes-service-dashboard-tab)
|
||||
- [Azure Kubernetes Service Dashboard tab](#azure-kubernetes-service-dashboard-tab)
|
||||
- [Scripts](#scripts)
|
||||
- [Generate All Subscriptions Advisor Recommendations](#generate-all-subscriptions-advisor-recommendations)
|
||||
- [PowerBI Dashboard Read Permissions Role](#powerbi-dashboard-read-permissions-role)
|
||||
|
@ -40,12 +41,12 @@
|
|||
- [PowerBI Dashboard Read Permissions Role (JSON)](#powerbi-dashboard-read-permissions-role-json)
|
||||
|
||||
## Overview
|
||||
The Continuous Cloud Optimization Power BI Dashboard is a report that aims to aggregate and consolidate the information generated by several Azure services to gain quick insights on your subscriptions to enable data driven business and technical optimization decisions. The main data sources for the Dashboard are the **Azure Advisor REST API**, **Azure Security Center REST API**, **Azure Graph REST API**, **Log Analytics API** and several **Azure IaaS REST APIs**.
|
||||
|
||||
The Continuous Cloud Optimization Azure Infrastructure Power BI Dashboard is a report that aims to aggregate and consolidate the information generated by several Azure services to gain quick insights on your subscriptions to enable data driven business and technical optimization decisions. The main data sources for this Azure Infrastructure Dashboard are the **Azure Advisor REST API**, **Azure Security Center REST API**, **Azure Graph REST API**, **Log Analytics API** and several **Azure IaaS REST APIs**.
|
||||
|
||||
### Requirements
|
||||
|
||||
- The Continuous Optimization Power BI Dashboard is a Power BI Template that requires to download and install the Microsoft Power BI Desktop Edition from the Microsoft Store. Below you can find the minimum requirements to run the Dashboard
|
||||
- The CCO Azure Infrastructure Dashboard is a Power BI Template that requires to download and install the Microsoft Power BI Desktop Edition from the Microsoft Store. Below you can find the minimum requirements to run the Dashboard
|
||||
- Windows 10 version **14393.0** or **higher**.
|
||||
- Internet access from the computer running Microsoft Power BI desktop.
|
||||
- An Azure account on the desired tenant space with permissions on the subscriptions to read from the Azure Services described above.
|
||||
|
@ -60,23 +61,22 @@ Below you can find the list of providers and the actions that you will need to p
|
|||
|
||||
## APIs in use
|
||||
<div style="text-align: justify">
|
||||
The Continuous Optimization Power BI Dashboard pulls the information from several APIs. You can read the public documentation if you need further information about the calls and methods available:
|
||||
The CCO Azure Infrastructure Dashboard pulls the information from several APIs. You can read the public documentation if you need further information about the calls and methods available:
|
||||
<br><br>
|
||||
</div>
|
||||
|
||||
| API Name| Dashboard API Version | Last API version | Using latest version|
|
||||
| --- | :---: | :---: |:---: |
|
||||
| [Azure Advisor](https://docs.microsoft.com/en-us/rest/api/advisor/) | 2017-04-19|2017-04-19|:heavy_check_mark:|
|
||||
| [Azure Advisor](https://docs.microsoft.com/en-us/rest/api/advisor/) | 2020-01-01|2020-01-01|:heavy_check_mark:|
|
||||
| [Azure Security Center Alerts](https://msdn.microsoft.com/en/US/library/mt704034(Azure.100).aspx) |2019-01-01 |2019-01-01|:heavy_check_mark:|
|
||||
| [Azure Security Center Tasks](https://msdn.microsoft.com/en/US/library/mt704034(Azure.100).aspx) |2015-06-01-preview |2015-06-01-preview|:heavy_check_mark:|
|
||||
| [Azure Kubernetes Service](https://docs.microsoft.com/en-us/rest/api/aks) | 2019-08-01|2019-08-01|:heavy_check_mark:|
|
||||
| [Azure Compute](https://docs.microsoft.com/en-us/rest/api/compute) | 2019-03-01|2019-03-01|:heavy_check_mark:|
|
||||
| [Azure Disks](https://docs.microsoft.com/en-us/rest/api/compute/disks/list) | 2019-03-01|2019-03-01|:heavy_check_mark:|
|
||||
| [Azure Virtual Networks](https://docs.microsoft.com/en-us/rest/api/virtual-network) | 2019-04-01|2019-04-01|:heavy_check_mark:|
|
||||
| [Azure Network Interfaces](https://docs.microsoft.com/en-us/rest/api/virtualnetwork/networkinterfaces) |2019-04-01 |2019-04-01|:heavy_check_mark:|
|
||||
| [Resource Groups](https://docs.microsoft.com/en-us/rest/api/resources/resourcegroups) |2019-05-01 |2019-05-01|:heavy_check_mark:|
|
||||
| [Azure Resources](https://docs.microsoft.com/en-us/rest/api/resources/resources) |2019-05-01 |2019-05-01|:heavy_check_mark:|
|
||||
| [Azure Subscriptions](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions) |2019-05-01 |2019-05-01|:heavy_check_mark:|
|
||||
| [Azure Resources](https://docs.microsoft.com/en-us/rest/api/resources/resources) |2019-10-01 |2019-10-01|:heavy_check_mark:|
|
||||
| [Azure Subscriptions](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions) |2020-01-01 |2020-01-01|:heavy_check_mark:|
|
||||
| [Azure Locations](https://docs.microsoft.com/en-us/rest/api/resources/subscriptions/listlocations) |2019-05-01 |2019-05-01|:heavy_check_mark:|
|
||||
| [Azure Role Assignments](https://docs.microsoft.com/en-us/rest/api/authorization/roleassignments) |2015-07-01 |2015-07-01|:heavy_check_mark:|
|
||||
| [Azure Role Definitions](https://docs.microsoft.com/en-us/rest/api/authorization/roledefinitions) |2015-07-01 |2015-07-01|:heavy_check_mark:|
|
||||
|
@ -86,6 +86,16 @@ The Continuous Optimization Power BI Dashboard pulls the information from severa
|
|||
|
||||
<div style="text-align: justify">
|
||||
|
||||
API URLs by environment:
|
||||
|
||||
| API Name| API URL | Environment|
|
||||
| --- | :---: | :---: |
|
||||
| Management |https://management.azure.com/|Global|
|
||||
| Azure AD Graph |https://graph.windows.net/|Global|
|
||||
| Management |https://management.usgovcloudapi.net/|US Government|
|
||||
| Azure AD Graph |https://graph.microsoft.us/|US Government|
|
||||
| Management |https://management.chinacloudapi.cn/|China|
|
||||
| Azure AD Graph |https://graph.chinacloudapi.cn/|China|
|
||||
|
||||
## Resource Providers requirements
|
||||
|
||||
|
@ -110,7 +120,9 @@ The Continuous Optimization Power BI Dashboard will directly pull data from Azur
|
|||
To do so, you need to generate the recommendations for the first time manually from the Azure Portal, or programmatically using the script [GenerateAllSubscriptionsAdvisorRecommendations.ps1](/scripts/GenerateAllSubsAdvisorRecommendations.ps1)
|
||||
|
||||
### Generating Azure Advisor recommendations manually
|
||||
Open the Azure Portal with your Azure Account http://portal.azure.com
|
||||
|
||||
Open the Azure Portal with your Azure Account http://portal.azure.com
|
||||
|
||||
1. Click on **Advisor**.
|
||||
2. Expand the subscriptions drop-down menu.
|
||||
3. Select the subscription you want to update or generate the recommendations for the first time.
|
||||
|
@ -120,17 +132,20 @@ Open the Azure Portal with your Azure Account http://portal.azure.com
|
|||
![AdvisorRecommendations](/install/images/AdvisorRecommendations.png)
|
||||
|
||||
## Azure Security Center Recommendations
|
||||
|
||||
Azure Security Center provides unified security management and advanced threat protection for workloads running in Azure, on-premises, and in other clouds. It delivers visibility and control over hybrid cloud workloads, active defence that reduces your exposure to threats, and intelligent detection to help you keep pace with rapidly evolving cyber-attacks.
|
||||
|
||||
You can find more information at the official Azure Security Center site [here](https://docs.microsoft.com/en-us/azure/security-center/security-center-intro).
|
||||
|
||||
Azure Security Center is offered in two tiers:
|
||||
|
||||
- Free
|
||||
- Standard
|
||||
|
||||
The Standard tier is offered [free for the first 60 days](https://azure.microsoft.com/en-us/pricing/details/security-center/).
|
||||
|
||||
The following picture shows the steps to configure Azure Security Center plan for Azure Subscriptions
|
||||
|
||||
1. Click on **Security Center**.
|
||||
2. Click on **Click on top to learn more**.
|
||||
3. Click on **Select the subscription you want to configure**.
|
||||
|
@ -138,11 +153,26 @@ The following picture shows the steps to configure Azure Security Center plan fo
|
|||
|
||||
![SecurityCenterStandardRecommendations](/install/images/EnableSecurityCenterStandard.png)
|
||||
|
||||
# Setting up the Continuous Optimization Power BI Dashboard
|
||||
# Setting up the Continuous Cloud Optimization Azure Infrastructure Power BI Dashboard
|
||||
|
||||
## Environment selection
|
||||
|
||||
Before start loading data you need to select which type of environment you're using:
|
||||
|
||||
- Select "Global" for Microsoft Azure commercial environments. This is the default selection.
|
||||
- Select [US-Government](https://docs.microsoft.com/en-us/azure/azure-government/documentation-government-developer-guide) for Azure Us government services. Azure Government is a separate instance of the Microsoft Azure service. It addresses the security and compliance needs of United States federal agencies, state and local governments, and their solution providers.
|
||||
- **Preview feature:** Select [China](https://docs.microsoft.com/en-us/azure/china/resources-developer-guide) to load data from cloud applications in Microsoft Azure operated by 21Vianet (Azure China).
|
||||
|
||||
![selector](/install/images/selector.png)
|
||||
|
||||
## Credentials
|
||||
|
||||
By default, the template doesn’t have any Azure Account credentials preloaded. Hence, the first step to start showing subscriptions data is to sign-in with the right user credentials.
|
||||
|
||||
**IMPORTANT NOTE**: Power BI Desktop caches the credentials after the first logon. It is important to clear the credentials from Power BI desktop if you plan to switch between Azure GLobal and any other region like US Government or China. The same concept applies if you plan to switch between tenants. Otherwise, the staged credentials will be used again for the different Azure environments and the authentication or data load process will fail.
|
||||
|
||||
### Clean Credentials on the Data Source
|
||||
|
||||
In some cases, old credentials are cached by previous logins using Power BI Desktop and the dashboard might show errors or blank fields.
|
||||
|
||||
- Click on Data sources in **Current file/Global permissions**.
|
||||
|
@ -152,6 +182,7 @@ In some cases, old credentials are cached by previous logins using Power BI Desk
|
|||
![credentials1](/install/images/Credentials1.png) ![credentials2](/install/images/Credentials2.png)
|
||||
|
||||
### Refresh the dashboard
|
||||
|
||||
If the permissions and credentials are properly flushed it should ask you for credentials for each REST API and you will have to set the Privacy Levels for each of them.
|
||||
|
||||
- Click on **Refresh**.
|
||||
|
@ -159,6 +190,7 @@ If the permissions and credentials are properly flushed it should ask you for cr
|
|||
![credentials3](/install/images/Credentials3.png)
|
||||
|
||||
### Credentials for <span>management.azure.com</span> REST API request:
|
||||
|
||||
- Click on **Organizational Account**.
|
||||
- Click on **Sign in**.
|
||||
- Click on **Connect**.
|
||||
|
@ -166,14 +198,8 @@ If the permissions and credentials are properly flushed it should ask you for cr
|
|||
|
||||
![credentials4](/install/images/Credentials4.png)
|
||||
|
||||
### Credentials for <span>github.com</span> Web
|
||||
- Click on **Anonymous**.
|
||||
- Click on **Sign in**.
|
||||
- Click on **Connect**.
|
||||
|
||||
![DocsCredentials](/install/images/DocsCredentials.png)
|
||||
|
||||
### Credentials for <span>graph.windows.net</span> API
|
||||
|
||||
- Click on **Organizational Account**.
|
||||
- Click on **Sign in**.
|
||||
- Click on **Connect**.
|
||||
|
@ -181,6 +207,7 @@ If the permissions and credentials are properly flushed it should ask you for cr
|
|||
![credentials5](/install/images/Credentials5.png)
|
||||
|
||||
### Credentials for <span>api.loganalytics.io</span> API
|
||||
|
||||
- Click on **Organizational Account**.
|
||||
- Click on **Sign in**.
|
||||
- Click on **Connect**.
|
||||
|
@ -196,31 +223,34 @@ If the permissions and credentials are properly flushed it should ask you for cr
|
|||
|
||||
### Modify Privacy settings
|
||||
|
||||
- Go to File -> Options -> Privacy and set to Always ignore privacy level settings.
|
||||
- Go to File -> Options -> Privacy and set to Always ignore privacy level settings.
|
||||
|
||||
![Privacy](https://user-images.githubusercontent.com/39730064/60920947-3e6d2580-a24e-11e9-9042-f799c9f6fc53.png)
|
||||
|
||||
# Report Pages
|
||||
## CCO Dashboard overview page
|
||||
In this page, you will be able to identify the top 5 of recommendations that Azure Advisor and Azure Security Center has identified. You can also locate all the deployed resources in a map.
|
||||
|
||||
## CCO Azure Infrastructure Dashboard overview page
|
||||
|
||||
In this page, you will be able to identify the top 5 of recommendations that Azure Advisor has identified, the top 10 most attacked resources and the number of subscription owners. You can also locate all the deployed resources in a map.
|
||||
It’s important to mention that this tab just gives you a quick view. All the recommendations will be available with more details in the following tabs
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Resource Tags
|
||||
|
||||
![overview](/install/images/OverviewImage.png)
|
||||
|
||||
## Resource Tags overview page
|
||||
In this page you will be able to sort and filter all your Resources and Resource groups based on Tags. It will help you identify any missing Tag and if your naming standards and Tags classifications adheres to your organization guidelines or policies.
|
||||
## Azure Advisor Recommendations page
|
||||
|
||||
![Tagsoverview](/install/images/TagsOverview.png)
|
||||
|
||||
## Azure Advisor Recommendations Dashboard page
|
||||
In this page of the report, you will be able to identify the total amount of recommendations that Azure Advisor has identified, to what resources each recommendations apply and to what subscription as well.
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Resource Group
|
||||
- Resource type
|
||||
- Recommendation type
|
||||
- Tags
|
||||
|
||||
It will also give a high-level overview of what subscriptions require more attention and has more recommendations to snooze or implement.
|
||||
|
||||
|
@ -228,35 +258,39 @@ If you navigate to a impacted resource you will see a quick description, potenti
|
|||
|
||||
![advisor](/install/images/Advisor.png)
|
||||
|
||||
## Azure Security Center Recommendations Dashboard page
|
||||
In this page, you will be able to identify the total amount of recommendations that Azure Security Center has detected, to what resources apply each recommendation and to what subscription is impacting.
|
||||
## Azure Security Center Alerts page
|
||||
|
||||
The third tab is used to show the Azure Security Center Advanced Threat Analytics Alerts from all the subscriptions a given Azure account has access to. Is important to remark that subscriptions will need to use the Standard plan if you want to detect and see the alerts in the Power BI Dashboard.
|
||||
|
||||
You can filter the information by:
|
||||
- Subscription
|
||||
- Resource Group
|
||||
- Task State
|
||||
- Resource Type
|
||||
- Tags
|
||||
|
||||
It will also give a high-level overview of what subscriptions require more attention and has more recommendations to snooze or implement.
|
||||
|
||||
![SecurityCenterRecommendations](/install/images/SecurityCenterRecommendations.png)
|
||||
|
||||
## Azure Security Center Alerts Dashboard tab
|
||||
The fourth tab is used to show the Azure Security Center Advanced Threat Analytics Alerts from all the subscriptions a given Azure account has access to. Is important to remark that subscriptions will need to use the Standard plan if you want to detect and see the alerts in the Power BI Dashboard.
|
||||
|
||||
You can filter the information by:
|
||||
- Data range
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Attack type
|
||||
- Tags
|
||||
|
||||
- Data range
|
||||
|
||||
![security Center alerts](/install/images/SecurityCenterAlerts.png)
|
||||
|
||||
## Azure VNETs and Subnets Recommendations Dashboard tab
|
||||
## Azure Compute Overview page
|
||||
|
||||
In this tab, you will be able to identify the number of VMs, the Operating System, the SKU, the Availability Set name, the location, the VM Size, the VNET and subnet each VM is connected, the private IP address and if the VM has any extension installed.
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Resource Group
|
||||
- Vm extension
|
||||
|
||||
![azurecompute](/install/images/AzureCompute.png)
|
||||
|
||||
## Azure VNETs and Subnets Recommendations page
|
||||
|
||||
In this tab, you will be able to identify VNETs with only one subnet, if there are any VNET peering and if some of the subnets is exhausting its IP Pool.
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Resource Group
|
||||
- VNET
|
||||
|
@ -267,70 +301,90 @@ You can filter the information by:
|
|||
|
||||
**IMPORTANT**: It is important to mention that although a VNET with only one subnet might not be an issue, it might be a good lead to investigate if that is the best network segmentation for the applications running on it.
|
||||
|
||||
## Azure Compute Dashboard tab
|
||||
In this tab, you will be able to identify the number of VMs, the Operating System, the SKU, the Availability Set name, the location, the VM Size, the VNET and subnet each VM is connected, the private IP address and if the VM has any extension installed.
|
||||
## Azure Network Security Groups page
|
||||
|
||||
In this tab, you will be able to identify all the NSGs assigned to a VM or Subnet. On each one, you can check all the rules that are being applied
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Resource Group
|
||||
- If the VM contains containers or no
|
||||
- Vm extension
|
||||
- VM
|
||||
- VNET
|
||||
- Subnet
|
||||
- NSG assignment
|
||||
|
||||
![azure NSGs](/install/images/NSGs.png)
|
||||
|
||||
![azurecompute](/install/images/AzureCompute.png)
|
||||
## Role Based Access Control page
|
||||
|
||||
## Role Based Access Control Dashboard tab
|
||||
This tab is used to show the Azure RBAC permissions from all the subscriptions a given Azure account has access to. You will be able to identify the roles applied to all Azure resources and if the subscriptions have custom roles.
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Resource type
|
||||
- Object type
|
||||
- User
|
||||
|
||||
![azure rbac](/install/images/RBAC.png)
|
||||
|
||||
## Service Principal Role Based Access Control Dashboard tab
|
||||
This tab is used to show Azure Services Principals RBAC permissions from all the subscriptions a given Azure account has access to. You will be able to identify the roles applied to all Azure resources and if the subscriptions have custom roles.
|
||||
## Service Principal Role Based Access Control page
|
||||
|
||||
This tab is used to show Azure Services Principals RBAC permissions from all the subscriptions a given Azure account has access to. You will be able to identify the roles applied to all Azure resources and if the subscriptions have custom roles.
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Resource type
|
||||
- Object type
|
||||
- User
|
||||
|
||||
![azure rbacSP](/install/images/RBACServicePrincipals.png)
|
||||
|
||||
## IaaS Usage and Limits Dashboard tab
|
||||
This tab allows to identify the usage of any Compute, Storage and Networking Azure resource and validate the limits for each region and subscription
|
||||
## IaaS Usage and Limits page
|
||||
|
||||
This tab allows to identify the usage of any Compute, Storage and Networking Azure resource and validate the limits for each region and subscription.
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
- Azure Region
|
||||
|
||||
![azure Idle](/install/images/UsageAndLimits.png)
|
||||
|
||||
## IaaS Idle Resources Dashboard tab
|
||||
## IaaS Idle Resources Dashboard page
|
||||
|
||||
This tab is lists all the Public IPs, Network Interfaces and Disks that are disconnected, idle or unattached.
|
||||
|
||||
You can filter the information by:
|
||||
- Subscription
|
||||
|
||||
- Tenant
|
||||
- Subscription
|
||||
|
||||
![azure Idle](/install/images/IdleResources.png)
|
||||
|
||||
## Azure Kubernetes Service Dashboard Overview tab
|
||||
## Azure Kubernetes Service Dashboard Overview page
|
||||
|
||||
In this page, you will be able to identify the number of AKS Clusters, Nodes, Pods, Containers, Service Principals and Azure Security Center recommedations. It’s important to mention that this tab just gives you a quick view. All the detailed information will be available in the following tab.
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Subscription
|
||||
- AKS Cluster
|
||||
|
||||
|
||||
![aks](/install/images/aks.PNG)
|
||||
|
||||
**IMPORTANT**: to receive all the information related to the Pods, Containers and Container Images a log analytics workspace configured **is required**.
|
||||
</div>
|
||||
|
||||
## Azure Kubernetes Service Dashboard tab
|
||||
## Azure Kubernetes Service page
|
||||
|
||||
In this page, you will be able to identify the number of AKS Clusters, Nodes, Pods, Containers, Container images, Service principals and Azure Container Instances . All the information related to these resources will be shown (IPs, pods in use, status, network, image repositories, RBAC roles …).
|
||||
|
||||
You can filter the information by:
|
||||
|
||||
- Subscription
|
||||
- AKS Cluster
|
||||
- Namespace
|
||||
|
@ -344,6 +398,7 @@ You can filter the information by:
|
|||
# Scripts
|
||||
|
||||
## Generate All Subscriptions Advisor Recommendations
|
||||
|
||||
```
|
||||
Login-AzureRmAccount
|
||||
|
||||
|
@ -408,6 +463,7 @@ Write-Output $result
|
|||
```
|
||||
|
||||
## PowerBI Dashboard Read Permissions Role
|
||||
|
||||
```
|
||||
Login-AzureRmAccount
|
||||
|
||||
|
@ -436,7 +492,9 @@ $role.AssignableScopes.Add("/subscriptions/$temp")
|
|||
|
||||
New-AzureRmRoleDefinition -Role $role
|
||||
```
|
||||
|
||||
## Check last Azure API version
|
||||
|
||||
```
|
||||
Login-AzureRmAccount
|
||||
Get-AzureRmSubscription | Out-GridView -PassThru
|
||||
|
@ -482,6 +540,7 @@ $providers | %{
|
|||
}
|
||||
}
|
||||
```
|
||||
|
||||
## PowerBI Dashboard Read Permissions Role (JSON)
|
||||
|
||||
```
|
|
@ -0,0 +1,43 @@
|
|||
| Resource Type| URL|
|
||||
| --- | :---: |
|
||||
|microsoft.alertsmanagement||
|
||||
|Microsoft.ApiManagement||
|
||||
|Microsoft.Automation||
|
||||
|Microsoft.BotService||
|
||||
|Microsoft.ClassicStorage||
|
||||
|Microsoft.CognitiveServices||
|
||||
|Microsoft.Compute||
|
||||
|Microsoft.ContainerInstance||
|
||||
|Microsoft.ContainerRegistry||
|
||||
|Microsoft.ContainerService||
|
||||
|Microsoft.CustomProviders||
|
||||
|Microsoft.DataFactory||
|
||||
|Microsoft.DesktopVirtualization||
|
||||
|Microsoft.Devices||
|
||||
|Microsoft.DevTestLab||
|
||||
|Microsoft.DocumentDb||
|
||||
|Microsoft.EventGrid||
|
||||
|Microsoft.EventHub||
|
||||
|Microsoft.HybridCompute||
|
||||
|microsoft.insights||
|
||||
|Microsoft.KeyVault||
|
||||
|Microsoft.Kusto||
|
||||
|Microsoft.Logic||
|
||||
|Microsoft.ManagedIdentity||
|
||||
|Microsoft.Migrate||
|
||||
|Microsoft.Network||
|
||||
|microsoft.offazure||
|
||||
|Microsoft.OperationalInsights||
|
||||
|Microsoft.OperationsManagement||
|
||||
|Microsoft.Portal||
|
||||
|Microsoft.RecoveryServices||
|
||||
|Microsoft.ResourceGraph||
|
||||
|Microsoft.Search||
|
||||
|Microsoft.Security||
|
||||
|Microsoft.ServiceBus||
|
||||
|Microsoft.SignalRService||
|
||||
|Microsoft.sql||
|
||||
|Microsoft.SqlVirtualMachine||
|
||||
|Microsoft.Storage||
|
||||
|Microsoft.Web||
|
||||
|Sendgrid.Email||
|
Двоичные данные
install/images/Advisor.png
До Ширина: | Высота: | Размер: 144 KiB После Ширина: | Высота: | Размер: 415 KiB |
Двоичные данные
install/images/AzureCompute.png
До Ширина: | Высота: | Размер: 238 KiB После Ширина: | Высота: | Размер: 335 KiB |
Двоичные данные
install/images/AzureNetworking.png
До Ширина: | Высота: | Размер: 354 KiB После Ширина: | Высота: | Размер: 401 KiB |
Двоичные данные
install/images/IdleResources.png
До Ширина: | Высота: | Размер: 136 KiB После Ширина: | Высота: | Размер: 300 KiB |
Двоичные данные
install/images/NSGs.png
До Ширина: | Высота: | Размер: 111 KiB После Ширина: | Высота: | Размер: 298 KiB |
Двоичные данные
install/images/OverviewImage.png
До Ширина: | Высота: | Размер: 775 KiB После Ширина: | Высота: | Размер: 386 KiB |
Двоичные данные
install/images/RBAC.png
До Ширина: | Высота: | Размер: 122 KiB После Ширина: | Высота: | Размер: 308 KiB |
Двоичные данные
install/images/RBACServicePrincipals.png
До Ширина: | Высота: | Размер: 108 KiB После Ширина: | Высота: | Размер: 331 KiB |
Двоичные данные
install/images/SecurityCenterAlerts.png
До Ширина: | Высота: | Размер: 140 KiB После Ширина: | Высота: | Размер: 323 KiB |
После Ширина: | Высота: | Размер: 188 KiB |
Двоичные данные
install/images/TagsOverview.png
До Ширина: | Высота: | Размер: 176 KiB После Ширина: | Высота: | Размер: 338 KiB |
Двоичные данные
install/images/UsageAndLimits.png
До Ширина: | Высота: | Размер: 291 KiB После Ширина: | Высота: | Размер: 464 KiB |
Двоичные данные
install/images/governancePolicies.png
До Ширина: | Высота: | Размер: 504 KiB После Ширина: | Высота: | Размер: 222 KiB |
Двоичные данные
install/images/governanceSubsBlueprints.png
До Ширина: | Высота: | Размер: 389 KiB После Ширина: | Высота: | Размер: 671 KiB |
Двоичные данные
install/images/regulatorycompliance.png
До Ширина: | Высота: | Размер: 290 KiB После Ширина: | Высота: | Размер: 206 KiB |
Двоичные данные
install/images/regulatorycomplianceresources.png
До Ширина: | Высота: | Размер: 438 KiB После Ширина: | Высота: | Размер: 718 KiB |
После Ширина: | Высота: | Размер: 28 KiB |
После Ширина: | Высота: | Размер: 27 KiB |
627
queries/AKS.m
|
@ -1,3 +1,49 @@
|
|||
// ListVirtualMachines
|
||||
let ListVirtualMachines = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Compute/virtualMachines?api-version=2017-12-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"properties", "resources", "type", "location", "tags", "id", "name"}, {"properties", "resources", "type", "location", "tags", "id", "name"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"id", "VM Resource Id"}, {"name", "VM Name"}}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Renamed Columns", "properties", {"vmId", "availabilitySet", "hardwareProfile", "storageProfile", "osProfile", "networkProfile", "provisioningState", "diagnosticsProfile"}, {"vmId", "availabilitySet", "hardwareProfile", "storageProfile", "osProfile", "networkProfile", "provisioningState", "diagnosticsProfile"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded properties",{"vmId"}),
|
||||
#"Expanded availabilitySet" = Table.ExpandRecordColumn(#"Removed Columns", "availabilitySet", {"id"}, {"id"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded availabilitySet",{{"id", "Availability Set Id"}}),
|
||||
#"Expanded hardwareProfile" = Table.ExpandRecordColumn(#"Renamed Columns1", "hardwareProfile", {"vmSize"}, {"vmSize"}),
|
||||
#"Expanded storageProfile" = Table.ExpandRecordColumn(#"Expanded hardwareProfile", "storageProfile", {"imageReference", "osDisk", "dataDisks"}, {"imageReference", "osDisk", "dataDisks"}),
|
||||
#"Expanded imageReference" = Table.ExpandRecordColumn(#"Expanded storageProfile", "imageReference", {"publisher", "offer", "sku", "version"}, {"publisher", "offer", "sku", "version"}),
|
||||
#"Expanded osDisk" = Table.ExpandRecordColumn(#"Expanded imageReference", "osDisk", {"osType", "name", "createOption", "vhd", "caching", "diskSizeGB", "managedDisk"}, {"osType", "name", "createOption", "vhd", "caching", "diskSizeGB", "managedDisk"}),
|
||||
#"Expanded vhd" = Table.ExpandRecordColumn(#"Expanded osDisk", "vhd", {"uri"}, {"uri"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Expanded vhd",{{"uri", "vhd uri"}}),
|
||||
#"Expanded managedDisk" = Table.ExpandRecordColumn(#"Renamed Columns2", "managedDisk", {"storageAccountType", "id"}, {"storageAccountType", "id"}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Expanded managedDisk",{{"id", "Managed Disk Id"}}),
|
||||
#"Expanded dataDisks" = Table.ExpandListColumn(#"Renamed Columns3", "dataDisks"),
|
||||
#"Expanded dataDisks1" = Table.ExpandRecordColumn(#"Expanded dataDisks", "dataDisks", {"lun", "name", "createOption", "vhd", "caching", "diskSizeGB"}, {"lun", "name.1", "createOption.1", "vhd", "caching.1", "diskSizeGB.1"}),
|
||||
#"Expanded vhd1" = Table.ExpandRecordColumn(#"Expanded dataDisks1", "vhd", {"uri"}, {"uri"}),
|
||||
#"Renamed Columns4" = Table.RenameColumns(#"Expanded vhd1",{{"uri", "Data vhd uri"}}),
|
||||
#"Expanded osProfile" = Table.ExpandRecordColumn(#"Renamed Columns4", "osProfile", {"computerName", "adminUsername", "linuxConfiguration", "secrets", "windowsConfiguration"}, {"computerName", "adminUsername", "linuxConfiguration", "secrets", "windowsConfiguration"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded osProfile",{"linuxConfiguration", "secrets"}),
|
||||
#"Expanded windowsConfiguration" = Table.ExpandRecordColumn(#"Removed Columns1", "windowsConfiguration", {"provisionVMAgent", "enableAutomaticUpdates"}, {"provisionVMAgent", "enableAutomaticUpdates"}),
|
||||
#"Expanded networkProfile" = Table.ExpandRecordColumn(#"Expanded windowsConfiguration", "networkProfile", {"networkInterfaces"}, {"networkInterfaces"}),
|
||||
#"Expanded networkInterfaces" = Table.ExpandListColumn(#"Expanded networkProfile", "networkInterfaces"),
|
||||
#"Expanded networkInterfaces1" = Table.ExpandRecordColumn(#"Expanded networkInterfaces", "networkInterfaces", {"id"}, {"id"}),
|
||||
#"Renamed Columns5" = Table.RenameColumns(#"Expanded networkInterfaces1",{{"id", "Network Inteface Id"}}),
|
||||
#"Expanded diagnosticsProfile" = Table.ExpandRecordColumn(#"Renamed Columns5", "diagnosticsProfile", {"bootDiagnostics"}, {"bootDiagnostics"}),
|
||||
#"Expanded bootDiagnostics" = Table.ExpandRecordColumn(#"Expanded diagnosticsProfile", "bootDiagnostics", {"enabled", "storageUri"}, {"enabled", "storageUri"}),
|
||||
#"Expanded resources" = Table.ExpandListColumn(#"Expanded bootDiagnostics", "resources"),
|
||||
#"Expanded resources1" = Table.ExpandRecordColumn(#"Expanded resources", "resources", {"id"}, {"id"}),
|
||||
#"Renamed Columns6" = Table.RenameColumns(#"Expanded resources1",{{"id", "Extensions Resource Id"}}),
|
||||
#"Expanded tags" = Table.ExpandRecordColumn(#"Renamed Columns6", "tags", {"creationSource", "orchestrator", "poolName", "resourceNameSuffix"}, {"creationSource", "orchestrator", "poolName", "resourceNameSuffix"})
|
||||
in
|
||||
#"Expanded tags"
|
||||
|
||||
in
|
||||
ListVirtualMachines
|
||||
|
||||
// TenantName
|
||||
"microsoft.com" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]
|
||||
|
||||
// AKS Clusters
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
|
@ -8,7 +54,8 @@ let
|
|||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "AKSClusters", each ListAKS([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"AKSClusters"}),
|
||||
#"Expanded AKSClusters" = Table.ExpandTableColumn(#"Removed Errors", "AKSClusters", {"id", "location", "name", "type", "provisioningState", "kubernetesVersion", "dnsPrefix", "fqdn", "name.1", "count", "vmSize", "storageProfile", "maxPods", "osType", "vnetSubnetID", "servicePrincipalProfile.clientId", "addonProfiles.omsagent.enabled", "logAnalyticsWorkspaceResourceID", "nodeResourceGroup", "enableRBAC", "AKS Cluster Id", "clientId", "enabled", "config", "enabled.1", "networkPlugin", "serviceCidr", "dnsServiceIP", "dockerBridgeCidr"}, {"id", "location", "name", "type", "provisioningState", "kubernetesVersion", "dnsPrefix", "fqdn", "name.1", "count", "vmSize", "storageProfile", "maxPods", "osType", "vnetSubnetID", "servicePrincipalProfile.clientId", "addonProfiles.omsagent.enabled", "logAnalyticsWorkspaceResourceID", "nodeResourceGroup", "enableRBAC", "AKS Cluster Id", "clientId", "enabled", "config", "enabled.1", "networkPlugin", "serviceCidr", "dnsServiceIP", "dockerBridgeCidr"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded AKSClusters",{"SubscriptionId", "Subscription Name"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Expanded AKSClusters", {"id"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Removed Duplicates",{"SubscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"name.1", "Agent Pool Name"}}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Renamed Columns1", "ClusterImage", each if [AKS Cluster Id] = "ClusterImage" then "" else "https://azure.github.io/ccodashboard/assets/pictures/000_AKS_ContainersLogo.svg"),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Added Conditional Column",{{"name", "Cluster Name"}}),
|
||||
|
@ -205,6 +252,335 @@ in
|
|||
in
|
||||
ListContainerImageInventory
|
||||
|
||||
// ListACS
|
||||
let ListResourceGroups= (subscriptionId as text) =>
|
||||
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.ContainerService/containerServices?api-version=2017-01-31")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
|
||||
in
|
||||
#"Converted to Table"
|
||||
|
||||
in
|
||||
#"ListResourceGroups"
|
||||
|
||||
// ACI
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List ACI" = Table.AddColumn(#"Renamed Columns", "ListACI", each ListACI([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List ACI", {"ListACI"}),
|
||||
#"Expanded ListACI" = Table.ExpandTableColumn(#"Removed Errors", "ListACI", {"id", "location", "name", "type", "properties"}, {"id", "location", "name", "type", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded ListACI", "properties", {"provisioningState", "containers", "restartPolicy", "ipAddress", "osType"}, {"provisioningState", "containers", "restartPolicy", "ipAddress", "osType"}),
|
||||
#"Expanded containers" = Table.ExpandListColumn(#"Expanded properties", "containers"),
|
||||
#"Expanded containers1" = Table.ExpandRecordColumn(#"Expanded containers", "containers", {"name", "properties"}, {"name.1", "properties"}),
|
||||
#"Expanded properties1" = Table.ExpandRecordColumn(#"Expanded containers1", "properties", {"image", "ports", "environmentVariables", "resources"}, {"image", "ports", "environmentVariables", "resources"}),
|
||||
#"Expanded ports" = Table.ExpandListColumn(#"Expanded properties1", "ports"),
|
||||
#"Expanded ports1" = Table.ExpandRecordColumn(#"Expanded ports", "ports", {"port"}, {"port"}),
|
||||
#"Expanded environmentVariables" = Table.ExpandListColumn(#"Expanded ports1", "environmentVariables"),
|
||||
#"Expanded resources" = Table.ExpandRecordColumn(#"Expanded environmentVariables", "resources", {"requests"}, {"requests"}),
|
||||
#"Expanded requests" = Table.ExpandRecordColumn(#"Expanded resources", "requests", {"memoryInGB", "cpu"}, {"memoryInGB", "cpu"}),
|
||||
#"Expanded ipAddress" = Table.ExpandRecordColumn(#"Expanded requests", "ipAddress", {"ip", "type"}, {"ip", "type.1"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded ipAddress", "id", "id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "id", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"id.1", "id.2", "id.3", "id.4", "id.5", "id.6", "id.7", "id.8", "id.9"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"id.1", type text}, {"id.2", type text}, {"id.3", type text}, {"id.4", type text}, {"id.5", type text}, {"id.6", type text}, {"id.7", type text}, {"id.8", type text}, {"id.9", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"id.1", "id.2", "id.3", "id.4"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"id.5", "Resource Group Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"id.6", "id.7", "id.8", "id.9"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Removed Columns1",{{"id - Copy", "Id"}, {"Column1.displayName", "Subscription Name"}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Renamed Columns2",{"SubscriptionId", "Subscription Name"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns2", {"Resource Group Name"})
|
||||
in
|
||||
#"Removed Duplicates"
|
||||
|
||||
// ListACI
|
||||
let ListResourceGroups= (subscriptionId as text) =>
|
||||
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.ContainerInstance/containerGroups?api-version=2018-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "location", "name", "type", "properties"}, {"id", "location", "name", "type", "properties"})
|
||||
in
|
||||
#"Expanded Column1"
|
||||
|
||||
in
|
||||
#"ListResourceGroups"
|
||||
|
||||
// ListRegistry
|
||||
let ListResourceGroups= (subscriptionId as text) =>
|
||||
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.ContainerRegistry/registries?api-version=2017-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
|
||||
in
|
||||
#"Converted to Table"
|
||||
|
||||
in
|
||||
#"ListResourceGroups"
|
||||
|
||||
// ACR
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List Registry" = Table.AddColumn(#"Renamed Columns", "ListRegistry", each ListRegistry([SubscriptionId])),
|
||||
#"Expanded ListRegistry" = Table.ExpandTableColumn(#"List Registry", "ListRegistry", {"Column1"}, {"Column1"}),
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Expanded ListRegistry", "Column1", {"sku", "type", "id", "name", "location", "tags", "properties"}, {"sku", "type", "id", "name", "location", "tags", "properties"}),
|
||||
#"Expanded sku" = Table.ExpandRecordColumn(#"Expanded Column2", "sku", {"name", "tier"}, {"sku.name", "sku.tier"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded sku",{"tags"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Removed Columns", "properties", {"loginServer", "creationDate", "provisioningState", "adminUserEnabled", "storageAccount"}, {"loginServer", "creationDate", "provisioningState", "adminUserEnabled", "storageAccount"}),
|
||||
#"Expanded storageAccount" = Table.ExpandRecordColumn(#"Expanded properties", "storageAccount", {"id"}, {"id.1"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded storageAccount",{{"Column1.displayName", "Subscription Name"}}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Renamed Columns1", each [type] <> null and [type] <> ""),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Filtered Rows",{"SubscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Removed Columns1",{{"loginServer", "Registry login Server"}})
|
||||
in
|
||||
#"Renamed Columns2"
|
||||
|
||||
// Resources
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListResources", each ListResources([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListResources"}),
|
||||
#"Expanded ListResources" = Table.ExpandTableColumn(#"Removed Errors", "ListResources", {"Resource Id", "Resource Name", "Resource Type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1", "name", "tier", "capacity", "size", "family", "kind", "name.1", "promotionCode", "product", "publisher", "managedBy", "Resource Group Id"}, {"Resource Id", "Resource Name", "Resource Type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1", "name", "tier", "capacity", "size", "family", "kind", "name.1", "promotionCode", "product", "publisher", "managedBy", "Resource Group Id"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Expanded ListResources", each true),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Filtered Rows", "Container Type", each if Text.Contains([Resource Type], "containerGroups") then "ACI" else if Text.Contains([Resource Type], "managedClusters") then "AKS" else if Text.Contains([Resource Type], "containerServices") then "ACS" else null),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Added Conditional Column", "Resource Group Id", "Resource Group Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Group Id - Copy", Splitter.SplitTextByDelimiter("/resourceGroups/", QuoteStyle.Csv), {"Resource Group Id - Copy.1", "Resource Group Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Group Id - Copy.1", type text}, {"Resource Group Id - Copy.2", type text}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Changed Type",{"Resource Group Id - Copy.1"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns1",{{"Resource Group Id - Copy.2", "Resource Group Name"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// ListResources
|
||||
let ListResources = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/resources?api-version=2017-05-10")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "location", "tags", "sku", "kind", "plan", "managedBy"}, {"id", "name", "type", "location", "tags", "sku", "kind", "plan", "managedBy"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"id", "Resource Id"}, {"name", "Resource Name"}, {"type", "Resource Type"}}),
|
||||
#"Expanded tags" = Table.ExpandRecordColumn(#"Renamed Columns", "tags", {"creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroups/WebappforcontainersCedwards/providers/Microsoft.Web/serverfarms/ServicePlanb8fd2fe5-b45f", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGroups/WebAppRG/providers/Microsoft.Web/serverfarms/cedwardWebApp1"}, {"creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1"}),
|
||||
#"Expanded sku" = Table.ExpandRecordColumn(#"Expanded tags", "sku", {"name", "tier", "capacity", "size", "family"}, {"name", "tier", "capacity", "size", "family"}),
|
||||
#"Expanded plan" = Table.ExpandRecordColumn(#"Expanded sku", "plan", {"name", "promotionCode", "product", "publisher"}, {"name.1", "promotionCode", "product", "publisher"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded plan", "Resource Id", "Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Id - Copy", Splitter.SplitTextByDelimiter("/providers", QuoteStyle.Csv), {"Resource Id - Copy.1", "Resource Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Id - Copy.1", type text}, {"Resource Id - Copy.2", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"Resource Id - Copy.2"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"Resource Id - Copy.1", "Resource Group Id"}})
|
||||
in
|
||||
#"Renamed Columns1"in
|
||||
ListResources
|
||||
|
||||
// ListVirtualNetworks
|
||||
let ListVirtualNetworks = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Network/virtualNetworks?api-version=2017-09-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"name", "id", "etag", "type", "location", "properties", "tags"}, {"name", "id", "etag", "type", "location", "properties", "tags"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"name", "VNET Name"}, {"id", "VNET Id"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns",{"etag"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Removed Columns", "properties", {"provisioningState", "resourceGuid", "addressSpace", "subnets", "virtualNetworkPeerings", "enableDdosProtection", "enableVmProtection", "dhcpOptions"}, {"provisioningState", "resourceGuid", "addressSpace", "subnets", "virtualNetworkPeerings", "enableDdosProtection", "enableVmProtection", "dhcpOptions"}),
|
||||
#"Expanded addressSpace" = Table.ExpandRecordColumn(#"Expanded properties", "addressSpace", {"addressPrefixes"}, {"addressPrefixes"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded addressSpace", {"addressPrefixes", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded subnets" = Table.ExpandListColumn(#"Extracted Values", "subnets"),
|
||||
#"Expanded subnets1" = Table.ExpandRecordColumn(#"Expanded subnets", "subnets", {"name", "id", "properties"}, {"name", "id", "properties"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded subnets1",{{"name", "Subnet Name"}, {"id", "Subnet Id"}}),
|
||||
#"Expanded properties1" = Table.ExpandRecordColumn(#"Renamed Columns1", "properties", {"provisioningState", "addressPrefix", "ipConfigurations", "serviceEndpoints", "routeTable"}, {"provisioningState.1", "addressPrefix", "ipConfigurations", "serviceEndpoints", "routeTable"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded properties1",{"provisioningState.1"}),
|
||||
#"Expanded ipConfigurations" = Table.ExpandListColumn(#"Removed Columns1", "ipConfigurations"),
|
||||
#"Expanded ipConfigurations1" = Table.ExpandRecordColumn(#"Expanded ipConfigurations", "ipConfigurations", {"id"}, {"id"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Expanded ipConfigurations1",{{"id", "IP Configuration Id"}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns2", "VNET Id", "VNET Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "VNET Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"VNET Id - Copy.1", "VNET Id - Copy.2", "VNET Id - Copy.3", "VNET Id - Copy.4", "VNET Id - Copy.5", "VNET Id - Copy.6", "VNET Id - Copy.7", "VNET Id - Copy.8", "VNET Id - Copy.9"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"VNET Id - Copy.1", type text}, {"VNET Id - Copy.2", type text}, {"VNET Id - Copy.3", type text}, {"VNET Id - Copy.4", type text}, {"VNET Id - Copy.5", type text}, {"VNET Id - Copy.6", type text}, {"VNET Id - Copy.7", type text}, {"VNET Id - Copy.8", type text}, {"VNET Id - Copy.9", type text}}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Changed Type",{{"VNET Id - Copy.3", "Subscription Id"}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Renamed Columns3",{"VNET Id - Copy.1", "VNET Id - Copy.2"}),
|
||||
#"Renamed Columns4" = Table.RenameColumns(#"Removed Columns2",{{"VNET Id - Copy.5", "Resource Group"}}),
|
||||
#"Removed Columns3" = Table.RemoveColumns(#"Renamed Columns4",{"VNET Id - Copy.4", "VNET Id - Copy.6", "VNET Id - Copy.7", "VNET Id - Copy.8", "VNET Id - Copy.9"}),
|
||||
#"Expanded virtualNetworkPeerings" = Table.ExpandListColumn(#"Removed Columns3", "virtualNetworkPeerings"),
|
||||
#"Expanded virtualNetworkPeerings1" = Table.ExpandRecordColumn(#"Expanded virtualNetworkPeerings", "virtualNetworkPeerings", {"name", "id", "etag", "properties"}, {"name", "id", "etag", "properties"}),
|
||||
#"Renamed Columns5" = Table.RenameColumns(#"Expanded virtualNetworkPeerings1",{{"id", "VNET Peering Id"}, {"name", "VNET Peering Name"}}),
|
||||
#"Removed Columns4" = Table.RemoveColumns(#"Renamed Columns5",{"etag"}),
|
||||
#"Expanded properties2" = Table.ExpandRecordColumn(#"Removed Columns4", "properties", {"provisioningState", "peeringState", "remoteVirtualNetwork", "allowVirtualNetworkAccess", "allowForwardedTraffic", "allowGatewayTransit", "useRemoteGateways", "remoteAddressSpace"}, {"provisioningState.1", "peeringState", "remoteVirtualNetwork", "allowVirtualNetworkAccess", "allowForwardedTraffic", "allowGatewayTransit", "useRemoteGateways", "remoteAddressSpace"}),
|
||||
#"Removed Columns5" = Table.RemoveColumns(#"Expanded properties2",{"provisioningState.1"}),
|
||||
#"Renamed Columns6" = Table.RenameColumns(#"Removed Columns5",{{"peeringState", "VNET peeringState"}}),
|
||||
#"Expanded remoteVirtualNetwork" = Table.ExpandRecordColumn(#"Renamed Columns6", "remoteVirtualNetwork", {"id"}, {"id"}),
|
||||
#"Renamed Columns7" = Table.RenameColumns(#"Expanded remoteVirtualNetwork",{{"id", "Remote VNET Id"}}),
|
||||
#"Expanded remoteAddressSpace" = Table.ExpandRecordColumn(#"Renamed Columns7", "remoteAddressSpace", {"addressPrefixes"}, {"addressPrefixes.1"}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Expanded remoteAddressSpace", {"addressPrefixes.1", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Replaced Errors" = Table.ReplaceErrorValues(#"Extracted Values1", {{"addressPrefixes.1", "Null"}}),
|
||||
#"Removed Columns6" = Table.RemoveColumns(#"Replaced Errors",{"tags"}),
|
||||
#"Expanded dhcpOptions" = Table.ExpandRecordColumn(#"Removed Columns6", "dhcpOptions", {"dnsServers"}, {"dnsServers"}),
|
||||
#"Extracted Values2" = Table.TransformColumns(#"Expanded dhcpOptions", {"dnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Replaced Errors1" = Table.ReplaceErrorValues(#"Extracted Values2", {{"dnsServers", "Null"}}),
|
||||
#"Removed Columns7" = Table.RemoveColumns(#"Replaced Errors1",{"type"}),
|
||||
#"Renamed Columns8" = Table.RenameColumns(#"Removed Columns7",{{"addressPrefixes", "VNET addressPrefixes"}, {"addressPrefix", "Subnet addressPrefix"}}),
|
||||
#"Expanded routeTable" = Table.ExpandRecordColumn(#"Renamed Columns8", "routeTable", {"id"}, {"id"}),
|
||||
#"Renamed Columns9" = Table.RenameColumns(#"Expanded routeTable",{{"id", "Route Table id"}, {"addressPrefixes.1", "Remote VNET addressPrefixes"}})
|
||||
in
|
||||
#"Renamed Columns9"
|
||||
in
|
||||
ListVirtualNetworks
|
||||
|
||||
// ListAllNICs
|
||||
let ListAllNICs = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Network/networkInterfaces?api-version=2017-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"name", "id", "etag", "location", "properties", "type"}, {"name", "id", "etag", "location", "properties", "type"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column1",{"etag"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Removed Columns", "properties", {"provisioningState", "resourceGuid", "ipConfigurations", "dnsSettings", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "networkSecurityGroup", "primary", "virtualMachine"}, {"provisioningState", "resourceGuid", "ipConfigurations", "dnsSettings", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "networkSecurityGroup", "primary", "virtualMachine"}),
|
||||
#"Expanded dnsSettings" = Table.ExpandRecordColumn(#"Expanded properties", "dnsSettings", {"dnsServers", "appliedDnsServers"}, {"dnsServers", "appliedDnsServers"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded dnsSettings", {"dnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Extracted Values", {"appliedDnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded networkSecurityGroup" = Table.ExpandRecordColumn(#"Extracted Values1", "networkSecurityGroup", {"id"}, {"id.1"}),
|
||||
#"Expanded virtualMachine" = Table.ExpandRecordColumn(#"Expanded networkSecurityGroup", "virtualMachine", {"id"}, {"id.2"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded virtualMachine",{"ipConfigurations"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns1",{{"id.1", "NSG Id"}, {"id.2", "Virtual Machine Id"}, {"id", "NIC Id"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
in
|
||||
ListAllNICs
|
||||
|
||||
// ListAllNICsDetails
|
||||
let ListAllNICsDetails = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Network/networkInterfaces?api-version=2017-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"name", "id", "etag", "location", "properties", "type"}, {"name", "id", "etag", "location", "properties", "type"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column1",{"etag"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Removed Columns", "properties", {"provisioningState", "resourceGuid", "ipConfigurations", "dnsSettings", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "networkSecurityGroup", "primary", "virtualMachine"}, {"provisioningState", "resourceGuid", "ipConfigurations", "dnsSettings", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "networkSecurityGroup", "primary", "virtualMachine"}),
|
||||
#"Expanded dnsSettings" = Table.ExpandRecordColumn(#"Expanded properties", "dnsSettings", {"dnsServers", "appliedDnsServers"}, {"dnsServers", "appliedDnsServers"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded dnsSettings", {"dnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Extracted Values", {"appliedDnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded networkSecurityGroup" = Table.ExpandRecordColumn(#"Extracted Values1", "networkSecurityGroup", {"id"}, {"id.1"}),
|
||||
#"Expanded virtualMachine" = Table.ExpandRecordColumn(#"Expanded networkSecurityGroup", "virtualMachine", {"id"}, {"id.2"}),
|
||||
#"Expanded ipConfigurations" = Table.ExpandListColumn(#"Expanded virtualMachine", "ipConfigurations"),
|
||||
#"Expanded ipConfigurations1" = Table.ExpandRecordColumn(#"Expanded ipConfigurations", "ipConfigurations", {"name", "id", "etag", "properties"}, {"name.1", "id.3", "etag", "properties"}),
|
||||
#"Expanded properties1" = Table.ExpandRecordColumn(#"Expanded ipConfigurations1", "properties", {"provisioningState", "privateIPAddress", "privateIPAllocationMethod", "publicIPAddress", "subnet", "primary", "privateIPAddressVersion", "isInUseWithService", "loadBalancerBackendAddressPools"}, {"provisioningState.1", "privateIPAddress", "privateIPAllocationMethod", "publicIPAddress", "subnet", "primary.1", "privateIPAddressVersion", "isInUseWithService", "loadBalancerBackendAddressPools"}),
|
||||
#"Expanded publicIPAddress" = Table.ExpandRecordColumn(#"Expanded properties1", "publicIPAddress", {"id"}, {"id.4"}),
|
||||
#"Expanded subnet" = Table.ExpandRecordColumn(#"Expanded publicIPAddress", "subnet", {"id"}, {"id.5"}),
|
||||
#"Expanded loadBalancerBackendAddressPools" = Table.ExpandListColumn(#"Expanded subnet", "loadBalancerBackendAddressPools"),
|
||||
#"Expanded loadBalancerBackendAddressPools1" = Table.ExpandRecordColumn(#"Expanded loadBalancerBackendAddressPools", "loadBalancerBackendAddressPools", {"id"}, {"id.6"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded loadBalancerBackendAddressPools1",{{"id.4", "Public IP Address ID"}, {"id.5", "Subnet Id"}, {"id.1", "NSG Id"}, {"id.2", "Virtual Machine Id"}, {"id", "NIC Id"}, {"name", "NIC Name"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
in
|
||||
ListAllNICsDetails
|
||||
|
||||
// Public IPs
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListPublicIPs", each ListPublicIPs([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListPublicIPs"}),
|
||||
#"Expanded ListPublicIPs" = Table.ExpandTableColumn(#"Removed Errors", "ListPublicIPs", {"Public IP Name", "Public IP Resource Id", "location", "provisioningState", "resourceGuid", "ipAddress", "publicIPAddressVersion", "publicIPAllocationMethod", "idleTimeoutInMinutes", "domainNameLabel", "fqdn", "ipTags", "IP Configuration Id", "type", "sku", "Resource Group Id"}, {"Public IP Name", "Public IP Resource Id", "location", "provisioningState", "resourceGuid", "ipAddress", "publicIPAddressVersion", "publicIPAllocationMethod", "idleTimeoutInMinutes", "domainNameLabel", "fqdn", "ipTags", "IP Configuration Id", "type", "sku", "Resource Group Id"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListPublicIPs",{"subscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"ipAddress", "Public IP Address"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// ListPublicIPs
|
||||
let ListPublicIPs = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Network/publicIPAddresses?api-version=2017-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"name", "id", "location", "properties", "type", "sku", "tags"}, {"name", "id", "location", "properties", "type", "sku", "tags"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"name", "Public IP Name"}, {"id", "Public IP Resource Id"}}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Renamed Columns", "properties", {"provisioningState", "resourceGuid", "ipAddress", "publicIPAddressVersion", "publicIPAllocationMethod", "idleTimeoutInMinutes", "dnsSettings", "ipTags", "ipConfiguration"}, {"provisioningState", "resourceGuid", "ipAddress", "publicIPAddressVersion", "publicIPAllocationMethod", "idleTimeoutInMinutes", "dnsSettings", "ipTags", "ipConfiguration"}),
|
||||
#"Expanded dnsSettings" = Table.ExpandRecordColumn(#"Expanded properties", "dnsSettings", {"domainNameLabel", "fqdn"}, {"domainNameLabel", "fqdn"}),
|
||||
#"Expanded ipTags" = Table.ExpandListColumn(#"Expanded dnsSettings", "ipTags"),
|
||||
#"Expanded ipConfiguration" = Table.ExpandRecordColumn(#"Expanded ipTags", "ipConfiguration", {"id"}, {"id"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded ipConfiguration",{{"id", "IP Configuration Id"}}),
|
||||
#"Expanded sku" = Table.ExpandRecordColumn(#"Renamed Columns1", "sku", {"name"}, {"name"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Expanded sku",{{"name", "sku"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns2",{"tags"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Removed Columns", "Public IP Resource Id", "Public IP Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Public IP Resource Id - Copy", Splitter.SplitTextByDelimiter("/providers", QuoteStyle.Csv), {"Public IP Resource Id - Copy.1", "Public IP Resource Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Public IP Resource Id - Copy.1", type text}, {"Public IP Resource Id - Copy.2", type text}}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Changed Type",{{"Public IP Resource Id - Copy.1", "Resource Group Id"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns3",{"Public IP Resource Id - Copy.2"})
|
||||
in
|
||||
#"Removed Columns1"
|
||||
|
||||
|
||||
in
|
||||
ListPublicIPs
|
||||
|
||||
// Containers VMs
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListVirtualMachines", each ListVirtualMachines([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListVirtualMachines"}),
|
||||
#"Expanded ListVirtualMachines" = Table.ExpandTableColumn(#"Removed Errors", "ListVirtualMachines", {"Availability Set Id", "vmSize", "publisher", "offer", "sku", "version", "osType", "name", "createOption", "vhd uri", "caching", "diskSizeGB", "storageAccountType", "Managed Disk Id", "lun", "name.1", "createOption.1", "Data vhd uri", "caching.1", "diskSizeGB.1", "computerName", "adminUsername", "provisionVMAgent", "enableAutomaticUpdates", "Network Inteface Id", "provisioningState", "enabled", "storageUri", "Extensions Resource Id", "type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "VM Resource Id", "VM Name"}, {"Availability Set Id", "vmSize", "publisher", "offer", "sku", "version", "osType", "name", "createOption", "vhd uri", "caching", "diskSizeGB", "storageAccountType", "Managed Disk Id", "lun", "name.1", "createOption.1", "Data vhd uri", "caching.1", "diskSizeGB.1", "computerName", "adminUsername", "provisionVMAgent", "enableAutomaticUpdates", "Network Inteface Id", "provisioningState", "enabled", "storageUri", "Extensions Resource Id", "type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "VM Resource Id", "VM Name"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListVirtualMachines",{"subscriptionId", "Subscription Name"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns", {"VM Resource Id"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Removed Duplicates", "VM Resource Id", "VM Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "VM Resource Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"VM Resource Id - Copy.1", "VM Resource Id - Copy.2", "VM Resource Id - Copy.3", "VM Resource Id - Copy.4", "VM Resource Id - Copy.5", "VM Resource Id - Copy.6", "VM Resource Id - Copy.7", "VM Resource Id - Copy.8", "VM Resource Id - Copy.9"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"VM Resource Id - Copy.1", type text}, {"VM Resource Id - Copy.2", type text}, {"VM Resource Id - Copy.3", type text}, {"VM Resource Id - Copy.4", type text}, {"VM Resource Id - Copy.5", type text}, {"VM Resource Id - Copy.6", type text}, {"VM Resource Id - Copy.7", type text}, {"VM Resource Id - Copy.8", type text}, {"VM Resource Id - Copy.9", type text}}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Changed Type",{{"VM Resource Id - Copy.5", "Resource Group Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"VM Resource Id - Copy.1", "VM Resource Id - Copy.2", "VM Resource Id - Copy.3", "VM Resource Id - Copy.4", "VM Resource Id - Copy.6", "VM Resource Id - Copy.7", "VM Resource Id - Copy.8", "VM Resource Id - Copy.9"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Columns1", "Is Using Managed Disks", each if [Managed Disk Id] = null then false else true),
|
||||
#"Duplicated Column1" = Table.DuplicateColumn(#"Added Conditional Column", "Extensions Resource Id", "Extensions Resource Id - Copy"),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Duplicated Column1", "Extensions Resource Id - Copy", Splitter.SplitTextByDelimiter("/extensions/", QuoteStyle.Csv), {"Extensions Resource Id - Copy.1", "Extensions Resource Id - Copy.2"}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Split Column by Delimiter1",{"Extensions Resource Id - Copy.1"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Removed Columns2",{{"Extensions Resource Id - Copy.2", "VM Extension"}}),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Renamed Columns2", "IsRunningContainers", each if [orchestrator] = null then "VM without Containers" else "VM with Containers"),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Added Conditional Column1",null,"Custom",Replacer.ReplaceValue,{"offer"}),
|
||||
#"Added Conditional Column2" = Table.AddColumn(#"Replaced Value", "OS Type", each if [osType] = "Windows" then "https://azure.github.io/ccodashboard/assets/pictures/001_Compute_WindowsLogo.svg" else if [osType] = "Linux" then "https://azure.github.io/ccodashboard/assets/pictures/002_Compute_LinuxLogo.svg" else null),
|
||||
#"Changed Type1" = Table.TransformColumnTypes(#"Added Conditional Column2",{{"OS Type", type text}}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Changed Type1", each ([IsRunningContainers] = "VM with Containers")),
|
||||
#"Added Conditional Column3" = Table.AddColumn(#"Filtered Rows", "Custom", each if [IsRunningContainers] <> "VM with Containers" then "" else "https://azure.github.io/ccodashboard/assets/pictures/002_AKS_ContainersHost.svg"),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Added Conditional Column3",{{"Custom", "Node Image"}})
|
||||
in
|
||||
#"Renamed Columns3"
|
||||
|
||||
// Containers NICs
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListAllNICsDetails", each ListAllNICsDetails([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListAllNICsDetails"}),
|
||||
#"Expanded ListAllNICsDetails" = Table.ExpandTableColumn(#"Removed Errors", "ListAllNICsDetails", {"NIC Name", "NIC Id", "location", "provisioningState", "resourceGuid", "name.1", "id.3", "etag", "provisioningState.1", "privateIPAddress", "privateIPAllocationMethod", "Public IP Address ID", "Subnet Id", "primary.1", "privateIPAddressVersion", "isInUseWithService", "id.6", "dnsServers", "appliedDnsServers", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "NSG Id", "primary", "Virtual Machine Id", "type"}, {"NIC Name", "NIC Id", "location", "provisioningState", "resourceGuid", "name.1", "id.3", "etag", "provisioningState.1", "privateIPAddress", "privateIPAllocationMethod", "Public IP Address ID", "Subnet Id", "primary.1", "privateIPAddressVersion", "isInUseWithService", "id.6", "dnsServers", "appliedDnsServers", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "NSG Id", "primary", "Virtual Machine Id", "type"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListAllNICsDetails",{"subscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"id.3", "IP Configuration Id"}, {"primary.1", "isPrimary"}, {"id.6", "BackendAddressPool Id"}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns1", "Subnet Id", "Subnet Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Subnet Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"Subnet Id - Copy.1", "Subnet Id - Copy.2", "Subnet Id - Copy.3", "Subnet Id - Copy.4", "Subnet Id - Copy.5", "Subnet Id - Copy.6", "Subnet Id - Copy.7", "Subnet Id - Copy.8", "Subnet Id - Copy.9", "Subnet Id - Copy.10", "Subnet Id - Copy.11"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Subnet Id - Copy.1", type text}, {"Subnet Id - Copy.2", type text}, {"Subnet Id - Copy.3", type text}, {"Subnet Id - Copy.4", type text}, {"Subnet Id - Copy.5", type text}, {"Subnet Id - Copy.6", type text}, {"Subnet Id - Copy.7", type text}, {"Subnet Id - Copy.8", type text}, {"Subnet Id - Copy.9", type text}, {"Subnet Id - Copy.10", type text}, {"Subnet Id - Copy.11", type text}}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Changed Type",{{"Subnet Id - Copy.9", "VNET Name"}, {"Subnet Id - Copy.11", "Subnet Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns2",{"Subnet Id - Copy.10", "Subnet Id - Copy.4", "Subnet Id - Copy.5", "Subnet Id - Copy.6", "Subnet Id - Copy.7", "Subnet Id - Copy.8", "Subnet Id - Copy.1", "Subnet Id - Copy.2", "Subnet Id - Copy.3", "name.1"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns1", {"NIC Id"})
|
||||
in
|
||||
#"Removed Duplicates"
|
||||
|
||||
// ListImages
|
||||
let ListContainerImageInventory = (CustomerId as text , ComputerName as text) =>
|
||||
|
||||
|
@ -266,4 +642,251 @@ let
|
|||
#"Expanded ContainerImageInventory" = Table.ExpandTableColumn(#"Removed Errors1", "ContainerImageInventory", {"TenantId", "SourceSystem", "TimeGenerated", "Computer", "ContainerID", "Name", "ContainerHostname", "ImageID", "Repository", "Image", "ImageTag", "ContainerState", "Ports", "Links", "ExitCode", "ComposeGroup", "EnvironmentVar", "Command", "CreatedTime", "StartedTime", "FinishedTime", "Type", "_ResourceId"}, {"ContainerImageInventory.TenantId", "ContainerImageInventory.SourceSystem", "ContainerImageInventory.TimeGenerated", "ContainerImageInventory.Computer", "ContainerImageInventory.ContainerID", "ContainerImageInventory.Name", "ContainerImageInventory.ContainerHostname", "ContainerImageInventory.ImageID", "ContainerImageInventory.Repository", "ContainerImageInventory.Image", "ContainerImageInventory.ImageTag", "ContainerImageInventory.ContainerState", "ContainerImageInventory.Ports", "ContainerImageInventory.Links", "ContainerImageInventory.ExitCode", "ContainerImageInventory.ComposeGroup", "ContainerImageInventory.EnvironmentVar", "ContainerImageInventory.Command", "ContainerImageInventory.CreatedTime", "ContainerImageInventory.StartedTime", "ContainerImageInventory.FinishedTime", "ContainerImageInventory.Type", "ContainerImageInventory._ResourceId"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Expanded ContainerImageInventory",{{"ContainerImageInventory.FinishedTime", type datetimezone}, {"ContainerImageInventory.StartedTime", type datetimezone}, {"ContainerImageInventory.CreatedTime", type datetimezone}})
|
||||
in
|
||||
#"Changed Type"
|
||||
#"Changed Type"
|
||||
|
||||
// ListServicePrincipals
|
||||
let ListRBACUsers = (principalId as text) =>
|
||||
let
|
||||
url = "https://graph.windows.net/myorganization/servicePrincipals?api-version=1.6&$filter=objectId eq '"&principalId&"'",
|
||||
iterations = 10,
|
||||
FuncGetOnePage = (url) as record =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(url)),
|
||||
data = try Source[value] otherwise null,
|
||||
next = try Source[nextLink] otherwise null,
|
||||
res = [Data=data, Next=next]
|
||||
in
|
||||
res,
|
||||
GeneratedListOfPages = List.Generate(()=>[i=0, res = FuncGetOnePage(url)],
|
||||
each [i]<iterations and [res][Data]<>null,
|
||||
each [i=[i]+1, res = FuncGetOnePage([res][Next])],
|
||||
each [res][Data]),
|
||||
|
||||
#"Converted to Table" = Table.FromList(GeneratedListOfPages, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandListColumn(#"Converted to Table", "Column1")
|
||||
|
||||
in
|
||||
#"Expanded Column1"
|
||||
in
|
||||
ListRBACUsers
|
||||
|
||||
// Service Principals
|
||||
// RBAC Role Assignments
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List RBACRoleAssignments" = Table.AddColumn(#"Renamed Columns", "ListRBACRoleAssignments", each ListRBACRoleAssignments([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List RBACRoleAssignments", {"ListRBACRoleAssignments"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Errors",{{"Column1.displayName", "Subscription Name"}}),
|
||||
#"Expanded ListRBACRoleAssignments" = Table.ExpandTableColumn(#"Renamed Columns1", "ListRBACRoleAssignments", {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}, {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Expanded ListRBACRoleAssignments", "Users", each ListServicePrincipals([principalId])),
|
||||
#"Removed Errors1" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"Users"}),
|
||||
#"Expanded Users" = Table.ExpandTableColumn(#"Removed Errors1", "Users", {"Column1"}, {"Column1"}),
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Expanded Users", "Column1", {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "addIns", "alternativeNames", "appDisplayName", "appId", "appOwnerTenantId", "appRoleAssignmentRequired", "appRoles", "displayName", "errorUrl", "homepage", "keyCredentials", "logoutUrl", "oauth2Permissions", "passwordCredentials", "preferredTokenSigningKeyThumbprint", "publisherName", "replyUrls", "samlMetadataUrl", "servicePrincipalNames", "servicePrincipalType", "signInAudience", "tags", "tokenEncryptionKeyId"}, {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "addIns", "alternativeNames", "appDisplayName", "appId", "appOwnerTenantId", "appRoleAssignmentRequired", "appRoles", "displayName", "errorUrl", "homepage", "keyCredentials", "logoutUrl", "oauth2Permissions", "passwordCredentials", "preferredTokenSigningKeyThumbprint", "publisherName", "replyUrls", "samlMetadataUrl", "servicePrincipalNames", "servicePrincipalType", "signInAudience", "tags", "tokenEncryptionKeyId"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column2",{"replyUrls", "servicePrincipalNames", "tags", "passwordCredentials"}),
|
||||
#"Expanded oauth2Permissions" = Table.ExpandListColumn(#"Removed Columns", "oauth2Permissions"),
|
||||
#"Expanded oauth2Permissions1" = Table.ExpandRecordColumn(#"Expanded oauth2Permissions", "oauth2Permissions", {"adminConsentDescription", "adminConsentDisplayName", "id", "isEnabled", "type", "userConsentDescription", "userConsentDisplayName", "value"}, {"adminConsentDescription", "adminConsentDisplayName", "id.1", "isEnabled", "type.1", "userConsentDescription", "userConsentDisplayName", "value"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded oauth2Permissions1",{"addIns", "alternativeNames", "appRoles", "errorUrl"}),
|
||||
#"Expanded keyCredentials" = Table.ExpandListColumn(#"Removed Columns1", "keyCredentials"),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Expanded keyCredentials",{"keyCredentials", "logoutUrl"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Removed Columns2", each not Text.StartsWith([displayName], "AzureContainerService") and not Text.StartsWith([displayName], "azure-cli-")),
|
||||
#"Filtered Rows1" = Table.SelectRows(#"Filtered Rows", each true),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Filtered Rows1", "scope", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"scope.1", "scope.2", "scope.3", "scope.4", "scope.5", "scope.6", "scope.7", "scope.8", "scope.9", "scope.10", "scope.11"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Split Column by Delimiter",{{"scope.5", "Resource Group"}, {"scope.7", "Resource Provider"}, {"scope.8", "Resource Type"}, {"scope.9", "Resource Name"}}),
|
||||
#"Removed Columns3" = Table.RemoveColumns(#"Renamed Columns2",{"scope.1", "scope.2", "scope.3", "scope.4", "scope.6"}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Removed Columns3",null,"*",Replacer.ReplaceValue,{"Resource Group"}),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Replaced Value",null,"*",Replacer.ReplaceValue,{"Resource Provider"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Replaced Value1", "Custom", each if [Resource Group] = "*" then "Subscription" else if [Resource Provider] = "*" then "Resource Group" else if [Resource Type] <> null then [Resource Type] else null),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Added Conditional Column",{{"scope.11", "Integration Runtime Name"}, {"scope.10", "DataFactory Resource Type"}}),
|
||||
#"Replaced Value2" = Table.ReplaceValue(#"Renamed Columns3",null,"resourcegroup",Replacer.ReplaceValue,{"Resource Type"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Replaced Value2", {"appId"})
|
||||
|
||||
in
|
||||
#"Removed Duplicates"
|
||||
|
||||
// ListRBACRoleAssignments
|
||||
let ListRBACRoleAssignments = (subscriptionId as text) =>
|
||||
let
|
||||
url = "https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Authorization/roleAssignments?api-version=2015-07-01",
|
||||
iterations = 10,
|
||||
FuncGetOnePage = (url) as record =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(url)),
|
||||
data = try Source[value] otherwise null,
|
||||
next = try Source[nextLink] otherwise null,
|
||||
res = [Data=data, Next=next]
|
||||
in
|
||||
res,
|
||||
GeneratedListOfPages = List.Generate(()=>[i=0, res = FuncGetOnePage(url)],
|
||||
each [i]<iterations and [res][Data]<>null,
|
||||
each [i=[i]+1, res = FuncGetOnePage([res][Next])],
|
||||
each [res][Data]),
|
||||
|
||||
#"Converted to Table" = Table.FromList(GeneratedListOfPages, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandListColumn(#"Converted to Table", "Column1"),
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Expanded Column1", "Column1", {"properties", "id", "type", "name"}, {"properties", "id", "type", "name"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column2", "properties", {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy"}, {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy"})
|
||||
in
|
||||
#"Expanded properties"
|
||||
|
||||
in
|
||||
ListRBACRoleAssignments
|
||||
|
||||
// RBAC Role Definitions
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List RBACRoleDefinitions" = Table.AddColumn(#"Renamed Columns", "ListRBACRoleDefinitions", each ListRBACRoleDefinitions([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List RBACRoleDefinitions", {"ListRBACRoleDefinitions"}),
|
||||
#"Expanded ListRBACRoleDefinitions" = Table.ExpandTableColumn(#"Removed Errors", "ListRBACRoleDefinitions", {"roleName", "type.1", "description", "assignableScopes", "actions", "notActions", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}, {"roleName", "type.1", "description", "assignableScopes", "actions", "notActions", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded ListRBACRoleDefinitions",{{"type.1", "roleType"}, {"Column1.displayName", "Subscription Name"}, {"id", "roleDefinitionId"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns1",{"type"})
|
||||
in
|
||||
#"Removed Columns"
|
||||
|
||||
// ListRBACRoleDefinitions
|
||||
let ListRBACRoleDefinitions = (subscriptionId as text) =>
|
||||
let
|
||||
url = "https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Authorization/roleDefinitions?api-version=2015-07-01",
|
||||
iterations = 10,
|
||||
FuncGetOnePage = (url) as record =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(url)),
|
||||
data = try Source[value] otherwise null,
|
||||
next = try Source[nextLink] otherwise null,
|
||||
res = [Data=data, Next=next]
|
||||
in
|
||||
res,
|
||||
GeneratedListOfPages = List.Generate(()=>[i=0, res = FuncGetOnePage(url)],
|
||||
each [i]<iterations and [res][Data]<>null,
|
||||
each [i=[i]+1, res = FuncGetOnePage([res][Next])],
|
||||
each [res][Data]),
|
||||
|
||||
#"Converted to Table" = Table.FromList(GeneratedListOfPages, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandListColumn(#"Converted to Table", "Column1"),
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Expanded Column1", "Column1", {"properties", "id", "type", "name"}, {"properties", "id", "type", "name"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column2", "properties", {"roleName", "type", "description", "assignableScopes", "permissions", "createdOn", "updatedOn", "createdBy", "updatedBy"}, {"roleName", "type.1", "description", "assignableScopes", "permissions", "createdOn", "updatedOn", "createdBy", "updatedBy"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded properties", {"assignableScopes", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded permissions" = Table.ExpandListColumn(#"Extracted Values", "permissions"),
|
||||
#"Expanded permissions1" = Table.ExpandRecordColumn(#"Expanded permissions", "permissions", {"actions", "notActions"}, {"actions", "notActions"}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Expanded permissions1", {"actions", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Extracted Values2" = Table.TransformColumns(#"Extracted Values1", {"notActions", each Text.Combine(List.Transform(_, Text.From)), type text})
|
||||
in
|
||||
#"Extracted Values2"
|
||||
in
|
||||
ListRBACRoleDefinitions
|
||||
|
||||
// RBAC Role Users
|
||||
// RBAC Role Assignments
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List RBACRoleAssignments" = Table.AddColumn(#"Renamed Columns", "ListRBACRoleAssignments", each ListRBACRoleAssignments([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List RBACRoleAssignments", {"ListRBACRoleAssignments"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Errors",{{"Column1.displayName", "Subscription Name"}}),
|
||||
#"Expanded ListRBACRoleAssignments" = Table.ExpandTableColumn(#"Renamed Columns1", "ListRBACRoleAssignments", {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}, {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Expanded ListRBACRoleAssignments", "scope", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"scope.1", "scope.2", "scope.3", "scope.4", "scope.5", "scope.6", "scope.7", "scope.8", "scope.9", "scope.10", "scope.11"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Split Column by Delimiter1",{{"scope.5", "Resource Group"}, {"scope.7", "Resource Provider"}, {"scope.8", "Resource Type"}, {"scope.9", "Resource Name"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns2",{"scope.1", "scope.2", "scope.3", "scope.4", "scope.6"}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Removed Columns",null,"*",Replacer.ReplaceValue,{"Resource Group"}),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Replaced Value",null,"*",Replacer.ReplaceValue,{"Resource Provider"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Replaced Value1", "Custom", each if [Resource Group] = "*" then "Subscription" else if [Resource Provider] = "*" then "Resource Group" else if [Resource Type] <> null then [Resource Type] else null),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Added Conditional Column",{{"Resource Type", "Rtype"}, {"Custom", "Resource Type"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns3", "Users", each ListRBACUsers([principalId])),
|
||||
#"Removed Errors1" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"Users"}),
|
||||
#"Expanded Users" = Table.ExpandTableColumn(#"Removed Errors1", "Users", {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "ageGroup", "city", "companyName", "consentProvidedForMinor", "country", "creationType", "department", "dirSyncEnabled", "displayName", "employeeId", "facsimileTelephoneNumber", "givenName", "immutableId", "isCompromised", "jobTitle", "lastDirSyncTime", "legalAgeGroupClassification", "mail", "mailNickname", "mobile", "onPremisesDistinguishedName", "onPremisesSecurityIdentifier", "passwordPolicies", "passwordProfile", "physicalDeliveryOfficeName", "postalCode", "preferredLanguage", "refreshTokensValidFromDateTime", "showInAddressList", "sipProxyAddress", "state", "streetAddress", "surname", "telephoneNumber", "thumbnailPhoto@odata.mediaContentType", "usageLocation", "userPrincipalName", "userType", "extension_18e31482d3fb4a8ea958aa96b662f508_SupervisorInd", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingName", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingID", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToPersonnelNbr", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToFullName", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToEmailName", "extension_18e31482d3fb4a8ea958aa96b662f508_CompanyCode", "extension_18e31482d3fb4a8ea958aa96b662f508_CostCenterCode", "extension_18e31482d3fb4a8ea958aa96b662f508_LocationAreaCode", "extension_18e31482d3fb4a8ea958aa96b662f508_PersonnelNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_PositionNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_ProfitCenterCode"}, {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "ageGroup", "city", "companyName", "consentProvidedForMinor", "country", "creationType", "department", "dirSyncEnabled", "displayName", "employeeId", "facsimileTelephoneNumber", "givenName", "immutableId", "isCompromised", "jobTitle", "lastDirSyncTime", "legalAgeGroupClassification", "mail", "mailNickname", "mobile", "onPremisesDistinguishedName", "onPremisesSecurityIdentifier", "passwordPolicies", "passwordProfile", "physicalDeliveryOfficeName", "postalCode", "preferredLanguage", "refreshTokensValidFromDateTime", "showInAddressList", "sipProxyAddress", "state", "streetAddress", "surname", "telephoneNumber", "thumbnailPhoto@odata.mediaContentType", "usageLocation", "userPrincipalName", "userType", "extension_18e31482d3fb4a8ea958aa96b662f508_SupervisorInd", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingName", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingID", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToPersonnelNbr", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToFullName", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToEmailName", "extension_18e31482d3fb4a8ea958aa96b662f508_CompanyCode", "extension_18e31482d3fb4a8ea958aa96b662f508_CostCenterCode", "extension_18e31482d3fb4a8ea958aa96b662f508_LocationAreaCode", "extension_18e31482d3fb4a8ea958aa96b662f508_PersonnelNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_PositionNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_ProfitCenterCode"})
|
||||
in
|
||||
#"Expanded Users"
|
||||
|
||||
// ListRBACUsers
|
||||
let ListRBACUsers = (principalId as text) =>
|
||||
let
|
||||
url = "https://graph.windows.net/"&TenantName&"/users?api-version=1.6&$filter=objectId eq '"&principalId&"'",
|
||||
iterations = 10,
|
||||
FuncGetOnePage = (url) as record =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(url)),
|
||||
data = try Source[value] otherwise null,
|
||||
next = try Source[nextLink] otherwise null,
|
||||
res = [Data=data, Next=next]
|
||||
in
|
||||
res,
|
||||
GeneratedListOfPages = List.Generate(()=>[i=0, res = FuncGetOnePage(url)],
|
||||
each [i]<iterations and [res][Data]<>null,
|
||||
each [i=[i]+1, res = FuncGetOnePage([res][Next])],
|
||||
each [res][Data]),
|
||||
|
||||
#"Converted to Table" = Table.FromList(GeneratedListOfPages, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandListColumn(#"Converted to Table", "Column1"),
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Expanded Column1", "Column1", {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "ageGroup", "assignedLicenses", "assignedPlans", "city", "companyName", "consentProvidedForMinor", "country", "creationType", "department", "dirSyncEnabled", "displayName", "employeeId", "facsimileTelephoneNumber", "givenName", "immutableId", "isCompromised", "jobTitle", "lastDirSyncTime", "legalAgeGroupClassification", "mail", "mailNickname", "mobile", "onPremisesDistinguishedName", "onPremisesSecurityIdentifier", "otherMails", "passwordPolicies", "passwordProfile", "physicalDeliveryOfficeName", "postalCode", "preferredLanguage", "provisionedPlans", "provisioningErrors", "proxyAddresses", "refreshTokensValidFromDateTime", "showInAddressList", "signInNames", "sipProxyAddress", "state", "streetAddress", "surname", "telephoneNumber", "thumbnailPhoto@odata.mediaContentType", "usageLocation", "userIdentities", "userPrincipalName", "userType", "extension_18e31482d3fb4a8ea958aa96b662f508_SupervisorInd", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingName", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingID", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToPersonnelNbr", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToFullName", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToEmailName", "extension_18e31482d3fb4a8ea958aa96b662f508_CompanyCode", "extension_18e31482d3fb4a8ea958aa96b662f508_CostCenterCode", "extension_18e31482d3fb4a8ea958aa96b662f508_LocationAreaCode", "extension_18e31482d3fb4a8ea958aa96b662f508_PersonnelNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_PositionNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_ProfitCenterCode"}, {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "ageGroup", "assignedLicenses", "assignedPlans", "city", "companyName", "consentProvidedForMinor", "country", "creationType", "department", "dirSyncEnabled", "displayName", "employeeId", "facsimileTelephoneNumber", "givenName", "immutableId", "isCompromised", "jobTitle", "lastDirSyncTime", "legalAgeGroupClassification", "mail", "mailNickname", "mobile", "onPremisesDistinguishedName", "onPremisesSecurityIdentifier", "otherMails", "passwordPolicies", "passwordProfile", "physicalDeliveryOfficeName", "postalCode", "preferredLanguage", "provisionedPlans", "provisioningErrors", "proxyAddresses", "refreshTokensValidFromDateTime", "showInAddressList", "signInNames", "sipProxyAddress", "state", "streetAddress", "surname", "telephoneNumber", "thumbnailPhoto@odata.mediaContentType", "usageLocation", "userIdentities", "userPrincipalName", "userType", "extension_18e31482d3fb4a8ea958aa96b662f508_SupervisorInd", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingName", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingID", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToPersonnelNbr", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToFullName", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToEmailName", "extension_18e31482d3fb4a8ea958aa96b662f508_CompanyCode", "extension_18e31482d3fb4a8ea958aa96b662f508_CostCenterCode", "extension_18e31482d3fb4a8ea958aa96b662f508_LocationAreaCode", "extension_18e31482d3fb4a8ea958aa96b662f508_PersonnelNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_PositionNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_ProfitCenterCode"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column2",{"assignedLicenses", "assignedPlans", "otherMails", "provisionedPlans", "provisioningErrors", "proxyAddresses", "signInNames", "userIdentities"})
|
||||
in
|
||||
#"Removed Columns"
|
||||
in
|
||||
ListRBACUsers
|
||||
|
||||
// List Security tasks
|
||||
let ListSecurityTasks = (subscriptionId as text)=>
|
||||
let
|
||||
url = "https://management.azure.com/subscriptions/"&subscriptionId&"/providers/microsoft.Security/tasks?api-version=2015-06-01-preview",
|
||||
iterations = 10,
|
||||
FuncGetOnePage = (url) as record =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(url)),
|
||||
data = try Source[value] otherwise null,
|
||||
next = try Source[nextLink] otherwise null,
|
||||
res = [Data=data, Next=next]
|
||||
in
|
||||
res,
|
||||
GeneratedListOfPages = List.Generate(()=>[i=0, res = FuncGetOnePage(url)],
|
||||
each [i]<iterations and [res][Data]<>null,
|
||||
each [i=[i]+1, res = FuncGetOnePage([res][Next])],
|
||||
each [res][Data]),
|
||||
|
||||
#"Converted to Table" = Table.FromList(GeneratedListOfPages, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandListColumn(#"Converted to Table", "Column1"),
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Expanded Column1", "Column1", {"id", "properties"}, {"id", "properties"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column2",{{"id", "Security Center Task Id"}}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Renamed Columns", "properties", {"state", "subState", "creationTimeUtc", "lastStateChangeTimeUtc", "securityTaskParameters"}, {"state", "subState", "creationTimeUtc", "lastStateChangeTimeUtc", "securityTaskParameters"}),
|
||||
#"Expanded securityTaskParameters" = Table.ExpandRecordColumn(#"Expanded properties", "securityTaskParameters", {"subscriptionId", "id", "title", "classification", "totalNumberOfImpactedMachines", "severity", "osType", "isMandatory", "workspaces", "name", "uniqueKey", "resourceId", "baselineRuleId", "baselineName", "baselineCceId", "osName", "ruleType", "totalNumberOfDefectedMachines", "resourceType", "category", "assessmentKey", "policyName", "policyDefinitionId", "details", "vmId", "vmName", "isOsDiskEncrypted", "isDataDiskEncrypted"}, {"subscriptionId", "id", "title", "classification", "totalNumberOfImpactedMachines", "severity", "osType", "isMandatory", "workspaces", "name", "uniqueKey", "resourceId", "baselineRuleId", "baselineName", "baselineCceId", "osName", "ruleType", "totalNumberOfDefectedMachines", "resourceType", "category", "assessmentKey", "policyName", "policyDefinitionId", "details", "vmId", "vmName", "isOsDiskEncrypted", "isDataDiskEncrypted"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Expanded securityTaskParameters", each ([subscriptionId] = null))
|
||||
in
|
||||
#"Filtered Rows"
|
||||
in
|
||||
ListSecurityTasks
|
||||
|
||||
// Security Tasks
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Converted to Table", {"Column1"}),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Removed Errors", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "SubscriptionName"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "SecurityTasks", each #"List Security tasks"([subscriptionId])),
|
||||
#"Removed Errors1" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"SecurityTasks"}),
|
||||
#"Expanded SecurityTasks" = Table.ExpandTableColumn(#"Removed Errors1", "SecurityTasks", {"Security Center Task Id", "state", "subState", "creationTimeUtc", "lastStateChangeTimeUtc", "id", "title", "classification", "totalNumberOfImpactedMachines", "severity", "osType", "isMandatory", "name", "uniqueKey", "resourceId", "resourceType", "policyName", "policyDefinitionId", "vmId", "vmName", "isOsDiskEncrypted", "isDataDiskEncrypted"}, {"Security Center Task Id", "state", "subState", "creationTimeUtc", "lastStateChangeTimeUtc", "id", "title", "classification", "totalNumberOfImpactedMachines", "severity", "osType", "isMandatory", "name", "uniqueKey", "resourceId", "resourceType", "policyName", "policyDefinitionId", "vmId", "vmName", "isOsDiskEncrypted", "isDataDiskEncrypted"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Expanded SecurityTasks", "Custom", each if [policyName] = null then [name] else [policyName]),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Added Conditional Column",{{"Custom", "Recommendation"}}),
|
||||
#"Replaced EncryptionOnVM Value" = Table.ReplaceValue(#"Renamed Columns1","EncryptionOnVm","Apply Disk Encryption on your virtual machines",Replacer.ReplaceText,{"Recommendation"}),
|
||||
#"Replaced InstallAntimalware Value" = Table.ReplaceValue(#"Replaced EncryptionOnVM Value","InstallAntimalware","#(tab)Install endpoint protection solution on your machines",Replacer.ReplaceText,{"Recommendation"}),
|
||||
#"Replaced UpgradePricingTierTaskParameters Value" = Table.ReplaceValue(#"Replaced InstallAntimalware Value","UpgradePricingTierTaskParameters","Enable Azure Security Center Standard tier on the Subscription",Replacer.ReplaceText,{"Recommendation"}),
|
||||
#"Filling Empty Categories" = Table.AddColumn(#"Replaced UpgradePricingTierTaskParameters Value", "Category2", each if [name] = "Enable Security Contact Configuration in Policy" then "IdentityAndAccess" else if [name] = "EncryptionOnVm" then "Compute" else if [name] = "UpgradePricingTierTaskParameters" then "IdentityAndAccess" else if [name] = "InstallAntimalware" then "Compute" else if [name] = "Enable auditing for the SQL server" then "Data" else if [name] = "Antimalware Health Issues" then "Compute" else if [name] = "Enable Transparent encryption for the database" then "Data" else if [name] = "RebootVm" then "Compute" else [resourceType]),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Filling Empty Categories","Subscription","IdentityAndAccess",Replacer.ReplaceText,{"Category2"}),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Replaced Value","VirtualMachine","Compute",Replacer.ReplaceText,{"Category2"}),
|
||||
#"Replaced Value2" = Table.ReplaceValue(#"Replaced Value1","SqlServer","Data",Replacer.ReplaceText,{"Category2"}),
|
||||
#"Replaced Value3" = Table.ReplaceValue(#"Replaced Value2","Microsoft_ContainerService_managedClusters","AKS_RBAC",Replacer.ReplaceText,{"Category2"}),
|
||||
#"Replaced Value4" = Table.ReplaceValue(#"Replaced Value3","SqlDb","Data",Replacer.ReplaceText,{"Category2"}),
|
||||
#"Replaced Value5" = Table.ReplaceValue(#"Replaced Value4","Server","Compute",Replacer.ReplaceText,{"Category2"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Replaced Value5", each ([resourceType] = "Microsoft_ContainerService_managedClusters"))
|
||||
in
|
||||
#"Filtered Rows"
|
|
@ -1,45 +0,0 @@
|
|||
// Get Recommendations
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}, {"Column1.displayName", "Subscription Name"}}),
|
||||
#"List Recommendations" = Table.AddColumn(#"Renamed Columns", "ListRecommendations", each ListRecommendations([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List Recommendations", {"ListRecommendations"}),
|
||||
#"Expanded ListRecommendations1" = Table.ExpandTableColumn(#"Removed Errors", "ListRecommendations", {"Recommendation Id", "category", "impact", "impactedField", "impactedValue", "lastUpdated", "risk", "problem", "solution", "type"}, {"Recommendation Id", "category", "impact", "impactedField", "impactedValue", "lastUpdated", "risk", "problem", "solution", "type"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Expanded ListRecommendations1", each ([problem] <> "Improve the security of your Azure resources")),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Filtered Rows", "Recommendation URL", each if [problem] = "Improve the reliability of your availability set" then "https://docs.microsoft.com/en-us/azure/virtual-machines/windows/managed-disks-overview" else if [problem] = "This virtual machine is not configured for fault tolerance" then "https://docs.microsoft.com/en-us/azure/virtual-machines/windows/change-availability-set" else if [problem] = "Your virtual machine has low usage" then "https://azure.microsoft.com/en-us/pricing/calculator/" else if [problem] = "This availability set is not configured for fault tolerance" then "https://docs.microsoft.com/en-us/azure/virtual-machines/windows/tutorial-availability-sets?toc=%2Fazure%2Fvirtual-machines%2Fwindows%2Ftoc.json#add-a-new-vm-to-an-existing-availability-set" else if [problem] = "Improve the performance of your SQL Azure database" then "https://docs.microsoft.com/en-us/azure/sql-database/sql-database-advisor" else if [problem] = "Create an Azure service health alert" then "https://docs.microsoft.com/en-us/azure/monitoring-and-diagnostics/monitoring-activity-log-alerts-on-service-notifications" else if [problem] = "Configure DNS Time to Live to 60 seconds" then "https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-monitoring" else if [problem] = "Add at least one more endpoint to the profile, preferably in another Azure region" then "https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-endpoint-types" else if Text.Contains([problem], "Add an endpoint configured to") then "https://docs.microsoft.com/en-us/azure/traffic-manager/traffic-manager-manage-endpoints" else null),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Added Conditional Column",{{"Recommendation URL", type text}}),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Changed Type", "Image", each if Text.Contains([problem], "Improve the security of your Azure resource") then "https://azure.microsoft.com/svghandler/security-center/?width=600&height=315" else if Text.Contains([problem], "Your virtual machine has low usage") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/LowUsageVM.svg?sanitize=true" else if Text.Contains([problem], "Buy virtual machine reserved instances") then "https://azurecomcdn.azureedge.net/cvt-19310ed07ad97301763e5432fc983677a816728ac59717720722e9728c21c602/images/page/pricing/hybrid-benefit/ahub-save.png" else if Text.Contains([problem], "Your virtual machine is not configured for backup") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/VMBackup.svg?sanitize=true" else if Text.Contains([problem], "Your virtual network gateway") then "https://azurecomcdn.azureedge.net/cvt-ab79ca2a218608d26c26428d9e099c013b0d2c572504031fa6e10dd32d697722/images/page/services/vpn-gateway/01-connect.png" else if Text.Contains([problem], "Improve the reliability of your availability set") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/MDonAS.svg?sanitize=true" else if Text.Contains([problem], "This virtual machine is not configured for fault tolerance") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/FaultTolerance.svg?sanitize=true" else if Text.Contains([problem], "Improve the performance of your SQL Azure database") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/SQLPerfromance.svg?sanitize=true" else if Text.Contains([problem], "This availability set ") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/AddVMtoAS.svg?sanitize=true" else if [problem] = "Create an Azure service health alert" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/ServiceHealthAlert.svg?sanitize=true" else if [problem] = "Configure DNS Time to Live to 60 seconds" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/TrafficManagerTTL60.svg?sanitize=true" else if Text.Contains([problem], "Add an endpoint configured to") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/TrafficManagerEndpoints.svg?sanitize=true" else if [problem] = "Add at least one more endpoint to the profile, preferably in another Azure region" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/TrafficManagerMoreRegions.svg?sanitize=true" else if [problem] = "Enable Soft Delete to protect your blob data" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/SoftDelete.svg?sanitize=true" else if Text.Contains([problem], "Right-size underutilized") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/SQLUnderUtil.svg?sanitize=true" else null),
|
||||
#"Filtered Rows1" = Table.SelectRows(#"Added Conditional Column1", each [impactedField] <> null and [impactedField] <> ""),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Filtered Rows1", "Recommendation Id", "id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"id - Copy.1", "id - Copy.2", "id - Copy.3", "id - Copy.4", "id - Copy.5", "id - Copy.6", "id - Copy.7", "id - Copy.8", "id - Copy.9", "id - Copy.10", "id - Copy.11", "id - Copy.12", "id - Copy.13", "id - Copy.14", "id - Copy.15"}),
|
||||
#"Changed Type2" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"id - Copy.1", type text}, {"id - Copy.2", type text}, {"id - Copy.3", type text}, {"id - Copy.4", type text}, {"id - Copy.5", type text}, {"id - Copy.6", type text}, {"id - Copy.7", type text}, {"id - Copy.8", type text}, {"id - Copy.9", type text}, {"id - Copy.10", type text}, {"id - Copy.11", type text}, {"id - Copy.12", type text}, {"id - Copy.13", type text}, {"id - Copy.14", type text}, {"id - Copy.15", type text}}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Changed Type2",{{"id - Copy.5", "Resource Group Name"}, {"id - Copy.8", "Resource Type"}, {"id - Copy.9", "Resource Name"}, {"id - Copy.11", "Subnet"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns1",{"id - Copy.1", "id - Copy.2", "id - Copy.3", "id - Copy.4", "id - Copy.6", "id - Copy.7", "id - Copy.10", "id - Copy.12", "id - Copy.13", "id - Copy.14", "id - Copy.15"}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Removed Columns",null,"Subscription",Replacer.ReplaceValue,{"Resource Type"}),
|
||||
#"Added Conditional Column2" = Table.AddColumn(#"Replaced Value", "Resource Name Final", each if [Resource Name] = null then [Subscription Name] else [Resource Name]),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Added Conditional Column2","Configure DNS Time to Live to 60 seconds","Time to Live (TTL) affects how recent of a response a client will get when it makes a request to Azure Traffic Manager. Reducing the TTL value means that the client will be routed to a functioning endpoint faster in the case of a failover. Configure your TTL to 60 seconds to route traffic to a health endpoint as quickly as possible.",Replacer.ReplaceText,{"solution"}),
|
||||
#"Replaced Value2" = Table.ReplaceValue(#"Replaced Value1","Add at least one more endpoint to the profile, preferably in another Azure region","Profiles should have more than one endpoint to ensure availability if one of the endpoints fails. It is also recommended that endpoints be in different regions",Replacer.ReplaceText,{"solution"}),
|
||||
#"Replaced Value3" = Table.ReplaceValue(#"Replaced Value2","Add an endpoint configured to ""All (World)""","For geographic routing, traffic is routed to endpoints based on defined regions. When a region fails, there is no pre-defined failover. Having an endpoint where the Regional Grouping is configured to \""All (World)\"" for geographic profiles will avoid traffic black holing and guarantee service remains available.",Replacer.ReplaceText,{"solution"}),
|
||||
#"Replaced Value4" = Table.ReplaceValue(#"Replaced Value3","Create an Azure service health alert","Service health alerts help you stay notified when Azure service issues affect you. Create a service health alert for the regions and services that you care about",Replacer.ReplaceText,{"solution"}),
|
||||
#"Replaced Value5" = Table.ReplaceValue(#"Replaced Value4","Right-size underutilized SQL Databases","We've analyzed the DTU consumption of your SQL Database over the past 14 days and identified SQL Databases with low usage. You can save money by right-sizing to the recommended SKU based on the 95th percentile of your every day workload",Replacer.ReplaceText,{"solution"})
|
||||
in
|
||||
#"Replaced Value5"
|
||||
|
||||
// ListRecommendations
|
||||
let ListRecommendations = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Advisor/recommendations?api-version=2017-03-31")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "properties", "type"}, {"id", "name", "properties", "type"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"category", "impact", "impactedField", "impactedValue", "lastUpdated", "risk", "shortDescription"}, {"category", "impact", "impactedField", "impactedValue", "lastUpdated", "risk", "shortDescription"}),
|
||||
#"Expanded shortDescription" = Table.ExpandRecordColumn(#"Expanded properties", "shortDescription", {"problem", "solution"}, {"problem", "solution"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded shortDescription",{{"id", "Recommendation Id"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns",{"name"})
|
||||
in
|
||||
#"Removed Columns"
|
||||
in
|
||||
ListRecommendations
|
|
@ -1,91 +0,0 @@
|
|||
// ListACS
|
||||
let ListResourceGroups= (subscriptionId as text) =>
|
||||
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.ContainerService/containerServices?api-version=2017-01-31")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
|
||||
in
|
||||
#"Converted to Table"
|
||||
|
||||
in
|
||||
#"ListResourceGroups"
|
||||
|
||||
// ACI
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List ACI" = Table.AddColumn(#"Renamed Columns", "ListACI", each ListACI([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List ACI", {"ListACI"}),
|
||||
#"Expanded ListACI" = Table.ExpandTableColumn(#"Removed Errors", "ListACI", {"id", "location", "name", "type", "properties"}, {"id", "location", "name", "type", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded ListACI", "properties", {"provisioningState", "containers", "restartPolicy", "ipAddress", "osType"}, {"provisioningState", "containers", "restartPolicy", "ipAddress", "osType"}),
|
||||
#"Expanded containers" = Table.ExpandListColumn(#"Expanded properties", "containers"),
|
||||
#"Expanded containers1" = Table.ExpandRecordColumn(#"Expanded containers", "containers", {"name", "properties"}, {"name.1", "properties"}),
|
||||
#"Expanded properties1" = Table.ExpandRecordColumn(#"Expanded containers1", "properties", {"image", "ports", "environmentVariables", "resources"}, {"image", "ports", "environmentVariables", "resources"}),
|
||||
#"Expanded ports" = Table.ExpandListColumn(#"Expanded properties1", "ports"),
|
||||
#"Expanded ports1" = Table.ExpandRecordColumn(#"Expanded ports", "ports", {"port"}, {"port"}),
|
||||
#"Expanded environmentVariables" = Table.ExpandListColumn(#"Expanded ports1", "environmentVariables"),
|
||||
#"Expanded resources" = Table.ExpandRecordColumn(#"Expanded environmentVariables", "resources", {"requests"}, {"requests"}),
|
||||
#"Expanded requests" = Table.ExpandRecordColumn(#"Expanded resources", "requests", {"memoryInGB", "cpu"}, {"memoryInGB", "cpu"}),
|
||||
#"Expanded ipAddress" = Table.ExpandRecordColumn(#"Expanded requests", "ipAddress", {"ip", "type"}, {"ip", "type.1"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded ipAddress", "id", "id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "id", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"id.1", "id.2", "id.3", "id.4", "id.5", "id.6", "id.7", "id.8", "id.9"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"id.1", type text}, {"id.2", type text}, {"id.3", type text}, {"id.4", type text}, {"id.5", type text}, {"id.6", type text}, {"id.7", type text}, {"id.8", type text}, {"id.9", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"id.1", "id.2", "id.3", "id.4"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"id.5", "Resource Group Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"id.6", "id.7", "id.8", "id.9"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Removed Columns1",{{"id - Copy", "Id"}, {"Column1.displayName", "Subscription Name"}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Renamed Columns2",{"SubscriptionId", "Subscription Name"})
|
||||
in
|
||||
#"Removed Columns2"
|
||||
|
||||
// ListACI
|
||||
let ListResourceGroups= (subscriptionId as text) =>
|
||||
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.ContainerInstance/containerGroups?api-version=2018-02-01-preview")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "location", "name", "type", "properties"}, {"id", "location", "name", "type", "properties"})
|
||||
in
|
||||
#"Expanded Column1"
|
||||
|
||||
in
|
||||
#"ListResourceGroups"
|
||||
|
||||
// ListRegistry
|
||||
let ListResourceGroups= (subscriptionId as text) =>
|
||||
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.ContainerRegistry/registries?api-version=2017-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error)
|
||||
in
|
||||
#"Converted to Table"
|
||||
|
||||
in
|
||||
#"ListResourceGroups"
|
||||
|
||||
// ACR
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List Registry" = Table.AddColumn(#"Renamed Columns", "ListRegistry", each ListRegistry([SubscriptionId])),
|
||||
#"Expanded ListRegistry" = Table.ExpandTableColumn(#"List Registry", "ListRegistry", {"Column1"}, {"Column1"}),
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Expanded ListRegistry", "Column1", {"sku", "type", "id", "name", "location", "tags", "properties"}, {"sku", "type", "id", "name", "location", "tags", "properties"}),
|
||||
#"Expanded sku" = Table.ExpandRecordColumn(#"Expanded Column2", "sku", {"name", "tier"}, {"sku.name", "sku.tier"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded sku",{"tags"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Removed Columns", "properties", {"loginServer", "creationDate", "provisioningState", "adminUserEnabled", "storageAccount"}, {"loginServer", "creationDate", "provisioningState", "adminUserEnabled", "storageAccount"}),
|
||||
#"Expanded storageAccount" = Table.ExpandRecordColumn(#"Expanded properties", "storageAccount", {"id"}, {"id.1"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded storageAccount",{{"Column1.displayName", "Subscription Name"}}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Renamed Columns1", each [type] <> null and [type] <> ""),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Filtered Rows",{"SubscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Removed Columns1",{{"loginServer", "Registry login Server"}})
|
||||
in
|
||||
#"Renamed Columns2"
|
|
@ -1,49 +0,0 @@
|
|||
// Azure Regions
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}, {"Column1.displayName", "Subscription Name"}}),
|
||||
#"List AzureLocations" = Table.AddColumn(#"Renamed Columns", " ListAzureLocations", each ListAzureLocations([SubscriptionId])),
|
||||
#"Expanded ListAzureLocations" = Table.ExpandTableColumn(#"List AzureLocations", " ListAzureLocations", {"Name", "Value.id", "Value.name", "Value.displayName", "Value.longitude", "Value.latitude"}, {" ListAzureLocations.Name", " ListAzureLocations.Value.id", " ListAzureLocations.Value.name", " ListAzureLocations.Value.displayName", " ListAzureLocations.Value.longitude", " ListAzureLocations.Value.latitude"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListAzureLocations",{" ListAzureLocations.Name", " ListAzureLocations.Value.id"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{" ListAzureLocations.Value.name", "AzureLocation"}, {" ListAzureLocations.Value.displayName", "Azure Location Display Name"}, {" ListAzureLocations.Value.longitude", "Longitude"}, {" ListAzureLocations.Value.latitude", "Latitude"}}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Renamed Columns1", {"AzureLocation"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Removed Duplicates",{"SubscriptionId", "Subscription Name"})
|
||||
in
|
||||
#"Removed Columns1"
|
||||
|
||||
// ListAzureLocations
|
||||
let ListAzureLocations = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/locations?api-version=2016-06-01")),
|
||||
#"Converted to Table" = Record.ToTable(Source),
|
||||
#"Expanded Value" = Table.ExpandListColumn(#"Converted to Table", "Value"),
|
||||
#"Expanded Value1" = Table.ExpandRecordColumn(#"Expanded Value", "Value", {"id", "name", "displayName", "longitude", "latitude"}, {"Value.id", "Value.name", "Value.displayName", "Value.longitude", "Value.latitude"})
|
||||
in
|
||||
#"Expanded Value1"
|
||||
in
|
||||
ListAzureLocations
|
||||
|
||||
// All Subscriptions
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "subscriptionId", "displayName", "state", "subscriptionPolicies", "authorizationSource"}, {"id", "subscriptionId", "displayName", "state", "subscriptionPolicies", "authorizationSource"}),
|
||||
#"Expanded subscriptionPolicies" = Table.ExpandRecordColumn(#"Expanded Column1", "subscriptionPolicies", {"locationPlacementId", "quotaId", "spendingLimit"}, {"locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded subscriptionPolicies",{"id"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"displayName", "Subscription Name"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
|
||||
// LastRefresh_Local
|
||||
let
|
||||
Source = #table(type table[LastRefresh=datetime], {{DateTime.LocalNow()}}),
|
||||
#"Renamed Columns" = Table.RenameColumns(Source,{{"LastRefresh", "Refresh"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
|
||||
// TenantName
|
||||
"XXXXXXXX" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]
|
|
@ -0,0 +1,613 @@
|
|||
// All Subscriptions
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions?api-version=2020-01-01"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "authorizationSource", "managedByTenants", "subscriptionId", "tenantId", "displayName", "state", "subscriptionPolicies", "tags"}, {"id", "authorizationSource", "managedByTenants", "subscriptionId", "tenantId", "displayName", "state", "subscriptionPolicies", "tags"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column1",{"managedByTenants"}),
|
||||
#"Expanded subscriptionPolicies" = Table.ExpandRecordColumn(#"Removed Columns", "subscriptionPolicies", {"locationPlacementId", "quotaId", "spendingLimit"}, {"locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded subscriptionPolicies",{{"displayName", "Subscription Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns",{"tags"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns1",{{"id", "Subscription Resource Id"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// GetManagementURL
|
||||
let GetManagementBaseUri=(govKind as text) as text =>
|
||||
let
|
||||
managementUrl = if govKind ="us-government" then "https://management.usgovcloudapi.net"
|
||||
else if govKind="germany-government" then""
|
||||
else if govKind = "china" then ""
|
||||
else "https://management.azure.com"
|
||||
|
||||
in
|
||||
managementUrl
|
||||
|
||||
in GetManagementBaseUri
|
||||
|
||||
// AzureKind
|
||||
"global" meta [IsParameterQuery=true, List={"us-government", "global"}, DefaultValue="global", Type="Text", IsParameterQueryRequired=true]
|
||||
|
||||
// SecureScoreControls_F
|
||||
let
|
||||
Source = #"All Subscriptions",
|
||||
#"Removed Columns" = Table.RemoveColumns(Source,{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Reordered Columns" = Table.ReorderColumns(#"Removed Columns",{"tenantId", "Subscription Name", "subscriptionId"}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Reordered Columns", "SecuirtyScoreControls", each SecureScoreControls([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"SecuirtyScoreControls"}),
|
||||
#"Expanded SecuirtyScoreControls" = Table.ExpandTableColumn(#"Removed Errors", "SecuirtyScoreControls", {"id", "name", "displayName", "score.max", "score.current", "healthyResourceCount", "unhealthyResourceCount", "notApplicableResourceCount"}, {"id", "name", "displayName", "score.max", "score.current", "healthyResourceCount", "unhealthyResourceCount", "notApplicableResourceCount"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded SecuirtyScoreControls",{{"id", "SecureControl Id"}, {"name", "SecureControl Name"}, {"displayName", "SecureControl Display Name"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
|
||||
// SecureScoreControls
|
||||
let ListSecureScoreControls= (SubscriptionId as text) =>
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/providers/Microsoft.Security/SecureScoreControls?api-version=2020-01-01-preview"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "properties"}, {"id", "name", "type", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"displayName", "score", "healthyResourceCount", "unhealthyResourceCount", "notApplicableResourceCount"}, {"displayName", "score", "healthyResourceCount", "unhealthyResourceCount", "notApplicableResourceCount"}),
|
||||
#"Expanded score" = Table.ExpandRecordColumn(#"Expanded properties", "score", {"max", "current"}, {"score.max", "score.current"})
|
||||
in
|
||||
#"Expanded score"
|
||||
in ListSecureScoreControls
|
||||
|
||||
// SecureScore
|
||||
let
|
||||
Source = SecureScoreControls_F
|
||||
in
|
||||
Source
|
||||
|
||||
// SecureScoreControlsDefinitions
|
||||
let ListSecureScoreControlsDefinitions = (SubscriptionId as text) =>
|
||||
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/providers/Microsoft.Security/SecureScoreControlDefinitions?api-version=2020-01-01-preview"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "properties"}, {"id", "name", "type", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"displayName", "maxScore", "source", "assessmentsDefinition"}, {"displayName", "maxScore", "source", "assessmentsDefinition"}),
|
||||
#"Expanded source" = Table.ExpandRecordColumn(#"Expanded properties", "source", {"sourceType"}, {"sourceType"}),
|
||||
#"Expanded assessmentsDefinition" = Table.ExpandListColumn(#"Expanded source", "assessmentsDefinition")
|
||||
in
|
||||
#"Expanded assessmentsDefinition"
|
||||
|
||||
in
|
||||
ListSecureScoreControlsDefinitions
|
||||
|
||||
// SecureScoreControlDefinitions_F
|
||||
let
|
||||
Source = #"All Subscriptions",
|
||||
#"Removed Columns" = Table.RemoveColumns(Source,{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Reordered Columns" = Table.ReorderColumns(#"Removed Columns",{"tenantId", "Subscription Name", "subscriptionId"}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Reordered Columns", "SecureScoreControlDefinitions", each SecureScoreControlsDefinitions([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"SecureScoreControlDefinitions"}),
|
||||
#"Expanded SecureScoreControlDefinitions" = Table.ExpandTableColumn(#"Removed Errors", "SecureScoreControlDefinitions", {"id", "name", "displayName", "maxScore", "sourceType", "assessmentsDefinition"}, {"SecureScoreControlDefinitions.id", "SecureScoreControlDefinitions.name", "SecureScoreControlDefinitions.displayName", "SecureScoreControlDefinitions.maxScore", "SecureScoreControlDefinitions.sourceType", "SecureScoreControlDefinitions.assessmentsDefinition"}),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Expanded SecureScoreControlDefinitions", "SecureScoreControlDefinitions.id", Splitter.SplitTextByDelimiter("/providers", QuoteStyle.Csv), {"SecureScoreControlDefinitions.id.1", "SecureScoreControlDefinitions.id.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"SecureScoreControlDefinitions.id.1", type text}, {"SecureScoreControlDefinitions.id.2", type text}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Changed Type",{"SecureScoreControlDefinitions.id.1"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns2",{{"SecureScoreControlDefinitions.id.2", "SecureScoreControlDefinitions.id"}}),
|
||||
#"Changed Type1" = Table.TransformColumnTypes(#"Renamed Columns",{{"SecureScoreControlDefinitions.maxScore", type number}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Changed Type1", "SecureScoreControlDefinitions.assessmentsDefinition", "SecureScoreControlDefinitions.assessmentsDefinition - Copy"),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Duplicated Column", "SecureScoreControlDefinitions.assessmentsDefinition - Copy", Splitter.SplitTextByEachDelimiter({"/"}, QuoteStyle.Csv, true), {"SecureScoreControlDefinitions.assessmentsDefinition - Copy.1", "SecureScoreControlDefinitions.assessmentsDefinition - Copy.2"}),
|
||||
#"Changed Type2" = Table.TransformColumnTypes(#"Split Column by Delimiter1",{{"SecureScoreControlDefinitions.assessmentsDefinition - Copy.1", type text}, {"SecureScoreControlDefinitions.assessmentsDefinition - Copy.2", type text}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Changed Type2",{"SecureScoreControlDefinitions.assessmentsDefinition - Copy.1"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns1",{{"SecureScoreControlDefinitions.assessmentsDefinition - Copy.2", "Assesstment name"}}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Renamed Columns1", {"SecureScoreControlDefinitions.assessmentsDefinition"}),
|
||||
#"Removed Columns3" = Table.RemoveColumns(#"Removed Duplicates",{"tenantId", "Subscription Name", "subscriptionId"})
|
||||
in
|
||||
#"Removed Columns3"
|
||||
|
||||
// CC Applied Policies
|
||||
let
|
||||
Source = CcoDashboardAzureConnector.Management(AzureKind),
|
||||
policies = Source{[Key="policies"]}[Data],
|
||||
#"Expanded Value" = Table.ExpandTableColumn(policies, "Value", {"Column1"}, {"Column1"}),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Expanded Value", {"Column1"}),
|
||||
#"Expanded Column1" = Table.ExpandListColumn(#"Removed Errors", "Column1"),
|
||||
#"Expanded Column3" = Table.ExpandRecordColumn(#"Expanded Column1", "Column1", {"timestamp", "resourceId", "policyAssignmentId", "policyDefinitionId", "effectiveParameters", "isCompliant", "resourceType", "resourceLocation", "resourceGroup", "policyAssignmentName", "policyAssignmentOwner", "policyAssignmentParameters", "policyAssignmentScope", "policyDefinitionName", "policyDefinitionAction", "policyDefinitionCategory", "policySetDefinitionId", "policySetDefinitionName", "policySetDefinitionOwner", "policySetDefinitionCategory", "policySetDefinitionParameters", "managementGroupIds", "policyDefinitionReferenceId", "complianceState"}, {"timestamp", "resourceId", "policyAssignmentId", "policyDefinitionId", "effectiveParameters", "isCompliant", "resourceType", "resourceLocation", "resourceGroup", "policyAssignmentName", "policyAssignmentOwner", "policyAssignmentParameters", "policyAssignmentScope", "policyDefinitionName", "policyDefinitionAction", "policyDefinitionCategory", "policySetDefinitionId", "policySetDefinitionName", "policySetDefinitionOwner", "policySetDefinitionCategory", "policySetDefinitionParameters", "managementGroupIds", "policyDefinitionReferenceId", "complianceState"}),
|
||||
#"Filtered Rows1" = Table.SelectRows(#"Expanded Column3", each [timestamp] <> null and [timestamp] <> ""),
|
||||
#"Lowercased Text" = Table.TransformColumns(#"Filtered Rows1",{{"policyAssignmentScope", Text.Lower, type text}}),
|
||||
#"Added Custom" = Table.AddColumn(#"Lowercased Text", "Policy Image", each "https://raw.githubusercontent.com/CristianEdwards/ccodashboard/master/docs/assets/2020_Icons/Policy.svg"),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Added Custom", "ComplianceState Number", each if [complianceState] = "Compliant" then 1 else 0),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Added Conditional Column1", "Policy Scope", each if Text.Contains([policyAssignmentScope], "managementgroup") then "Management Group" else if Text.Contains([policyAssignmentScope], "resourcegroup") then "Resource Group" else "Subscription")
|
||||
in
|
||||
#"Added Conditional Column"
|
||||
|
||||
// ListPolicySets
|
||||
let listPolicySets = (SubscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01")),
|
||||
#"Converted to Table" = Record.ToTable(Source)
|
||||
in
|
||||
#"Converted to Table"
|
||||
|
||||
in listPolicySets
|
||||
|
||||
// ListPolicyDefinitions
|
||||
let ListAllPolicies = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(GetManagementURL(AzureKind)&"/subscriptions/"&subscriptionId&"/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"properties", "id", "type", "name"}, {"properties", "id", "type", "name"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"displayName", "policyType", "mode", "description", "metadata", "policyRule", "parameters"}, {"displayName", "policyType", "mode", "description", "metadata", "policyRule", "parameters"}),
|
||||
#"Expanded metadata" = Table.ExpandRecordColumn(#"Expanded properties", "metadata", {"category", "additionalMetadataId", "preview", "deprecated", "requiredProviders"}, {"metadata.category", "metadata.additionalMetadataId", "metadata.preview", "metadata.deprecated", "metadata.requiredProviders"}),
|
||||
#"Expanded parameters" = Table.ExpandRecordColumn(#"Expanded metadata", "parameters", {"effect"}, {"parameters.effect"}),
|
||||
#"Expanded parameters.effect" = Table.ExpandRecordColumn(#"Expanded parameters", "parameters.effect", {"defaultValue"}, {"parameters.effect.defaultValue"})
|
||||
in
|
||||
#"Expanded parameters.effect"
|
||||
in
|
||||
ListAllPolicies
|
||||
|
||||
// PolicyDefinitions
|
||||
let
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"All Subscriptions", "Definitions", each ListPolicyDefinitions([subscriptionId])),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Invoked Custom Function",{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Removed Columns", {"Definitions"}),
|
||||
#"Expanded Definitions" = Table.ExpandTableColumn(#"Removed Errors", "Definitions", {"displayName", "policyType", "mode", "description", "metadata.category", "metadata.additionalMetadataId", "metadata.preview", "metadata.deprecated", "metadata.requiredProviders", "policyRule", "parameters.effect.defaultValue", "id", "type", "name"}, {"Definitions.displayName", "Definitions.policyType", "Definitions.mode", "Definitions.description", "Definitions.metadata.category", "Definitions.metadata.additionalMetadataId", "Definitions.metadata.preview", "Definitions.metadata.deprecated", "Definitions.metadata.requiredProviders", "Definitions.policyRule", "Definitions.parameters.effect.defaultValue", "Definitions.id", "Definitions.type", "Definitions.name"}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Expanded Definitions",null,false,Replacer.ReplaceValue,{"Definitions.metadata.preview"}),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Replaced Value",null,false,Replacer.ReplaceValue,{"Definitions.metadata.deprecated"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Replaced Value1", {"Definitions.id"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Duplicates", "Preview?", each if [Definitions.metadata.preview] = false then 0 else 1),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Added Conditional Column", "Deprecated", each if [Definitions.metadata.deprecated] = false then 0 else 1),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Added Conditional Column1",{{"Deprecated", Int64.Type}, {"Preview?", Int64.Type}}),
|
||||
#"Added Conditional Column2" = Table.AddColumn(#"Changed Type", "Image", each if [Definitions.displayName] <> null then "https://raw.githubusercontent.com/josunefon/ccodashboard/master/install/DI_Images/Azure_Policy.png" else "https://raw.githubusercontent.com/josunefon/ccodashboard/master/install/DI_Images/Azure_Policy.png")
|
||||
in
|
||||
#"Added Conditional Column2"
|
||||
|
||||
// AllBuiltInPoliciesDefinition
|
||||
let
|
||||
Source = Json.Document(Web.Contents(GetManagementURL(AzureKind)&"/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"properties", "id", "name"}, {"properties", "id", "name"}),
|
||||
#"Reordered Columns" = Table.ReorderColumns(#"Expanded Column1",{"id", "name", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Reordered Columns", "properties", {"displayName", "policyType", "mode", "description", "metadata"}, {"displayName", "policyType", "mode", "description", "metadata"}),
|
||||
#"Expanded metadata" = Table.ExpandRecordColumn(#"Expanded properties", "metadata", {"version", "category", "deprecated", "preview"}, {"version", "category", "deprecated", "preview"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded metadata",{{"id", "Policy Definition Id"}, {"name", "Policy Name"}, {"displayName", "Policy DisplayName"}}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Renamed Columns", each ([policyType] = "BuiltIn")),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Filtered Rows", "Image", each if [category] = "Key Vault" then "https://azure.github.io/ccodashboard/assets/2020_Icons/KeyVaults.svg" else if [category] = "Storage" then "https://azure.github.io/ccodashboard/assets/2020_Icons/StorageAccounts.svg" else if [category] = "SQL" then "https://azure.github.io/ccodashboard/assets/2020_Icons/SQLdatabases.svg" else if [category] = "Compute" then "https://azure.github.io/ccodashboard/assets/2020_Icons/VirtualMachines.svg" else if [category] = "Security Center" then "https://azure.github.io/ccodashboard/assets/2020_Icons/SecurityCenter.svg" else if [category] = "App Service" then "https://azure.github.io/ccodashboard/assets/2020_Icons/AppServices.svg" else if [category] = "Logic Apps" then "https://azure.github.io/ccodashboard/assets/2020_Icons/LogicApps.svg" else if [category] = "Monitoring" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Monitor.svg" else if [category] = "Guest Configuration" then "https://azure.github.io/ccodashboard/assets/2020_Icons/GuestConfig.svg" else if [category] = "Data Lake" then "https://azure.github.io/ccodashboard/assets/2020_Icons/DataLake.svg" else if [category] = "Backup" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Backup.svg" else if [category] = "Cognitive Services" then "https://azure.github.io/ccodashboard/assets/2020_Icons/CognitiveServices.svg" else if [category] = "Cosmos DB" then "https://azure.github.io/ccodashboard/assets/2020_Icons/AzureCosmosDB.svg" else if [category] = "Tags" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Tags.svg" else if [category] = "Service Fabric" then "https://azure.github.io/ccodashboard/assets/2020_Icons/ServiceFabric.svg" else if [category] = "General" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Subscriptions.svg" else if [category] = "Managed Application" then "https://azure.github.io/ccodashboard/assets/2020_Icons/ManagedApplications.svg" else if [category] = "Network" then "https://azure.github.io/ccodashboard/assets/2020_Icons/VirtualNetworks.svg" else if [category] = "Automation" then "https://azure.github.io/ccodashboard/assets/2020_Icons/AutomationAccounts.svg" else if [category] = "Internet of Things" then "https://azure.github.io/ccodashboard/assets/2020_Icons/IoT.svg" else if [category] = "Event Grid" then "https://azure.github.io/ccodashboard/assets/2020_Icons/EventGrid.svg" else if [category] = "Search" then "https://azure.github.io/ccodashboard/assets/2020_Icons/SearchServices.svg" else if [category] = "App Configuration" then "https://azure.github.io/ccodashboard/assets/2020_Icons/AppConfiguration.svg" else if [category] = "App Platform" then "https://azure.github.io/ccodashboard/assets/2020_Icons/AzureSpringCloud.svg" else if [category] = "Cache" then "https://azure.github.io/ccodashboard/assets/2020_Icons/AzureCacheRedis.svg" else if [category] = "Batch" then "https://azure.github.io/ccodashboard/assets/2020_Icons/BatchAccounts.svg" else if [category] = "Container Registry" then "https://azure.github.io/ccodashboard/assets/2020_Icons/ContainerRegistries.svg" else if [category] = "Lighthouse" then "https://azure.github.io/ccodashboard/assets/2020_Icons/AzureLighthouse.svg" else if [category] = "Event Hub" then "https://azure.github.io/ccodashboard/assets/2020_Icons/EventHubs.svg" else if [category] = "Service Bus" then "https://azure.github.io/ccodashboard/assets/2020_Icons/ServiceBus.svg" else if [category] = "Custom Provider" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Resource.svg" else if [category] = "API Management" then "https://azure.github.io/ccodashboard/assets/2020_Icons/APIManagement.svg" else if [category] = "Kubernetes" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Kubernetesservices.svg" else if [category] = "Kubernetes service" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Kubernetesservices.svg" else if [category] = "Machine Learning" then "https://azure.github.io/ccodashboard/assets/2020_Icons/MachineLearning.svg" else if [category] = "Stream Analytics" then "https://azure.github.io/ccodashboard/assets/2020_Icons/StreamAnalytics.svg" else null)
|
||||
in
|
||||
#"Added Conditional Column"
|
||||
|
||||
// ListResourcesFinal
|
||||
let ListResources= (SubscriptionId as text) =>
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/resources?api-version=2019-05-01"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "location", "tags"}, {"id", "name", "type", "location", "tags"}),
|
||||
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Expanded Column2", "IsTagged", each if [tags] = null then "Untagged" else if [tags] = [] then "Untagged" else "Tagged"),
|
||||
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Added Conditional Column",{"tags"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns1",{{"id", "Resource Id"}, {"name", "Resource Name"}, {"type", "Resource Type"}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns", "Resource Id", "Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Id - Copy", Splitter.SplitTextByDelimiter("/providers", QuoteStyle.Csv), {"Resource Id - Copy.1", "Resource Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Id - Copy.1", type text}, {"Resource Id - Copy.2", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"Resource Id - Copy.2"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"Resource Id - Copy.1", "Resource Group Id"}}),
|
||||
#"Duplicated Column1" = Table.DuplicateColumn(#"Renamed Columns1", "Resource Group Id", "Resource Group Id - Copy"),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Duplicated Column1", "Resource Group Id - Copy", Splitter.SplitTextByEachDelimiter({"/"}, QuoteStyle.Csv, true), {"Resource Group Id - Copy.1", "Resource Group Id - Copy.2"}),
|
||||
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter1",{{"Resource Group Id - Copy.1", type text}, {"Resource Group Id - Copy.2", type text}}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Changed Type1",{{"Resource Group Id - Copy.2", "Resource Group Name"}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Renamed Columns2",{"Resource Group Id - Copy.1"})
|
||||
in
|
||||
#"Removed Columns2"
|
||||
in
|
||||
ListResources
|
||||
|
||||
// Resources
|
||||
let
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"All Subscriptions", "ListOfResources", each ListResourcesFinal([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListOfResources"}),
|
||||
#"Expanded ListOfResources" = Table.ExpandTableColumn(#"Removed Errors", "ListOfResources", {"Resource Id", "Resource Name", "Resource Type", "location", "IsTagged", "Resource Group Id", "Resource Group Name"}, {"Resource Id", "Resource Name", "Resource Type", "location", "IsTagged", "Resource Group Id", "Resource Group Name"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Expanded ListOfResources", each [Resource Id] <> null and [Resource Id] <> ""),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Filtered Rows", "IsTagged?", each if [IsTagged] = "Tagged" then 1 else 0),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Added Conditional Column", "Resource Type", "Resource Type - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Type - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"Resource Type - Copy.1", "Resource Type - Copy.2", "Resource Type - Copy.3"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Type - Copy.1", type text}, {"Resource Type - Copy.2", type text}, {"Resource Type - Copy.3", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"Resource Type - Copy.1", "Resource Type - Copy.3"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"Resource Type - Copy.2", "Resource Type for Usage"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"})
|
||||
in
|
||||
#"Removed Columns1"
|
||||
|
||||
// ListAssessments
|
||||
let ListAllAssesssments = (SubscriptionId as text) =>
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/providers/Microsoft.Security/assessments?api-version=2020-01-01"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"type", "id", "name", "properties"}, {"type", "id", "name", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"resourceDetails", "displayName", "status", "additionalData"}, {"resourceDetails", "displayName", "status", "additionalData"}),
|
||||
#"Expanded resourceDetails" = Table.ExpandRecordColumn(#"Expanded properties", "resourceDetails", {"Source", "Id"}, {"resourceDetails.Source", "resourceDetails.Id"}),
|
||||
#"Expanded status" = Table.ExpandRecordColumn(#"Expanded resourceDetails", "status", {"code", "cause", "description"}, {"status.code", "status.cause", "status.description"})
|
||||
in
|
||||
#"Expanded status"
|
||||
in ListAllAssesssments
|
||||
|
||||
// ASC_Assessments
|
||||
let
|
||||
Source = #"All Subscriptions",
|
||||
#"Removed Columns" = Table.RemoveColumns(Source,{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Reordered Columns" = Table.ReorderColumns(#"Removed Columns",{"tenantId", "Subscription Name", "subscriptionId"}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Reordered Columns", "Assesstments", each ListAssessments([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"Assesstments"}),
|
||||
#"Expanded Assesstments" = Table.ExpandTableColumn(#"Removed Errors", "Assesstments", {"id", "name", "resourceDetails.Source", "resourceDetails.Id", "displayName", "status.code", "status.cause", "status.description"}, {"Assesstments.id", "Assesstments.name", "Assesstments.resourceDetails.Source", "Assesstments.resourceDetails.Id", "Assesstments.displayName", "Assesstments.status.code", "Assesstments.status.cause", "Assesstments.status.description"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded Assesstments", "Assesstments.id", "Assesstments.id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Assesstments.id - Copy", Splitter.SplitTextByDelimiter("providers", QuoteStyle.Csv), {"Assesstments.id - Copy.1", "Assesstments.id - Copy.2", "Assesstments.id - Copy.3"}),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Split Column by Delimiter", "Assessment Id Final", each if [#"Assesstments.id - Copy.3"] = null then [#"Assesstments.id - Copy.2"] else [#"Assesstments.id - Copy.3"]),
|
||||
#"Removed Columns3" = Table.RemoveColumns(#"Added Conditional Column1",{"Assesstments.id - Copy.2", "Assesstments.id - Copy.3", "Assesstments.id - Copy.1"}),
|
||||
#"Lowercased Text" = Table.TransformColumns(#"Removed Columns3",{{"Assesstments.resourceDetails.Id", Text.Lower, type text}}),
|
||||
#"Duplicated Column1" = Table.DuplicateColumn(#"Lowercased Text", "Assesstments.resourceDetails.Id", "Assesstments.resourceDetails.Id - Copy"),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Duplicated Column1", "Assesstments.resourceDetails.Id - Copy", Splitter.SplitTextByEachDelimiter({"/"}, QuoteStyle.Csv, true), {"Assesstments.resourceDetails.Id - Copy.1", "Assesstments.resourceDetails.Id - Copy.2"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Split Column by Delimiter1",{{"Assesstments.resourceDetails.Id - Copy.2", "ResourceName"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"Assesstments.resourceDetails.Id - Copy.1"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Columns1", "ResourceScore", each if [Assesstments.status.code] = "Unhealthy" then 1 else if [Assesstments.status.code] = "NotApplicable" then 10 else 0),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Added Conditional Column",{"Assesstments.id"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Removed Columns2", each ([Assesstments.resourceDetails.Source] = "Azure")),
|
||||
#"Added Conditional Column2" = Table.AddColumn(#"Filtered Rows", "Image", each if [Assesstments.status.code] = "Healthy" then "https://azure.github.io/ccodashboard/assets/pictures/checkmark.svg" else if [Assesstments.status.code] = "NotApplicable" then "https://azure.github.io/ccodashboard/assets/pictures/crossout.svg" else "https://azure.github.io/ccodashboard/assets/pictures/crossout.svg")
|
||||
in
|
||||
#"Added Conditional Column2"
|
||||
|
||||
// assessmentMetadata_F
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/providers/Microsoft.Security/assessmentMetadata?api-version=2020-01-01"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Converted to Table", {"Column1"}),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Removed Errors", "Column1", {"id", "name", "type", "properties"}, {"id", "name", "type", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"displayName", "assessmentType", "policyDefinitionId", "description", "remediationDescription", "categories", "preview", "severity", "userImpact", "implementationEffort", "threats"}, {"displayName", "assessmentType", "policyDefinitionId", "description", "remediationDescription", "categories", "preview", "severity", "userImpact", "implementationEffort", "threats"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded properties", {"categories", each Text.Combine(List.Transform(_, Text.From), ","), type text}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Extracted Values", {"threats", each Text.Combine(List.Transform(_, Text.From), ","), type text})
|
||||
in
|
||||
#"Extracted Values1"
|
||||
|
||||
// Blueprints
|
||||
let
|
||||
Source = CcoDashboardAzureConnector.Management(AzureKind),
|
||||
blueprints = Source{[Key="blueprints"]}[Data],
|
||||
#"Removed Columns" = Table.RemoveColumns(blueprints,{"id", "tenantId", "countryCode", "displayName", "domains", "tenantCategory", "ManagementGroups.count"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns", {"scopeId"}),
|
||||
#"Expanded Blueprints" = Table.ExpandTableColumn(#"Removed Duplicates", "Blueprints", {"Column1"}, {"Column1"}),
|
||||
#"Expanded Column1" = Table.ExpandListColumn(#"Expanded Blueprints", "Column1"),
|
||||
#"Expanded Column2" = Table.ExpandRecordColumn(#"Expanded Column1", "Column1", {"properties", "id", "name"}, {"properties", "id", "name"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Expanded Column2", each [id] <> null and [id] <> ""),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Filtered Rows",{{"id", "Blueprint Id"}, {"name", "Blueprint Custom Name"}}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Renamed Columns", "properties", {"targetScope", "status", "displayName", "description"}, {"targetScope", "status", "displayName", "description"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded properties",{{"displayName", "Blueprint Official Name"}}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Renamed Columns1",null,"Custom Blueprint",Replacer.ReplaceValue,{"Blueprint Official Name"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Replaced Value",{{"description", "Blueprint Descriptions"}}),
|
||||
#"Expanded status" = Table.ExpandRecordColumn(#"Renamed Columns2", "status", {"timeCreated", "lastModified"}, {"timeCreated", "lastModified"}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Expanded status",{{"scopeId", "Blueprint Store and Scope"}}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Renamed Columns3", "Store Type", each if Text.Contains([Blueprint Store and Scope], "managementGroups") then "Management Group" else "Subscription"),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Added Conditional Column", "Img", each if [Store Type] = "Subscription" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Subscriptions.svg" else "https://azure.github.io/ccodashboard/assets/2020_Icons/ManagementGroups.svg")
|
||||
in
|
||||
#"Added Conditional Column1"
|
||||
|
||||
// Published Blueprints
|
||||
let
|
||||
Source = CcoDashboardAzureConnector.Management(AzureKind),
|
||||
blueprintspublished = Source{[Key="blueprintspublished"]}[Data],
|
||||
#"Renamed Columns" = Table.RenameColumns(blueprintspublished,{{"id.1", "Published Blueprint Version Id"}, {"description", "Published Blueprint Description"}, {"name.2", "Published Blueprint Version"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns",{"parameters", "resourceGroups"}),
|
||||
#"Expanded status" = Table.ExpandRecordColumn(#"Removed Columns", "status", {"timeCreated", "lastModified"}, {"timeCreated", "lastModified"}),
|
||||
#"Removed Columns3" = Table.RemoveColumns(#"Expanded status",{"properties"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Removed Columns3",{"Name.1"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns1",{{"id", "Blueprint Id"}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Renamed Columns1",{"type.1"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns2", {"Blueprint Id"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Removed Duplicates",{{"displayName.1", "Blueprint Portal Name"}}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Renamed Columns2",{{"scopeId", "Blueprint Store"}}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Renamed Columns3",null,"NOT PUBLISHED",Replacer.ReplaceValue,{"blueprintName"}),
|
||||
#"Renamed Columns4" = Table.RenameColumns(#"Replaced Value",{{"blueprintName", "Published Blueprint Name"}}),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Renamed Columns4",null,"Draft",Replacer.ReplaceValue,{"Published Blueprint Version"})
|
||||
in
|
||||
#"Replaced Value1"
|
||||
|
||||
// Blueprint Artifacts
|
||||
let
|
||||
Source = CcoDashboardAzureConnector.Management(AzureKind),
|
||||
blueprintartifact = Source{[Key="blueprintartifact"]}[Data],
|
||||
#"Renamed Columns" = Table.RenameColumns(blueprintartifact,{{"id.1", "Blueprint Artifact Id"}, {"name.1", "Blueprint Artifact Name"}, {"id", "Blueprint Id"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns",{"tenantId", "displayName", "scopeId", "properties", "type"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"name", "Blueprint Custom Name"}}),
|
||||
#"Expanded properties.1" = Table.ExpandRecordColumn(#"Renamed Columns1", "properties.1", {"policyDefinitionId"}, {"policyDefinitionId"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded properties.1",{"type.1"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Columns1", "Img", each if [kind] = "policyAssignment" then "https://azure.github.io/ccodashboard/assets/2020_Icons/Policy.svg" else if [kind] = "template" then "https://azure.github.io/ccodashboard/assets/2020_Icons/BlueprintTemplateKind.svg" else if [kind] = "roleAssignment" then "https://azure.github.io/ccodashboard/assets/2020_Icons/BlueprintRoleContributorKind.svg" else null),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Added Conditional Column", each [Blueprint Artifact Id] <> null and [Blueprint Artifact Id] <> "")
|
||||
in
|
||||
#"Filtered Rows"
|
||||
|
||||
// ListBlueprintAssignments
|
||||
let ListBlueprintAssignments = (SubscriptionId as text) =>
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/providers/Microsoft.Blueprint/blueprintAssignments?api-version=2018-11-01-preview"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"identity", "location", "properties", "id", "name"}, {"identity", "location", "properties", "id", "name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded Column1",{{"id", "Assigned Blueprint Id"}, {"name", "Assigned Blueprint Name"}}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Renamed Columns1", "properties", {"provisioningState", "blueprintId", "parameters", "resourceGroups", "status", "scope", "locks"}, {"provisioningState", "blueprintId", "parameters", "resourceGroups", "status", "scope", "locks"})
|
||||
in
|
||||
#"Expanded properties"
|
||||
in
|
||||
ListBlueprintAssignments
|
||||
|
||||
// Resource Groups
|
||||
let
|
||||
Source = #"All Subscriptions",
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"All Subscriptions", "ListOfResourceGroups", each ListResourceGroups([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListOfResourceGroups"}),
|
||||
#"Expanded ListOfResourceGroups" = Table.ExpandTableColumn(#"Removed Errors", "ListOfResourceGroups", {"Resource Group Id", "Resource Group Name", "type", "location", "IsTagged"}, {"Resource Group Id", "Resource Group Name", "type", "location", "IsTagged"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Expanded ListOfResourceGroups", "IsTaggedNumeric", each if [IsTagged] = "Tagged" then 1 else 0),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Added Conditional Column",{{"IsTaggedNumeric", "IsTagged?"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// ListResourceGroups
|
||||
let ListResourceGroups = (SubscriptionId as text) =>
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/resourcegroups?api-version=2019-05-01"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "location", "tags"}, {"id", "name", "type", "location", "tags"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"id", "Resource Group Id"}, {"name", "Resource Group Name"}}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Renamed Columns", "IsTagged", each if [tags] = null then "Untagged" else if [tags] = [] then "Untagged" else "Tagged"),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Added Conditional Column",{"tags"})
|
||||
in
|
||||
#"Removed Columns"
|
||||
|
||||
in
|
||||
ListResourceGroups
|
||||
|
||||
// TaggedResourceGroups
|
||||
let
|
||||
Source = #"All Subscriptions",
|
||||
#"Removed Columns" = Table.RemoveColumns(Source,{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Removed Columns", "ListResourceGroupsTags", each ListResourceGroupsTags([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListResourceGroupsTags"}),
|
||||
#"Expanded ListResourceGroupsTags" = Table.ExpandTableColumn(#"Removed Errors", "ListResourceGroupsTags", {"id", "TagKey", "TagValue"}, {"id", "TagKey", "TagValue"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded ListResourceGroupsTags", "id", "Resource Group Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Group Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"Resource Group Id - Copy.1", "Resource Group Id - Copy.2", "Resource Group Id - Copy.3", "Resource Group Id - Copy.4", "Resource Group Id - Copy.5"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Group Id - Copy.1", type text}, {"Resource Group Id - Copy.2", type text}, {"Resource Group Id - Copy.3", type text}, {"Resource Group Id - Copy.4", type text}, {"Resource Group Id - Copy.5", type text}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Changed Type",{"Resource Group Id - Copy.1", "Resource Group Id - Copy.2", "Resource Group Id - Copy.3"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns1",{{"Resource Group Id - Copy.4", "Resource Type"}, {"Resource Group Id - Copy.5", "Resource Group Name"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
|
||||
// ListResourceGroupsTags
|
||||
let ListResourceGroupsTags = (SubscriptionId as text) =>
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/resourcegroups?api-version=2019-05-01"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name","tags"}, {"id", "name","tags"}),
|
||||
ColumnContents = Table.Column(#"Expanded Column1", "tags"),
|
||||
ColumnsToExpand = List.Distinct(List.Combine(List.Transform(ColumnContents, each if _ is record then Record.FieldNames(_) else {}))),
|
||||
#"Expanded tags"= Table.ExpandRecordColumn(#"Expanded Column1", "tags", ColumnsToExpand, ColumnsToExpand),
|
||||
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Expanded tags", {"id", "name"}, "Attribute", "Value"),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Unpivoted Other Columns",{{"Attribute", "TagKey"}, {"Value", "TagValue"}, {"name", "Resource Name"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
in
|
||||
ListResourceGroupsTags
|
||||
|
||||
// GetGraphURL
|
||||
let GetGraphBaseUri=(govKind as text) as text =>
|
||||
let
|
||||
GraphURL = if govKind ="us-government" then "https://graph.microsoft.us"
|
||||
else if govKind="germany-government" then""
|
||||
else if govKind = "china" then ""
|
||||
else "https://graph.windows.net"
|
||||
|
||||
in
|
||||
GraphURL
|
||||
|
||||
in GetGraphBaseUri
|
||||
|
||||
// CC GetEntities
|
||||
let
|
||||
Source = CcoDashboardAzureConnector.Management(AzureKind),
|
||||
alldescendantstrick = Source{[Key="alldescendantstrick"]}[Data],
|
||||
#"Expanded ManagementGroups" = Table.ExpandRecordColumn(alldescendantstrick, "ManagementGroups", {"value"}, {"value"}),
|
||||
#"Expanded value" = Table.ExpandListColumn(#"Expanded ManagementGroups", "value"),
|
||||
#"Expanded value1" = Table.ExpandRecordColumn(#"Expanded value", "value", {"name", "id", "type", "properties"}, {"name", "id.1", "type", "properties"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded value1",{{"id.1", "Resource Id"}}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Renamed Columns", each [name] <> null and [name] <> ""),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Filtered Rows",{{"name", "Resource Name"}, {"type", "Resource Type"}}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Renamed Columns1", "properties", {"numberOfChildren", "numberOfChildGroups", "numberOfDescendants", "displayName", "parentDisplayNameChain", "inheritedPermissions", "permissions"}, {"numberOfChildren", "numberOfChildGroups", "numberOfDescendants", "displayName.1", "parentDisplayNameChain", "inheritedPermissions", "permissions"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Expanded properties",{{"displayName.1", "Resource Display Name"}}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Renamed Columns2", {"parentDisplayNameChain", each Text.Combine(List.Transform(_, Text.From), "/"), type text}),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Extracted Values", "parentDisplayNameChain", Splitter.SplitTextByEachDelimiter({"/"}, QuoteStyle.Csv, true), {"parentDisplayNameChain.1", "parentDisplayNameChain.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"parentDisplayNameChain.1", type text}, {"parentDisplayNameChain.2", type text}}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Changed Type", "TempParentDisplayName", each if [parentDisplayNameChain.1] = "" then "IsRoot" else [parentDisplayNameChain.2]),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Added Conditional Column", "Parent Display Name", each if [TempParentDisplayName] = null then [parentDisplayNameChain.1] else [TempParentDisplayName]),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Added Conditional Column1",{"parentDisplayNameChain.1", "parentDisplayNameChain.2", "TempParentDisplayName"}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Removed Columns1","Is Tenant Root Group",null,Replacer.ReplaceValue,{"Parent Display Name"}),
|
||||
#"Added Index" = Table.AddIndexColumn(#"Replaced Value", "Index", 1, 1),
|
||||
#"Added Conditional Column2" = Table.AddColumn(#"Added Index", "Image", each if [Resource Type] = "/providers/Microsoft.Management/managementGroups" then "https://azure.github.io/ccodashboard/assets/pictures/037_Management_Groups.svg" else "https://azure.github.io/ccodashboard/assets/pictures/036_ASCTasks_Subscription.svg"),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Added Conditional Column2","IsRoot",null,Replacer.ReplaceValue,{"Parent Display Name"})
|
||||
in
|
||||
#"Replaced Value1"
|
||||
|
||||
// ListAzureLocations
|
||||
let ListAzureLocations = (SubscriptionId as text) =>
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/locations?api-version=2020-01-01"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "displayName", "regionalDisplayName", "metadata"}, {"id", "name", "displayName", "regionalDisplayName", "metadata"}),
|
||||
#"Expanded metadata" = Table.ExpandRecordColumn(#"Expanded Column1", "metadata", {"regionType", "regionCategory", "geographyGroup", "longitude", "latitude", "physicalLocation", "pairedRegion"}, {"regionType", "regionCategory", "geographyGroup", "longitude", "latitude", "physicalLocation", "pairedRegion"}),
|
||||
#"Expanded pairedRegion" = Table.ExpandListColumn(#"Expanded metadata", "pairedRegion"),
|
||||
#"Expanded pairedRegion1" = Table.ExpandRecordColumn(#"Expanded pairedRegion", "pairedRegion", {"name", "id"}, {"name.1", "id.1"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded pairedRegion1",{{"id", "Location Id"}, {"name", "Location Name"}, {"displayName", "Location Display Name"}, {"regionalDisplayName", "Location regionalDisplayName"}, {"name.1", "Paired Region Name"}, {"id.1", "Paired Region Id"}}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Renamed Columns", each ([regionType] = "Physical"))
|
||||
in
|
||||
#"Filtered Rows"
|
||||
in
|
||||
ListAzureLocations
|
||||
|
||||
// Azure Regions
|
||||
let
|
||||
Source = #"All Subscriptions",
|
||||
#"Removed Columns" = Table.RemoveColumns(Source,{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Removed Columns", "ListAzureLocations", each ListAzureLocations([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListAzureLocations"}),
|
||||
#"Expanded ListAzureLocations" = Table.ExpandTableColumn(#"Removed Errors", "ListAzureLocations", {"Location Id", "Location Name", "Location Display Name", "Location regionalDisplayName", "regionType", "regionCategory", "geographyGroup", "longitude", "latitude", "physicalLocation", "Paired Region Name", "Paired Region Id"}, {"Location Id", "Location Name", "Location Display Name", "Location regionalDisplayName", "regionType", "regionCategory", "geographyGroup", "longitude", "latitude", "physicalLocation", "Paired Region Name", "Paired Region Id"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded ListAzureLocations",{"Subscription Resource Id", "subscriptionId", "Subscription Name", "Location Id", "tenantId"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns1", {"Location Name"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Removed Duplicates",{{"longitude", type number}, {"latitude", type number}})
|
||||
in
|
||||
#"Changed Type"
|
||||
|
||||
// Tagged Resources
|
||||
let
|
||||
Source = #"All Subscriptions",
|
||||
#"Removed Columns" = Table.RemoveColumns(Source,{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Removed Columns", "ListResourceTags", each ListResourceTags([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListResourceTags"}),
|
||||
#"Expanded ListResourceTags" = Table.ExpandTableColumn(#"Removed Errors", "ListResourceTags", {"id", "ResourceName", "TagKey", "TagValue"}, {"id", "ResourceName", "TagKey", "TagValue"})
|
||||
in
|
||||
#"Expanded ListResourceTags"
|
||||
|
||||
// ListResourceTags
|
||||
let ListResourceTags = (SubscriptionId as text) =>
|
||||
let
|
||||
GetPages = (Path)=>
|
||||
let
|
||||
Source = Json.Document(Web.Contents(Path)),
|
||||
LL= @Source[value],
|
||||
result = try @LL & @GetPages(Source[#"nextLink"]) otherwise @LL
|
||||
in
|
||||
result,
|
||||
Fullset = GetPages(GetManagementURL(AzureKind)&"/subscriptions/"&SubscriptionId&"/resources?api-version=2019-10-01"),
|
||||
#"Converted to Table" = Table.FromList(Fullset, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn( #"Converted to Table", "Column1", {"id", "name", "tags"}, {"id", "name", "tags"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded Column1",{{"name", "ResourceName"}}),
|
||||
ColumnContents = Table.Column(#"Renamed Columns1", "tags"),
|
||||
ColumnsToExpand = List.Distinct(List.Combine(List.Transform(ColumnContents, each if _ is record then Record.FieldNames(_) else {}))),
|
||||
#"Expanded tags"= Table.ExpandRecordColumn(#"Renamed Columns1", "tags", ColumnsToExpand, ColumnsToExpand),
|
||||
#"Unpivoted Other Columns" = Table.UnpivotOtherColumns(#"Expanded tags", {"id", "ResourceName"}, "Attribute", "Value"),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Unpivoted Other Columns",{{"Attribute", "TagKey"}, {"Value", "TagValue"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
|
||||
in
|
||||
ListResourceTags
|
||||
|
||||
// Blueprint Subscription Assignments
|
||||
let
|
||||
Source = #"All Subscriptions",
|
||||
#"Removed Columns" = Table.RemoveColumns(Source,{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Removed Columns", "Blueprint Assignments", each ListBlueprintAssignments([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"Blueprint Assignments"}),
|
||||
#"Expanded Blueprint Assignments" = Table.ExpandTableColumn(#"Removed Errors", "Blueprint Assignments", {"identity", "location", "provisioningState", "blueprintId", "parameters", "resourceGroups", "status", "scope", "locks", "Assigned Blueprint Id", "Assigned Blueprint Name"}, {"identity", "location", "provisioningState", "blueprintId", "parameters", "resourceGroups", "status", "scope", "locks", "Assigned Blueprint Id", "Assigned Blueprint Name"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Expanded Blueprint Assignments", "Img", each if [provisioningState] = "succeeded" then "https://azure.github.io/ccodashboard/assets/2020_Icons/AssignedBlueprints.svg" else "https://azure.github.io/ccodashboard/assets/2020_Icons/AssignedBlueprints.svg"),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Added Conditional Column",{{"blueprintId", "Published Blueprint version Id"}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns", "Published Blueprint version Id", "Published Blueprint version Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Published Blueprint version Id - Copy", Splitter.SplitTextByDelimiter("/versions/", QuoteStyle.Csv), {"Published Blueprint version Id - Copy.1", "Published Blueprint version Id - Copy.2"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Split Column by Delimiter",{{"Published Blueprint version Id - Copy.2", "Assigned Version"}}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Renamed Columns2",{{"Published Blueprint version Id - Copy.1", "Blueprint Id"}}),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Renamed Columns1", "StateIcon", each if [provisioningState] = "failed" then 0 else 1),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Added Conditional Column1",{{"StateIcon", Int64.Type}})
|
||||
in
|
||||
#"Changed Type"
|
||||
|
||||
// RegulatoryCompliancesPolicies
|
||||
let
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"All Subscriptions", "ListPolicySets", each ListPolicySets([subscriptionId])),
|
||||
#"Removed Columns5" = Table.RemoveColumns(#"Invoked Custom Function",{"authorizationSource", "state", "locationPlacementId", "quotaId", "spendingLimit"}),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Removed Columns5", {"ListPolicySets"}),
|
||||
#"Expanded ListPolicySets" = Table.ExpandTableColumn(#"Removed Errors", "ListPolicySets", {"Value"}, {"Value"}),
|
||||
#"Expanded Value" = Table.ExpandListColumn(#"Expanded ListPolicySets", "Value"),
|
||||
#"Expanded Value1" = Table.ExpandRecordColumn(#"Expanded Value", "Value", {"properties", "id", "name"}, {"properties", "id", "name"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Value1", "properties", {"displayName", "policyType", "description", "metadata", "policyDefinitions"}, {"displayName", "policyType", "description", "metadata", "policyDefinitions"}),
|
||||
#"Expanded metadata" = Table.ExpandRecordColumn(#"Expanded properties", "metadata", {"version", "category"}, {"version", "category"}),
|
||||
#"Expanded policyDefinitions" = Table.ExpandListColumn(#"Expanded metadata", "policyDefinitions"),
|
||||
#"Expanded policyDefinitions1" = Table.ExpandRecordColumn(#"Expanded policyDefinitions", "policyDefinitions", {"policyDefinitionReferenceId", "policyDefinitionId"}, {"policyDefinitionReferenceId", "policyDefinitionId"}),
|
||||
#"Duplicated Column1" = Table.DuplicateColumn(#"Expanded policyDefinitions1", "description", "description - Copy"),
|
||||
#"Split Column by Delimiter2" = Table.SplitColumn(#"Duplicated Column1", "description - Copy", Splitter.SplitTextByDelimiter("visit", QuoteStyle.Csv), {"description - Copy.1", "description - Copy.2"}),
|
||||
#"Changed Type2" = Table.TransformColumnTypes(#"Split Column by Delimiter2",{{"description - Copy.1", type text}, {"description - Copy.2", type text}}),
|
||||
#"Removed Columns4" = Table.RemoveColumns(#"Changed Type2",{"description - Copy.1"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns4",{{"description - Copy.2", "URL"}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns", "URL", "URL - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "URL - Copy", Splitter.SplitTextByDelimiter("https://aka.ms/", QuoteStyle.Csv), {"URL - Copy.1", "URL - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"URL - Copy.1", type text}, {"URL - Copy.2", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"URL - Copy.1"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Columns", "Regulatory Standard Name", each if [#"URL - Copy.2"] = null then [displayName] else [#"URL - Copy.2"]),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Added Conditional Column", each true),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Filtered Rows",{"URL - Copy.2"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns1",{{"id", "policySetDefinitionId"}, {"name", "policySetDefinitionName"}, {"displayName", "Regulatory Standard Long Name"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// LastRefresh_Local
|
||||
let
|
||||
Source = #table(type table[LastRefresh=datetime], {{DateTime.LocalNow()}}),
|
||||
#"Renamed Columns" = Table.RenameColumns(Source,{{"LastRefresh", "Refresh"}})
|
||||
in
|
||||
#"Renamed Columns"
|
|
@ -1,103 +0,0 @@
|
|||
// Network Interfaces
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListAllNICs", each ListAllNICs([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListAllNICs"}),
|
||||
#"Expanded ListAllNICs" = Table.ExpandTableColumn(#"Removed Errors", "ListAllNICs", {"name", "NIC Id", "location", "provisioningState", "resourceGuid", "dnsServers", "appliedDnsServers", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "NSG Id", "primary", "Virtual Machine Id", "type"}, {"name", "NIC Id", "location", "provisioningState", "resourceGuid", "dnsServers", "appliedDnsServers", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "NSG Id", "primary", "Virtual Machine Id", "type"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListAllNICs",{"subscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"name", "NIC Name"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// ListAllNICs
|
||||
let ListAllNICs = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Network/networkInterfaces?api-version=2017-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"name", "id", "etag", "location", "properties", "type"}, {"name", "id", "etag", "location", "properties", "type"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column1",{"etag"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Removed Columns", "properties", {"provisioningState", "resourceGuid", "ipConfigurations", "dnsSettings", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "networkSecurityGroup", "primary", "virtualMachine"}, {"provisioningState", "resourceGuid", "ipConfigurations", "dnsSettings", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "networkSecurityGroup", "primary", "virtualMachine"}),
|
||||
#"Expanded dnsSettings" = Table.ExpandRecordColumn(#"Expanded properties", "dnsSettings", {"dnsServers", "appliedDnsServers"}, {"dnsServers", "appliedDnsServers"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded dnsSettings", {"dnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Extracted Values", {"appliedDnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded networkSecurityGroup" = Table.ExpandRecordColumn(#"Extracted Values1", "networkSecurityGroup", {"id"}, {"id.1"}),
|
||||
#"Expanded virtualMachine" = Table.ExpandRecordColumn(#"Expanded networkSecurityGroup", "virtualMachine", {"id"}, {"id.2"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded virtualMachine",{"ipConfigurations"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns1",{{"id.1", "NSG Id"}, {"id.2", "Virtual Machine Id"}, {"id", "NIC Id"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
in
|
||||
ListAllNICs
|
||||
|
||||
// Network Interfaces Details
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListAllNICsDetails", each ListAllNICsDetails([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListAllNICsDetails"}),
|
||||
#"Expanded ListAllNICsDetails" = Table.ExpandTableColumn(#"Removed Errors", "ListAllNICsDetails", {"NIC Name", "NIC Id", "location", "provisioningState", "resourceGuid", "name.1", "id.3", "etag", "provisioningState.1", "privateIPAddress", "privateIPAllocationMethod", "Public IP Address ID", "Subnet Id", "primary.1", "privateIPAddressVersion", "isInUseWithService", "id.6", "dnsServers", "appliedDnsServers", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "NSG Id", "primary", "Virtual Machine Id", "type"}, {"NIC Name", "NIC Id", "location", "provisioningState", "resourceGuid", "name.1", "id.3", "etag", "provisioningState.1", "privateIPAddress", "privateIPAllocationMethod", "Public IP Address ID", "Subnet Id", "primary.1", "privateIPAddressVersion", "isInUseWithService", "id.6", "dnsServers", "appliedDnsServers", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "NSG Id", "primary", "Virtual Machine Id", "type"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListAllNICsDetails",{"subscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"id.3", "IP Configuration Id"}, {"primary.1", "isPrimary"}, {"id.6", "BackendAddressPool Id"}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns1", "Subnet Id", "Subnet Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Subnet Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"Subnet Id - Copy.1", "Subnet Id - Copy.2", "Subnet Id - Copy.3", "Subnet Id - Copy.4", "Subnet Id - Copy.5", "Subnet Id - Copy.6", "Subnet Id - Copy.7", "Subnet Id - Copy.8", "Subnet Id - Copy.9", "Subnet Id - Copy.10", "Subnet Id - Copy.11"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Subnet Id - Copy.1", type text}, {"Subnet Id - Copy.2", type text}, {"Subnet Id - Copy.3", type text}, {"Subnet Id - Copy.4", type text}, {"Subnet Id - Copy.5", type text}, {"Subnet Id - Copy.6", type text}, {"Subnet Id - Copy.7", type text}, {"Subnet Id - Copy.8", type text}, {"Subnet Id - Copy.9", type text}, {"Subnet Id - Copy.10", type text}, {"Subnet Id - Copy.11", type text}}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Changed Type",{{"Subnet Id - Copy.9", "VNET Name"}, {"Subnet Id - Copy.11", "Subnet Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns2",{"Subnet Id - Copy.10", "Subnet Id - Copy.4", "Subnet Id - Copy.5", "Subnet Id - Copy.6", "Subnet Id - Copy.7", "Subnet Id - Copy.8", "Subnet Id - Copy.1", "Subnet Id - Copy.2", "Subnet Id - Copy.3", "name.1"})
|
||||
in
|
||||
#"Removed Columns1"
|
||||
|
||||
// ListAllNICsDetails
|
||||
let ListAllNICsDetails = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Network/networkInterfaces?api-version=2017-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"name", "id", "etag", "location", "properties", "type"}, {"name", "id", "etag", "location", "properties", "type"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column1",{"etag"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Removed Columns", "properties", {"provisioningState", "resourceGuid", "ipConfigurations", "dnsSettings", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "networkSecurityGroup", "primary", "virtualMachine"}, {"provisioningState", "resourceGuid", "ipConfigurations", "dnsSettings", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "networkSecurityGroup", "primary", "virtualMachine"}),
|
||||
#"Expanded dnsSettings" = Table.ExpandRecordColumn(#"Expanded properties", "dnsSettings", {"dnsServers", "appliedDnsServers"}, {"dnsServers", "appliedDnsServers"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded dnsSettings", {"dnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Extracted Values", {"appliedDnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded networkSecurityGroup" = Table.ExpandRecordColumn(#"Extracted Values1", "networkSecurityGroup", {"id"}, {"id.1"}),
|
||||
#"Expanded virtualMachine" = Table.ExpandRecordColumn(#"Expanded networkSecurityGroup", "virtualMachine", {"id"}, {"id.2"}),
|
||||
#"Expanded ipConfigurations" = Table.ExpandListColumn(#"Expanded virtualMachine", "ipConfigurations"),
|
||||
#"Expanded ipConfigurations1" = Table.ExpandRecordColumn(#"Expanded ipConfigurations", "ipConfigurations", {"name", "id", "etag", "properties"}, {"name.1", "id.3", "etag", "properties"}),
|
||||
#"Expanded properties1" = Table.ExpandRecordColumn(#"Expanded ipConfigurations1", "properties", {"provisioningState", "privateIPAddress", "privateIPAllocationMethod", "publicIPAddress", "subnet", "primary", "privateIPAddressVersion", "isInUseWithService", "loadBalancerBackendAddressPools"}, {"provisioningState.1", "privateIPAddress", "privateIPAllocationMethod", "publicIPAddress", "subnet", "primary.1", "privateIPAddressVersion", "isInUseWithService", "loadBalancerBackendAddressPools"}),
|
||||
#"Expanded publicIPAddress" = Table.ExpandRecordColumn(#"Expanded properties1", "publicIPAddress", {"id"}, {"id.4"}),
|
||||
#"Expanded subnet" = Table.ExpandRecordColumn(#"Expanded publicIPAddress", "subnet", {"id"}, {"id.5"}),
|
||||
#"Expanded loadBalancerBackendAddressPools" = Table.ExpandListColumn(#"Expanded subnet", "loadBalancerBackendAddressPools"),
|
||||
#"Expanded loadBalancerBackendAddressPools1" = Table.ExpandRecordColumn(#"Expanded loadBalancerBackendAddressPools", "loadBalancerBackendAddressPools", {"id"}, {"id.6"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded loadBalancerBackendAddressPools1",{{"id.4", "Public IP Address ID"}, {"id.5", "Subnet Id"}, {"id.1", "NSG Id"}, {"id.2", "Virtual Machine Id"}, {"id", "NIC Id"}, {"name", "NIC Name"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
in
|
||||
ListAllNICsDetails
|
||||
|
||||
// Containers NICs
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListAllNICsDetails", each ListAllNICsDetails([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListAllNICsDetails"}),
|
||||
#"Expanded ListAllNICsDetails" = Table.ExpandTableColumn(#"Removed Errors", "ListAllNICsDetails", {"NIC Name", "NIC Id", "location", "provisioningState", "resourceGuid", "name.1", "id.3", "etag", "provisioningState.1", "privateIPAddress", "privateIPAllocationMethod", "Public IP Address ID", "Subnet Id", "primary.1", "privateIPAddressVersion", "isInUseWithService", "id.6", "dnsServers", "appliedDnsServers", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "NSG Id", "primary", "Virtual Machine Id", "type"}, {"NIC Name", "NIC Id", "location", "provisioningState", "resourceGuid", "name.1", "id.3", "etag", "provisioningState.1", "privateIPAddress", "privateIPAllocationMethod", "Public IP Address ID", "Subnet Id", "primary.1", "privateIPAddressVersion", "isInUseWithService", "id.6", "dnsServers", "appliedDnsServers", "macAddress", "enableAcceleratedNetworking", "enableIPForwarding", "NSG Id", "primary", "Virtual Machine Id", "type"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListAllNICsDetails",{"subscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"id.3", "IP Configuration Id"}, {"primary.1", "isPrimary"}, {"id.6", "BackendAddressPool Id"}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns1", "Subnet Id", "Subnet Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Subnet Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"Subnet Id - Copy.1", "Subnet Id - Copy.2", "Subnet Id - Copy.3", "Subnet Id - Copy.4", "Subnet Id - Copy.5", "Subnet Id - Copy.6", "Subnet Id - Copy.7", "Subnet Id - Copy.8", "Subnet Id - Copy.9", "Subnet Id - Copy.10", "Subnet Id - Copy.11"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Subnet Id - Copy.1", type text}, {"Subnet Id - Copy.2", type text}, {"Subnet Id - Copy.3", type text}, {"Subnet Id - Copy.4", type text}, {"Subnet Id - Copy.5", type text}, {"Subnet Id - Copy.6", type text}, {"Subnet Id - Copy.7", type text}, {"Subnet Id - Copy.8", type text}, {"Subnet Id - Copy.9", type text}, {"Subnet Id - Copy.10", type text}, {"Subnet Id - Copy.11", type text}}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Changed Type",{{"Subnet Id - Copy.9", "VNET Name"}, {"Subnet Id - Copy.11", "Subnet Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns2",{"Subnet Id - Copy.10", "Subnet Id - Copy.4", "Subnet Id - Copy.5", "Subnet Id - Copy.6", "Subnet Id - Copy.7", "Subnet Id - Copy.8", "Subnet Id - Copy.1", "Subnet Id - Copy.2", "Subnet Id - Copy.3", "name.1"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns1", {"NIC Id"})
|
||||
in
|
||||
#"Removed Duplicates"
|
|
@ -1,42 +0,0 @@
|
|||
// Public IPs
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListPublicIPs", each ListPublicIPs([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListPublicIPs"}),
|
||||
#"Expanded ListPublicIPs" = Table.ExpandTableColumn(#"Removed Errors", "ListPublicIPs", {"Public IP Name", "Public IP Resource Id", "location", "provisioningState", "resourceGuid", "ipAddress", "publicIPAddressVersion", "publicIPAllocationMethod", "idleTimeoutInMinutes", "domainNameLabel", "fqdn", "ipTags", "IP Configuration Id", "type", "sku", "Resource Group Id"}, {"Public IP Name", "Public IP Resource Id", "location", "provisioningState", "resourceGuid", "ipAddress", "publicIPAddressVersion", "publicIPAllocationMethod", "idleTimeoutInMinutes", "domainNameLabel", "fqdn", "ipTags", "IP Configuration Id", "type", "sku", "Resource Group Id"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListPublicIPs",{"subscriptionId", "Subscription Name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"ipAddress", "Public IP Address"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// ListPublicIPs
|
||||
let ListPublicIPs = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Network/publicIPAddresses?api-version=2017-10-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"name", "id", "location", "properties", "type", "sku", "tags"}, {"name", "id", "location", "properties", "type", "sku", "tags"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"name", "Public IP Name"}, {"id", "Public IP Resource Id"}}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Renamed Columns", "properties", {"provisioningState", "resourceGuid", "ipAddress", "publicIPAddressVersion", "publicIPAllocationMethod", "idleTimeoutInMinutes", "dnsSettings", "ipTags", "ipConfiguration"}, {"provisioningState", "resourceGuid", "ipAddress", "publicIPAddressVersion", "publicIPAllocationMethod", "idleTimeoutInMinutes", "dnsSettings", "ipTags", "ipConfiguration"}),
|
||||
#"Expanded dnsSettings" = Table.ExpandRecordColumn(#"Expanded properties", "dnsSettings", {"domainNameLabel", "fqdn"}, {"domainNameLabel", "fqdn"}),
|
||||
#"Expanded ipTags" = Table.ExpandListColumn(#"Expanded dnsSettings", "ipTags"),
|
||||
#"Expanded ipConfiguration" = Table.ExpandRecordColumn(#"Expanded ipTags", "ipConfiguration", {"id"}, {"id"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded ipConfiguration",{{"id", "IP Configuration Id"}}),
|
||||
#"Expanded sku" = Table.ExpandRecordColumn(#"Renamed Columns1", "sku", {"name"}, {"name"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Expanded sku",{{"name", "sku"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns2",{"tags"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Removed Columns", "Public IP Resource Id", "Public IP Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Public IP Resource Id - Copy", Splitter.SplitTextByDelimiter("/providers", QuoteStyle.Csv), {"Public IP Resource Id - Copy.1", "Public IP Resource Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Public IP Resource Id - Copy.1", type text}, {"Public IP Resource Id - Copy.2", type text}}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Changed Type",{{"Public IP Resource Id - Copy.1", "Resource Group Id"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns3",{"Public IP Resource Id - Copy.2"})
|
||||
in
|
||||
#"Removed Columns1"
|
||||
|
||||
|
||||
in
|
||||
ListPublicIPs
|
|
@ -1,87 +0,0 @@
|
|||
// ListRBACRoleAssignments
|
||||
let ListRBACRoleAssignments = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Authorization/roleAssignments?api-version=2015-07-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"properties", "id", "type", "name"}, {"properties", "id", "type", "name"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy"}, {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy"})
|
||||
in
|
||||
#"Expanded properties"
|
||||
|
||||
in
|
||||
ListRBACRoleAssignments
|
||||
|
||||
// RBAC Role Definitions
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List RBACRoleDefinitions" = Table.AddColumn(#"Renamed Columns", "ListRBACRoleDefinitions", each ListRBACRoleDefinitions([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List RBACRoleDefinitions", {"ListRBACRoleDefinitions"}),
|
||||
#"Expanded ListRBACRoleDefinitions" = Table.ExpandTableColumn(#"Removed Errors", "ListRBACRoleDefinitions", {"roleName", "type.1", "description", "assignableScopes", "actions", "notActions", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}, {"roleName", "type.1", "description", "assignableScopes", "actions", "notActions", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded ListRBACRoleDefinitions",{{"type.1", "roleType"}, {"Column1.displayName", "Subscription Name"}, {"id", "roleDefinitionId"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns1",{"type"})
|
||||
in
|
||||
#"Removed Columns"
|
||||
|
||||
// ListRBACRoleDefinitions
|
||||
let ListRBACRoleDefinitions = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Authorization/roleDefinitions?api-version=2015-07-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"properties", "id", "type", "name"}, {"properties", "id", "type", "name"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"roleName", "type", "description", "assignableScopes", "permissions", "createdOn", "updatedOn", "createdBy", "updatedBy"}, {"roleName", "type.1", "description", "assignableScopes", "permissions", "createdOn", "updatedOn", "createdBy", "updatedBy"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded properties", {"assignableScopes", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded permissions" = Table.ExpandListColumn(#"Extracted Values", "permissions"),
|
||||
#"Expanded permissions1" = Table.ExpandRecordColumn(#"Expanded permissions", "permissions", {"actions", "notActions"}, {"actions", "notActions"}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Expanded permissions1", {"actions", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Extracted Values2" = Table.TransformColumns(#"Extracted Values1", {"notActions", each Text.Combine(List.Transform(_, Text.From)), type text})
|
||||
in
|
||||
#"Extracted Values2"
|
||||
in
|
||||
ListRBACRoleDefinitions
|
||||
|
||||
// RBAC Role Users
|
||||
// RBAC Role Assignments
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List RBACRoleAssignments" = Table.AddColumn(#"Renamed Columns", "ListRBACRoleAssignments", each ListRBACRoleAssignments([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List RBACRoleAssignments", {"ListRBACRoleAssignments"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Errors",{{"Column1.displayName", "Subscription Name"}}),
|
||||
#"Expanded ListRBACRoleAssignments" = Table.ExpandTableColumn(#"Renamed Columns1", "ListRBACRoleAssignments", {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}, {"roleDefinitionId", "principalId", "scope", "createdOn", "updatedOn", "createdBy", "updatedBy", "id", "type", "name"}),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Expanded ListRBACRoleAssignments", "scope", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"scope.1", "scope.2", "scope.3", "scope.4", "scope.5", "scope.6", "scope.7", "scope.8", "scope.9", "scope.10", "scope.11"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Split Column by Delimiter1",{{"scope.5", "Resource Group"}, {"scope.7", "Resource Provider"}, {"scope.8", "Resource Type"}, {"scope.9", "Resource Name"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns2",{"scope.1", "scope.2", "scope.3", "scope.4", "scope.6"}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Removed Columns",null,"*",Replacer.ReplaceValue,{"Resource Group"}),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Replaced Value",null,"*",Replacer.ReplaceValue,{"Resource Provider"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Replaced Value1", "Custom", each if [Resource Group] = "*" then "Subscription" else if [Resource Provider] = "*" then "Resource Group" else if [Resource Type] <> null then [Resource Type] else null),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Added Conditional Column",{{"Resource Type", "Rtype"}, {"Custom", "Resource Type"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns3", "Users", each ListRBACUsers([principalId])),
|
||||
#"Removed Errors1" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"Users"}),
|
||||
#"Expanded Users" = Table.ExpandTableColumn(#"Removed Errors1", "Users", {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "ageGroup", "city", "companyName", "consentProvidedForMinor", "country", "creationType", "department", "dirSyncEnabled", "displayName", "employeeId", "facsimileTelephoneNumber", "givenName", "immutableId", "isCompromised", "jobTitle", "lastDirSyncTime", "legalAgeGroupClassification", "mail", "mailNickname", "mobile", "onPremisesDistinguishedName", "onPremisesSecurityIdentifier", "passwordPolicies", "passwordProfile", "physicalDeliveryOfficeName", "postalCode", "preferredLanguage", "refreshTokensValidFromDateTime", "showInAddressList", "sipProxyAddress", "state", "streetAddress", "surname", "telephoneNumber", "thumbnailPhoto@odata.mediaContentType", "usageLocation", "userPrincipalName", "userType", "extension_18e31482d3fb4a8ea958aa96b662f508_SupervisorInd", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingName", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingID", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToPersonnelNbr", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToFullName", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToEmailName", "extension_18e31482d3fb4a8ea958aa96b662f508_CompanyCode", "extension_18e31482d3fb4a8ea958aa96b662f508_CostCenterCode", "extension_18e31482d3fb4a8ea958aa96b662f508_LocationAreaCode", "extension_18e31482d3fb4a8ea958aa96b662f508_PersonnelNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_PositionNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_ProfitCenterCode"}, {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "ageGroup", "city", "companyName", "consentProvidedForMinor", "country", "creationType", "department", "dirSyncEnabled", "displayName", "employeeId", "facsimileTelephoneNumber", "givenName", "immutableId", "isCompromised", "jobTitle", "lastDirSyncTime", "legalAgeGroupClassification", "mail", "mailNickname", "mobile", "onPremisesDistinguishedName", "onPremisesSecurityIdentifier", "passwordPolicies", "passwordProfile", "physicalDeliveryOfficeName", "postalCode", "preferredLanguage", "refreshTokensValidFromDateTime", "showInAddressList", "sipProxyAddress", "state", "streetAddress", "surname", "telephoneNumber", "thumbnailPhoto@odata.mediaContentType", "usageLocation", "userPrincipalName", "userType", "extension_18e31482d3fb4a8ea958aa96b662f508_SupervisorInd", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingName", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingID", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToPersonnelNbr", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToFullName", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToEmailName", "extension_18e31482d3fb4a8ea958aa96b662f508_CompanyCode", "extension_18e31482d3fb4a8ea958aa96b662f508_CostCenterCode", "extension_18e31482d3fb4a8ea958aa96b662f508_LocationAreaCode", "extension_18e31482d3fb4a8ea958aa96b662f508_PersonnelNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_PositionNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_ProfitCenterCode"})
|
||||
in
|
||||
#"Expanded Users"
|
||||
|
||||
// TenantName
|
||||
"repsol.com" meta [IsParameterQuery=true, Type="Text", IsParameterQueryRequired=true]
|
||||
|
||||
// ListRBACUsers
|
||||
let ListRBACUsers = (principalId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://graph.windows.net/"&TenantName&"/users?api-version=1.6&$filter=objectId eq '"&principalId&"'")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "ageGroup", "assignedLicenses", "assignedPlans", "city", "companyName", "consentProvidedForMinor", "country", "creationType", "department", "dirSyncEnabled", "displayName", "employeeId", "facsimileTelephoneNumber", "givenName", "immutableId", "isCompromised", "jobTitle", "lastDirSyncTime", "legalAgeGroupClassification", "mail", "mailNickname", "mobile", "onPremisesDistinguishedName", "onPremisesSecurityIdentifier", "otherMails", "passwordPolicies", "passwordProfile", "physicalDeliveryOfficeName", "postalCode", "preferredLanguage", "provisionedPlans", "provisioningErrors", "proxyAddresses", "refreshTokensValidFromDateTime", "showInAddressList", "signInNames", "sipProxyAddress", "state", "streetAddress", "surname", "telephoneNumber", "thumbnailPhoto@odata.mediaContentType", "usageLocation", "userIdentities", "userPrincipalName", "userType", "extension_18e31482d3fb4a8ea958aa96b662f508_SupervisorInd", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingName", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingID", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToPersonnelNbr", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToFullName", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToEmailName", "extension_18e31482d3fb4a8ea958aa96b662f508_CompanyCode", "extension_18e31482d3fb4a8ea958aa96b662f508_CostCenterCode", "extension_18e31482d3fb4a8ea958aa96b662f508_LocationAreaCode", "extension_18e31482d3fb4a8ea958aa96b662f508_PersonnelNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_PositionNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_ProfitCenterCode"}, {"odata.type", "objectType", "objectId", "deletionTimestamp", "accountEnabled", "ageGroup", "assignedLicenses", "assignedPlans", "city", "companyName", "consentProvidedForMinor", "country", "creationType", "department", "dirSyncEnabled", "displayName", "employeeId", "facsimileTelephoneNumber", "givenName", "immutableId", "isCompromised", "jobTitle", "lastDirSyncTime", "legalAgeGroupClassification", "mail", "mailNickname", "mobile", "onPremisesDistinguishedName", "onPremisesSecurityIdentifier", "otherMails", "passwordPolicies", "passwordProfile", "physicalDeliveryOfficeName", "postalCode", "preferredLanguage", "provisionedPlans", "provisioningErrors", "proxyAddresses", "refreshTokensValidFromDateTime", "showInAddressList", "signInNames", "sipProxyAddress", "state", "streetAddress", "surname", "telephoneNumber", "thumbnailPhoto@odata.mediaContentType", "usageLocation", "userIdentities", "userPrincipalName", "userType", "extension_18e31482d3fb4a8ea958aa96b662f508_SupervisorInd", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingName", "extension_18e31482d3fb4a8ea958aa96b662f508_BuildingID", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToPersonnelNbr", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToFullName", "extension_18e31482d3fb4a8ea958aa96b662f508_ReportsToEmailName", "extension_18e31482d3fb4a8ea958aa96b662f508_CompanyCode", "extension_18e31482d3fb4a8ea958aa96b662f508_CostCenterCode", "extension_18e31482d3fb4a8ea958aa96b662f508_LocationAreaCode", "extension_18e31482d3fb4a8ea958aa96b662f508_PersonnelNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_PositionNumber", "extension_18e31482d3fb4a8ea958aa96b662f508_ProfitCenterCode"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded Column1",{"assignedLicenses", "assignedPlans", "otherMails", "provisionedPlans", "provisioningErrors", "proxyAddresses", "signInNames", "userIdentities"})
|
||||
in
|
||||
#"Removed Columns"
|
||||
in
|
||||
ListRBACUsers
|
|
@ -1,42 +0,0 @@
|
|||
// Resource Groups
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListResourceGroups", each ListResourceGroups([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListResourceGroups"}),
|
||||
#"Expanded ListResourceGroups" = Table.ExpandTableColumn(#"Removed Errors", "ListResourceGroups", {"Resource Group Id", "Resource Group Name", "location", "provisioningState"}, {"Resource Group Id", "Resource Group Name", "location", "provisioningState"})
|
||||
in
|
||||
#"Expanded ListResourceGroups"
|
||||
|
||||
// ListResourceGroups
|
||||
let ListResourceGroups = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/resourcegroups?api-version=2017-05-10")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "location", "properties"}, {"id", "name", "location", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"provisioningState"}, {"provisioningState"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded properties",{{"id", "Resource Group Id"}, {"name", "Resource Group Name"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
|
||||
in
|
||||
ListResourceGroups
|
||||
|
||||
// ListResourceGroups (2)
|
||||
let ListResourceGroups = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/resourcegroups?api-version=2017-05-10")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "location", "properties"}, {"id", "name", "location", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"provisioningState"}, {"provisioningState"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded properties",{{"id", "Resource Group Id"}, {"name", "Resource Group Name"}})
|
||||
in
|
||||
#"Renamed Columns"
|
||||
|
||||
in
|
||||
ListResourceGroups
|
|
@ -1,40 +0,0 @@
|
|||
// Resources
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListResources", each ListResources([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListResources"}),
|
||||
#"Expanded ListResources" = Table.ExpandTableColumn(#"Removed Errors", "ListResources", {"Resource Id", "Resource Name", "Resource Type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1", "name", "tier", "capacity", "size", "family", "kind", "name.1", "promotionCode", "product", "publisher", "managedBy", "Resource Group Id"}, {"Resource Id", "Resource Name", "Resource Type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1", "name", "tier", "capacity", "size", "family", "kind", "name.1", "promotionCode", "product", "publisher", "managedBy", "Resource Group Id"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListResources",{"subscriptionId", "Subscription Name"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Removed Columns", each true),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Filtered Rows", "Container Type", each if Text.Contains([Resource Type], "containerGroups") then "ACI" else if Text.Contains([Resource Type], "managedClusters") then "AKS" else if Text.Contains([Resource Type], "containerServices") then "ACS" else null),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Added Conditional Column", "Resource Group Id", "Resource Group Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Group Id - Copy", Splitter.SplitTextByDelimiter("/resourceGroups/", QuoteStyle.Csv), {"Resource Group Id - Copy.1", "Resource Group Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Group Id - Copy.1", type text}, {"Resource Group Id - Copy.2", type text}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Changed Type",{"Resource Group Id - Copy.1"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns1",{{"Resource Group Id - Copy.2", "Resource Group Name"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// ListResources
|
||||
let ListResources = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/resources?api-version=2017-05-10")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "location", "tags", "sku", "kind", "plan", "managedBy"}, {"id", "name", "type", "location", "tags", "sku", "kind", "plan", "managedBy"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"id", "Resource Id"}, {"name", "Resource Name"}, {"type", "Resource Type"}}),
|
||||
#"Expanded tags" = Table.ExpandRecordColumn(#"Renamed Columns", "tags", {"creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroups/WebappforcontainersCedwards/providers/Microsoft.Web/serverfarms/ServicePlanb8fd2fe5-b45f", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGroups/WebAppRG/providers/Microsoft.Web/serverfarms/cedwardWebApp1"}, {"creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1"}),
|
||||
#"Expanded sku" = Table.ExpandRecordColumn(#"Expanded tags", "sku", {"name", "tier", "capacity", "size", "family"}, {"name", "tier", "capacity", "size", "family"}),
|
||||
#"Expanded plan" = Table.ExpandRecordColumn(#"Expanded sku", "plan", {"name", "promotionCode", "product", "publisher"}, {"name.1", "promotionCode", "product", "publisher"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded plan", "Resource Id", "Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Id - Copy", Splitter.SplitTextByDelimiter("/providers", QuoteStyle.Csv), {"Resource Id - Copy.1", "Resource Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Id - Copy.1", type text}, {"Resource Id - Copy.2", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"Resource Id - Copy.2"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"Resource Id - Copy.1", "Resource Group Id"}})
|
||||
in
|
||||
#"Renamed Columns1"in
|
||||
ListResources
|
|
@ -1,97 +0,0 @@
|
|||
// Get Security Center Tasks
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"Column1.subscriptionId", "Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionID"}}),
|
||||
ListSecurityCenterTasksFunction = Table.AddColumn(#"Renamed Columns", "ListSecurityCenterTasks", each ListSecurityCenterTasks([SubscriptionID])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(ListSecurityCenterTasksFunction, {"ListSecurityCenterTasks"}),
|
||||
#"Expanded ListSecurityCenterTasks" = Table.ExpandTableColumn(#"Removed Errors", "ListSecurityCenterTasks", {"Security Task Id", "state", "subState", "creationTimeUtc", "lastStateChangeTimeUtc", "Missing Updates", "Updates Classification", "totalNumberOfImpactedMachines", "severity", "osType", "isMandatory", "workspaceId", "serverCount", "Security Task Name", "resourceId", "baselineRuleId", "baselineName", "baselineCceId", "osName", "ruleType", "totalNumberOfDefectedMachines", "resourceType", "policyName", "vmId", "vmName", "supportedAgents", "isOsDiskEncrypted", "isDataDiskEncrypted", "publicIpName", "fullyQualifiedDomainName", "portsToProtect", "existingWafAvailable", "resourceName", "resourceParent", "resourceParentIPAddress", "protectingNsgId", "ipAddress", "location", "resourceGroup", "subnetIds", "resourcesIdsToProtect", "Resource Type Final", "name", "type", "subscriptionId", "uniqueKey", "id.1", "title", "classification", "healthStatus", "totalMachines", "parentIpAddress", "concreteResourceType", "ImageForTasks"}, {"Security Task Id", "state", "subState", "creationTimeUtc", "lastStateChangeTimeUtc", "Missing Updates", "Updates Classification", "totalNumberOfImpactedMachines", "severity", "osType", "isMandatory", "workspaceId", "serverCount", "Security Task Name", "resourceId", "baselineRuleId", "baselineName", "baselineCceId", "osName", "ruleType", "totalNumberOfDefectedMachines", "resourceType", "policyName", "vmId", "vmName", "supportedAgents", "isOsDiskEncrypted", "isDataDiskEncrypted", "publicIpName", "fullyQualifiedDomainName", "portsToProtect", "existingWafAvailable", "resourceName", "resourceParent", "resourceParentIPAddress", "protectingNsgId", "ipAddress", "location", "resourceGroup", "subnetIds", "resourcesIdsToProtect", "Resource Type Final", "name", "type", "subscriptionId.1", "uniqueKey", "id.1", "title", "classification", "healthStatus", "totalMachines", "parentIpAddress", "concreteResourceType", "ImageForTasks"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded ListSecurityCenterTasks", "resourceId", "resourceId - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "resourceId - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"resourceId - Copy.1", "resourceId - Copy.2", "resourceId - Copy.3", "resourceId - Copy.4", "resourceId - Copy.5", "resourceId - Copy.6", "resourceId - Copy.7", "resourceId - Copy.8", "resourceId - Copy.9", "resourceId - Copy.10", "resourceId - Copy.11"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"resourceId - Copy.1", type text}, {"resourceId - Copy.2", type text}, {"resourceId - Copy.3", type text}, {"resourceId - Copy.4", type text}, {"resourceId - Copy.5", type text}, {"resourceId - Copy.6", type text}, {"resourceId - Copy.7", type text}, {"resourceId - Copy.8", type text}, {"resourceId - Copy.9", type text}, {"resourceId - Copy.10", type text}, {"resourceId - Copy.11", type text}}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Changed Type",{{"resourceId - Copy.5", "Resource Group Name"}, {"resourceId - Copy.9", "Resource Name"}, {"resourceId - Copy.8", "Resource Type"}, {"resourceId - Copy.10", "Subnet"}, {"resourceId - Copy.11", "Subnet Name"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns1",{"Subnet", "resourceId - Copy.3", "resourceId - Copy.4", "resourceId - Copy.6", "resourceId - Copy.7", "resourceId - Copy.1", "resourceId - Copy.2"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Columns", "Custom", each if Text.Contains([Security Task Name], "EncryptionOnVm") then "https://docs.microsoft.com/en-us/azure/security/azure-security-disk-encryption" else if Text.Contains([Security Task Name], "VirtualMachinesNsgShouldRestrict") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-restrict-access-through-internet-facing-endpoints" else if Text.Contains([Security Task Name], "InstallAntimalware") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-install-endpoint-protection" else if Text.Contains([Security Task Name], "VulnerabilityAssessmentDeployment") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-vulnerability-assessment-recommendations" else if Text.Contains([Security Task Name], "JitNetworkAccessRecommendation") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-just-in-time" else if Text.Contains([Security Task Name], "ProvisionNgfw") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-add-next-generation-firewall" else if Text.Contains([Security Task Name], "Enable auditing") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-enable-auditing-on-sql-servers" else if Text.Contains([Security Task Name], "NetworkSecurityGroupMissingOnSubnet") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-enable-network-security-groups" else if Text.Contains([Security Task Name], "Enable Transparent encryption") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-enable-transparent-data-encryption" else if Text.Contains([Security Task Name], "ProvisionWafArm") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-add-web-application-firewall" else if Text.Contains([Security Task Name], "NetworkSecurityGroupMissingOnVm") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-enable-network-security-groups" else if Text.Contains([Security Task Name], "RebootVm") then "https://docs.microsoft.com/en-us/azure/security-center/security-center-apply-system-updates#reboot-after-system-updates" else if [policyName] = "Enable MFA for accounts with owner permissions on your subscription" then "https://docs.microsoft.com/en-us/azure/active-directory/authentication/howto-mfa-userstates" else if [policyName] = "Designate up to 3 owners on your subscription" then "https://docs.microsoft.com/en-us/azure/role-based-access-control/overview" else if [policyName] = "Designate more than one owner on your subscription" then "https://docs.microsoft.com/en-us/azure/role-based-access-control/overview" else if [policyName] = "Use the latest supported PHP version for API App" then "https://azure.microsoft.com/en-us/updates/app-service-updating-php-to-latest-versions/" else if [policyName] = "Configure IP restrictions for API App" then "https://docs.microsoft.com/en-us/azure/app-service/app-service-ip-restrictions" else null),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Added Conditional Column",{{"Custom", "Recommendation URL"}}),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Renamed Columns2", "Solution", each if Text.Contains([Security Task Name], "EncryptionOnVm") then "Azure Security Center recommends that you apply disk encryption if you have Windows or Linux VM disks that are not encrypted using Azure Disk Encryption" else if Text.Contains([Security Task Name], "VirtualMachinesNsgShouldRestrict") then "We recommend that you edit the inbound rules to restrict access to a specified set of sources." else if Text.Contains([Security Task Name], "InstallAntimalware") then "We recommend that endpoint protection be provisioned for all VMs and computers to help identify and remove viruses, spyware, and other malicious software" else if Text.Contains([Security Task Name], "VulnerabilityAssessmentDeployment") then "Currently, a vulnerability assessment is available from Qualys. More partners will be added in the future" else if Text.Contains([Security Task Name], "JitNetworkAccessRecommendation") then "It is recommended to enable Just in time Administration to reduce exposure to a brute force attack" else if Text.Contains([Security Task Name], "ProvisionNgfw") then "Azure Security Center may recommend that you add a next generation firewall (NGFW) from a Microsoft partner to increase your security protections" else if Text.Contains([Security Task Name], "Enable auditing") then "Auditing and threat detection can help you maintain regulatory compliance, understand database activity, and gain insight into discrepancies and anomalies that could indicate business concerns or suspected security violations" else if Text.Contains([Security Task Name], "NetworkSecurityGroupMissingOnSubnet") then "If you do not have NSGs enabled, Security Center presents two recommendations to you: Enable Network Security Groups on subnets and Enable Network Security Groups on virtual machines. You choose which level, subnet or VM, to apply NSGs" else if Text.Contains([Security Task Name], "Enable Transparent encryption") then " TDE protects your data and helps you meet compliance requirements by encrypting your database, associated backups, and transaction log files at rest, without requiring changes to your application" else if Text.Contains([Security Task Name], "ProvisionWafArm") then "Security Center recommends that you provision a WAF to help defend against attacks targeting your web applications on virtual machines and on external App Service Environments (ASE)" else if Text.Contains([Security Task Name], "NetworkSecurityGroupMissingOnVm") then "If you do not have NSGs enabled, Security Center presents two recommendations to you: Enable Network Security Groups on subnets and Enable Network Security Groups on virtual machines. You choose which level, subnet or VM, to apply NSGs" else if Text.Contains([Security Task Name], "RebootVm") then "Reboot the Virtual Machine" else if [policyName] = "Enable MFA for accounts with owner permissions on your subscription" then "Azure Multi-Factor Authentication is an easy to use, scalable, and reliable solution that provides a second method of authentication to protect your users." else if [policyName] = "Designate up to 3 owners on your subscription" then "Minimize the number of subscription owners whenever is possible" else if [policyName] = "Designate more than one owner on your subscription" then "Enable at least a second subscription owner account to avoid access issues if something happen to the unique owner" else if [policyName] = "Web Sockets should be disabled for Web Application" then "The Web Sockets protocol is vulnerable to different types of security threats. Use of Web Sockets within a web application must be carefully reviewed." else if [policyName] = "Use the latest supported PHP version for API App" then "Recommends that you use the latest PHP version for the latest security classes. Using older classes and types can make your application vulnerable." else if [policyName] = "Configure IP restrictions for API App" then "IP Restrictions allow you to define a priority ordered allow/deny list of IP addresses that are allowed to access your app. The allow list can include IPv4 and IPv6 addresses. When there are one or more entries, there is then an implicit deny all that exists at the end of the list." else null),
|
||||
#"Added Conditional Column2" = Table.AddColumn(#"Added Conditional Column1", "Problem", each if Text.Contains([Security Task Name], "EncryptionOnVm") then "VM Disks Encryption not enabled" else if Text.Contains([Security Task Name], "JitNetworkAccessRecommendation") then "Just in time VM access not enabled" else if Text.Contains([Security Task Name], "ProvisionNgfw") then "Add a next generation firewall" else if Text.Contains([Security Task Name], "VirtualMachinesNsgShouldRestrict") then "Your NSG has inbound rules that open access to ‘Any’ or ‘Internet’ which might enable attackers to access your resources" else if Text.Contains([Security Task Name], "InstallAntimalware") then "A supported antimalware solution is not installed on these Azure VMs." else if Text.Contains([Security Task Name], "VulnerabilityAssessmentDeployment") then "If Security Center doesn't find a vulnerability assessment solution installed on your VM, it recommends that you install one" else if Text.Contains([Security Task Name], "Enable auditing") then "Auditing and threat detection is not enabled" else if Text.Contains([Security Task Name], "NetworkSecurityGroupMissingOnSubnet") then "This network subnet does not have any NSG enabled" else if Text.Contains([Security Task Name], "Enable Transparent encryption") then "Transparent Data Encryption is not enabled on your SQL Database" else if Text.Contains([Security Task Name], "ProvisionWafArm") then "A WAF recommendation is shown for any public facing IP (either Instance Level IP or Load Balanced IP) that has an associated network security group with open inbound web ports (80,443)" else if Text.Contains([Security Task Name], "NetworkSecurityGroupMissingOnVm") then "The Virtual Machine does not have any NSG enabled" else if Text.Contains([Security Task Name], "RebootVm") then "Virtual Machine needs to reboot after system updates" else [policyName]),
|
||||
#"Added Conditional Column3" = Table.AddColumn(#"Added Conditional Column2", "Image", each if Text.Contains([Security Task Name], "EncryptionOnVm") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/EncryptionOnVm.svg?sanitize=true" else if Text.Contains([Security Task Name], "ProvisionNgfw") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/NextGenFirewall.svg?sanitize=true" else if Text.Contains([Security Task Name], "Enable auditing") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/enable_auditing.svg?sanitize=true" else if Text.Contains([Security Task Name], "JitNetworkAccessRecommendation") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/JitAdmin.svg?sanitize=true" else if Text.Contains([Security Task Name], "InstallAntimalware") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/installAntimalware.svg?sanitize=true" else if Text.Contains([Security Task Name], "VulnerabilityAssessmentDeployment") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/VulnerabilityAssessmentDeployment.svg?sanitize=true" else if Text.Contains([Security Task Name], "NetworkSecurityGroupMissingOnVm") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/VMNSG.svg?sanitize=true" else if Text.Contains([Security Task Name], "ProvisionWafArm") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/WAF.svg?sanitize=true" else if Text.Contains([Security Task Name], "NetworkSecurityGroupMissingOnSubnet") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/NSGSubnetFinal.svg?sanitize=true" else if Text.Contains([Security Task Name], "Enable Transparent encryption") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/SQLTDE.svg?sanitize=true" else if Text.Contains([Security Task Name], "Antimalware Health Issues") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/installAntimalware.svg?sanitize=true" else if Text.Contains([Security Task Name], "VirtualMachinesNsgShouldRestrictTrafficTaskParameters") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/InetFacingNSG.svg?sanitize=true" else if Text.Contains([Security Task Name], "RebootVm") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/RebootVm.svg?sanitize=true" else if [policyName] = "Enable MFA for accounts with owner permissions on your subscription" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/subscriptionsandMFA2.svg?sanitize=true" else if [policyName] = "Designate up to 3 owners on your subscription" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/3SubscriptionOwners.svg?sanitize=true" else if [policyName] = "Designate more than one owner on your subscription" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/MoreSubscriptionOwners.svg?sanitize=true" else if [policyName] = "Use the latest supported PHP version for API App" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/PHPUpdate.svg?sanitize=true" else if [policyName] = "Configure IP restrictions for API App" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/IPRestrictions.svg?sanitize=true" else null),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Added Conditional Column3", each ([Security Task Name] <> "Enable Security Contact Configuration in Policy" and [Security Task Name] <> "EnableApplicationWhitelisting" and [Security Task Name] <> "Subscription has machines with failed baseline rule" and [Security Task Name] <> "Subscription has machines with missing system updates" and [Security Task Name] <> "UpgradePricingTierTaskParameters")),
|
||||
#"Merged Columns" = Table.CombineColumns(#"Filtered Rows",{"Resource Type Final", "Resource Type"},Combiner.CombineTextByDelimiter("", QuoteStyle.None),"ResourceType.1"),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Merged Columns",{{"ResourceType.1", "All Resources Types"}}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Renamed Columns3","servers","SQL Resources",Replacer.ReplaceText,{"All Resources Types"}),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Replaced Value","VirtualMachinevirtualMachines","virtualMachines",Replacer.ReplaceText,{"All Resources Types"}),
|
||||
#"Replaced Value2" = Table.ReplaceValue(#"Replaced Value1","virtualMachines","Virtual Machines",Replacer.ReplaceText,{"All Resources Types"}),
|
||||
#"Replaced Value3" = Table.ReplaceValue(#"Replaced Value2","publicIPAddresses","Public IP Addresses",Replacer.ReplaceText,{"All Resources Types"}),
|
||||
#"Replaced Value4" = Table.ReplaceValue(#"Replaced Value3","WebApplicationsites","Web Application",Replacer.ReplaceText,{"All Resources Types"}),
|
||||
#"Replaced Value5" = Table.ReplaceValue(#"Replaced Value4","SubnetvirtualNetworks","Subnet",Replacer.ReplaceText,{"All Resources Types"}),
|
||||
#"Replaced Value6" = Table.ReplaceValue(#"Replaced Value5","FunctionAppsites","Functions",Replacer.ReplaceText,{"All Resources Types"}),
|
||||
#"Added Conditional Column4" = Table.AddColumn(#"Replaced Value6", "All Resources", each if [All Resources Types] = "Subscription" then [Column1.displayName] else [Resource Name]),
|
||||
#"Renamed Columns4" = Table.RenameColumns(#"Added Conditional Column4",{{"Column1.displayName", "Subscription Name"}})
|
||||
in
|
||||
#"Renamed Columns4"
|
||||
|
||||
// ListSecurityCenterTasks
|
||||
let ListSecurityCenterTasks = (subscriptionId as text) =>
|
||||
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/microsoft.Security/tasks?api-version=2015-06-01-preview")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "properties"}, {"id", "name", "type", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"state", "subState", "creationTimeUtc", "lastStateChangeTimeUtc", "securityTaskParameters"}, {"state", "subState", "creationTimeUtc", "lastStateChangeTimeUtc", "securityTaskParameters"}),
|
||||
#"Expanded securityTaskParameters" = Table.ExpandRecordColumn(#"Expanded properties", "securityTaskParameters", {"subscriptionId", "id", "title", "classification", "totalNumberOfImpactedMachines", "severity", "osType", "isMandatory", "workspaces", "name", "uniqueKey", "resourceId", "baselineRuleId", "baselineName", "baselineCceId", "osName", "ruleType", "totalNumberOfDefectedMachines", "resourceType", "policyName", "vmId", "vmName", "lastScanTime", "supportedAgents", "isOsDiskEncrypted", "isDataDiskEncrypted", "groupName", "publicIpName", "fullyQualifiedDomainName", "portsToProtect", "existingWafAvailable", "resourceName", "resourceParent", "resourceParentIPAddress", "protectingNsgId", "ipAddress", "location", "resourceGroup", "subnetIds", "resourcesIdsToProtect"}, {"subscriptionId", "id.1", "title", "classification", "totalNumberOfImpactedMachines", "severity", "osType", "isMandatory", "workspaces", "name.1", "uniqueKey", "resourceId", "baselineRuleId", "baselineName", "baselineCceId", "osName", "ruleType", "totalNumberOfDefectedMachines", "resourceType", "policyName", "vmId", "vmName", "lastScanTime", "supportedAgents", "isOsDiskEncrypted", "isDataDiskEncrypted", "groupName", "publicIpName", "fullyQualifiedDomainName", "portsToProtect", "existingWafAvailable", "resourceName", "resourceParent", "resourceParentIPAddress", "protectingNsgId", "ipAddress", "location", "resourceGroup", "subnetIds", "resourcesIdsToProtect"}),
|
||||
#"Expanded workspaces" = Table.ExpandListColumn(#"Expanded securityTaskParameters", "workspaces"),
|
||||
#"Expanded workspaces1" = Table.ExpandRecordColumn(#"Expanded workspaces", "workspaces", {"workspaceId", "serverCount"}, {"workspaceId", "serverCount"}),
|
||||
#"Expanded portsToProtect" = Table.ExpandListColumn(#"Expanded workspaces1", "portsToProtect"),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded portsToProtect",{{"name.1", "Security Task Name"}, {"id", "Security Task Id"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns",{"name", "type", "subscriptionId", "id.1"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"title", "Missing Updates"}, {"classification", "Updates Classification"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"uniqueKey"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Removed Columns1", "resourceType", "resourceType - Copy"),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Duplicated Column",{{"resourceType - Copy", "Resource Type Final"}}),
|
||||
#"Expanded subnetIds" = Table.ExpandListColumn(#"Renamed Columns2", "subnetIds"),
|
||||
#"Expanded resourcesIdsToProtect" = Table.ExpandListColumn(#"Expanded subnetIds", "resourcesIdsToProtect")
|
||||
in
|
||||
#"Expanded resourcesIdsToProtect"
|
||||
in
|
||||
ListSecurityCenterTasks
|
||||
|
||||
// Get Security Center Alerts
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"Column1.subscriptionId", "Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListSecurityCenterAlerts", each ListSecurityCenterAlerts([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListSecurityCenterAlerts"}),
|
||||
#"Expanded ListSecurityCenterAlerts" = Table.ExpandTableColumn(#"Removed Errors", "ListSecurityCenterAlerts", {"Alert Id", "alertDisplayName", "alertName", "detectedTimeUtc", "description", "remediationSteps", "actionTaken", "reportedSeverity", "compromisedEntity", "associatedResource", "subscriptionId", "instanceId", "alert Start Time (UTC)", "source", "non-Existent Users", "existing Users", "failed Attempts", "successful Logins", "successful User Logons", "account Logon Ids", "failed User Logons", "end Time UTC", "enrichment_tas_threat__reports", "state", "reportedTimeUtc", "workspaceArmId", "confidenceReasons", "canBeInvestigated", "Unique Alert Id", "Resource Type", "dnsDomain", "hostName", "azureID", "omsAgentID", "name.1", "address"}, {"Alert Id", "alertDisplayName", "alertName", "detectedTimeUtc", "description", "remediationSteps", "actionTaken", "reportedSeverity", "compromisedEntity", "associatedResource", "subscriptionId.1", "instanceId", "alert Start Time (UTC)", "source", "non-Existent Users", "existing Users", "failed Attempts", "successful Logins", "successful User Logons", "account Logon Ids", "failed User Logons", "end Time UTC", "enrichment_tas_threat__reports", "state", "reportedTimeUtc", "workspaceArmId", "confidenceReasons", "canBeInvestigated", "Unique Alert Id", "Resource Type", "dnsDomain", "hostName", "azureID", "omsAgentID", "name.1", "address"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded ListSecurityCenterAlerts",{{"alertDisplayName", "Attack Type"}, {"compromisedEntity", "Impacted Resource"}, {"remediationSteps", "Potential Remediation"}, {"detectedTimeUtc", "Detected Time UTC"}, {"end Time UTC", "End Time UTC"}, {"source", "Attack Source IP Address"}}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns1",{{"Detected Time UTC", type datetime}}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Changed Type", "AttackImage", each if Text.Contains([Attack Type], "Failed RDP Brute Force Attack") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/UnderAttack.svg?sanitize=true" else if Text.Contains([Attack Type], "Possible incoming SQL brute force") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/SQLUnderAttack.svg?sanitize=true" else if Text.Contains([Attack Type], "network activity") then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/SubnetUnderAttack.svg?sanitize=true" else null)
|
||||
in
|
||||
#"Added Conditional Column"
|
||||
|
||||
// ListSecurityCenterAlerts
|
||||
let ListSecurityCenterAlerts = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/microsoft.Security/alerts?api-version=2015-06-01-preview")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "properties"}, {"id", "name", "type", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"vendorName", "alertDisplayName", "alertName", "detectedTimeUtc", "description", "remediationSteps", "actionTaken", "reportedSeverity", "compromisedEntity", "associatedResource", "subscriptionId", "instanceId", "extendedProperties", "state", "reportedTimeUtc", "workspaceArmId", "confidenceReasons", "canBeInvestigated", "entities"}, {"vendorName", "alertDisplayName", "alertName", "detectedTimeUtc", "description", "remediationSteps", "actionTaken", "reportedSeverity", "compromisedEntity", "associatedResource", "subscriptionId", "instanceId", "extendedProperties", "state", "reportedTimeUtc", "workspaceArmId", "confidenceReasons", "canBeInvestigated", "entities"}),
|
||||
#"Expanded extendedProperties" = Table.ExpandRecordColumn(#"Expanded properties", "extendedProperties", {"alert Start Time (UTC)", "source", "non-Existent Users", "existing Users", "failed Attempts", "successful Logins", "successful User Logons", "account Logon Ids", "failed User Logons", "end Time UTC", "enrichment_tas_threat__reports"}, {"alert Start Time (UTC)", "source", "non-Existent Users", "existing Users", "failed Attempts", "successful Logins", "successful User Logons", "account Logon Ids", "failed User Logons", "end Time UTC", "enrichment_tas_threat__reports"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded extendedProperties", {"confidenceReasons", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded entities" = Table.ExpandListColumn(#"Extracted Values", "entities"),
|
||||
#"Expanded entities1" = Table.ExpandRecordColumn(#"Expanded entities", "entities", {"$id", "type", "dnsDomain", "hostName", "azureID", "omsAgentID", "name", "address"}, {"$id", "type.1", "dnsDomain", "hostName", "azureID", "omsAgentID", "name.1", "address"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded entities1",{{"id", "Alert Id"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns",{"name", "type", "vendorName"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"type.1", "Resource Type"}, {"$id", "Unique Alert Id"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
in
|
||||
ListSecurityCenterAlerts
|
|
@ -1,22 +0,0 @@
|
|||
// ListResourcesHealth
|
||||
let ListResourcesHealth = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.ResourceHealth/availabilityStatuses?api-version=2017-07-01&$expand=recommendedActions")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "location", "properties"}, {"id", "name", "type", "location", "properties"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Expanded Column1", "properties", {"availabilityState", "summary", "detailedStatus", "reasonType", "recommendedActions", "occuredTime", "reasonChronicity", "reportedTime"}, {"availabilityState", "summary", "detailedStatus", "reasonType", "recommendedActions", "occuredTime", "reasonChronicity", "reportedTime"}),
|
||||
#"Expanded recommendedActions" = Table.ExpandListColumn(#"Expanded properties", "recommendedActions"),
|
||||
#"Expanded recommendedActions1" = Table.ExpandRecordColumn(#"Expanded recommendedActions", "recommendedActions", {"action", "actionUrl", "actionUrlText"}, {"action", "actionUrl", "actionUrlText"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded recommendedActions1", "id", "id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"id - Copy.1", "id - Copy.2", "id - Copy.3", "id - Copy.4", "id - Copy.5", "id - Copy.6", "id - Copy.7", "id - Copy.8", "id - Copy.9", "id - Copy.10", "id - Copy.11", "id - Copy.12", "id - Copy.13"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"id - Copy.1", type text}, {"id - Copy.2", type text}, {"id - Copy.3", type text}, {"id - Copy.4", type text}, {"id - Copy.5", type text}, {"id - Copy.6", type text}, {"id - Copy.7", type text}, {"id - Copy.8", type text}, {"id - Copy.9", type text}, {"id - Copy.10", type text}, {"id - Copy.11", type text}, {"id - Copy.12", type text}, {"id - Copy.13", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"id - Copy.1", "id - Copy.2", "id - Copy.3", "id - Copy.4"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Removed Columns",{{"id - Copy.5", "Resource Group"}, {"id - Copy.8", "Resource Type"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns",{"id - Copy.6", "id - Copy.7"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns1",{{"id - Copy.9", "Resource Name"}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Renamed Columns1",{"id - Copy.10", "id - Copy.11", "id - Copy.12", "id - Copy.13"})
|
||||
in
|
||||
#"Removed Columns2"
|
||||
in
|
||||
ListResourcesHealth
|
|
@ -1,101 +0,0 @@
|
|||
// Virtual Machines
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListVirtualMachines", each ListVirtualMachines([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListVirtualMachines"}),
|
||||
#"Expanded ListVirtualMachines" = Table.ExpandTableColumn(#"Removed Errors", "ListVirtualMachines", {"Availability Set Id", "vmSize", "publisher", "offer", "sku", "version", "osType", "name", "createOption", "vhd uri", "caching", "diskSizeGB", "storageAccountType", "Managed Disk Id", "lun", "name.1", "createOption.1", "Data vhd uri", "caching.1", "diskSizeGB.1", "computerName", "adminUsername", "provisionVMAgent", "enableAutomaticUpdates", "Network Inteface Id", "provisioningState", "enabled", "storageUri", "Extensions Resource Id", "type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "VM Resource Id", "VM Name"}, {"Availability Set Id", "vmSize", "publisher", "offer", "sku", "version", "osType", "name", "createOption", "vhd uri", "caching", "diskSizeGB", "storageAccountType", "Managed Disk Id", "lun", "name.1", "createOption.1", "Data vhd uri", "caching.1", "diskSizeGB.1", "computerName", "adminUsername", "provisionVMAgent", "enableAutomaticUpdates", "Network Inteface Id", "provisioningState", "enabled", "storageUri", "Extensions Resource Id", "type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "VM Resource Id", "VM Name"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListVirtualMachines",{"subscriptionId", "Subscription Name"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns", {"VM Resource Id"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Removed Duplicates", "VM Resource Id", "VM Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "VM Resource Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"VM Resource Id - Copy.1", "VM Resource Id - Copy.2", "VM Resource Id - Copy.3", "VM Resource Id - Copy.4", "VM Resource Id - Copy.5", "VM Resource Id - Copy.6", "VM Resource Id - Copy.7", "VM Resource Id - Copy.8", "VM Resource Id - Copy.9"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"VM Resource Id - Copy.1", type text}, {"VM Resource Id - Copy.2", type text}, {"VM Resource Id - Copy.3", type text}, {"VM Resource Id - Copy.4", type text}, {"VM Resource Id - Copy.5", type text}, {"VM Resource Id - Copy.6", type text}, {"VM Resource Id - Copy.7", type text}, {"VM Resource Id - Copy.8", type text}, {"VM Resource Id - Copy.9", type text}}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Changed Type",{{"VM Resource Id - Copy.5", "Resource Group Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"VM Resource Id - Copy.1", "VM Resource Id - Copy.2", "VM Resource Id - Copy.3", "VM Resource Id - Copy.4", "VM Resource Id - Copy.6", "VM Resource Id - Copy.7", "VM Resource Id - Copy.8", "VM Resource Id - Copy.9"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Columns1", "Is Using Managed Disks", each if [Managed Disk Id] = null then false else true),
|
||||
#"Duplicated Column1" = Table.DuplicateColumn(#"Added Conditional Column", "Extensions Resource Id", "Extensions Resource Id - Copy"),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Duplicated Column1", "Extensions Resource Id - Copy", Splitter.SplitTextByDelimiter("/extensions/", QuoteStyle.Csv), {"Extensions Resource Id - Copy.1", "Extensions Resource Id - Copy.2"}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Split Column by Delimiter1",{"Extensions Resource Id - Copy.1"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Removed Columns2",{{"Extensions Resource Id - Copy.2", "VM Extension"}}),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Renamed Columns2", "IsRunningContainers", each if [orchestrator] = null then "VM without Containers" else "VM with Containers"),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Added Conditional Column1",null,"Custom",Replacer.ReplaceValue,{"offer"}),
|
||||
#"Added Conditional Column2" = Table.AddColumn(#"Replaced Value", "OS Type", each if [osType] = "Windows" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/WindowsLogo.svg?sanitize=true" else if [osType] = "Linux" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/dbf1dcabfb992474849157c48596a5f05c9512b1/LinuxLogo.svg?sanitize=true" else null),
|
||||
#"Changed Type1" = Table.TransformColumnTypes(#"Added Conditional Column2",{{"OS Type", type text}})
|
||||
in
|
||||
#"Changed Type1"
|
||||
|
||||
// ListVirtualMachines
|
||||
let ListVirtualMachines = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Compute/virtualMachines?api-version=2017-12-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"properties", "resources", "type", "location", "tags", "id", "name"}, {"properties", "resources", "type", "location", "tags", "id", "name"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"id", "VM Resource Id"}, {"name", "VM Name"}}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Renamed Columns", "properties", {"vmId", "availabilitySet", "hardwareProfile", "storageProfile", "osProfile", "networkProfile", "provisioningState", "diagnosticsProfile"}, {"vmId", "availabilitySet", "hardwareProfile", "storageProfile", "osProfile", "networkProfile", "provisioningState", "diagnosticsProfile"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded properties",{"vmId"}),
|
||||
#"Expanded availabilitySet" = Table.ExpandRecordColumn(#"Removed Columns", "availabilitySet", {"id"}, {"id"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded availabilitySet",{{"id", "Availability Set Id"}}),
|
||||
#"Expanded hardwareProfile" = Table.ExpandRecordColumn(#"Renamed Columns1", "hardwareProfile", {"vmSize"}, {"vmSize"}),
|
||||
#"Expanded storageProfile" = Table.ExpandRecordColumn(#"Expanded hardwareProfile", "storageProfile", {"imageReference", "osDisk", "dataDisks"}, {"imageReference", "osDisk", "dataDisks"}),
|
||||
#"Expanded imageReference" = Table.ExpandRecordColumn(#"Expanded storageProfile", "imageReference", {"publisher", "offer", "sku", "version"}, {"publisher", "offer", "sku", "version"}),
|
||||
#"Expanded osDisk" = Table.ExpandRecordColumn(#"Expanded imageReference", "osDisk", {"osType", "name", "createOption", "vhd", "caching", "diskSizeGB", "managedDisk"}, {"osType", "name", "createOption", "vhd", "caching", "diskSizeGB", "managedDisk"}),
|
||||
#"Expanded vhd" = Table.ExpandRecordColumn(#"Expanded osDisk", "vhd", {"uri"}, {"uri"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Expanded vhd",{{"uri", "vhd uri"}}),
|
||||
#"Expanded managedDisk" = Table.ExpandRecordColumn(#"Renamed Columns2", "managedDisk", {"storageAccountType", "id"}, {"storageAccountType", "id"}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Expanded managedDisk",{{"id", "Managed Disk Id"}}),
|
||||
#"Expanded dataDisks" = Table.ExpandListColumn(#"Renamed Columns3", "dataDisks"),
|
||||
#"Expanded dataDisks1" = Table.ExpandRecordColumn(#"Expanded dataDisks", "dataDisks", {"lun", "name", "createOption", "vhd", "caching", "diskSizeGB"}, {"lun", "name.1", "createOption.1", "vhd", "caching.1", "diskSizeGB.1"}),
|
||||
#"Expanded vhd1" = Table.ExpandRecordColumn(#"Expanded dataDisks1", "vhd", {"uri"}, {"uri"}),
|
||||
#"Renamed Columns4" = Table.RenameColumns(#"Expanded vhd1",{{"uri", "Data vhd uri"}}),
|
||||
#"Expanded osProfile" = Table.ExpandRecordColumn(#"Renamed Columns4", "osProfile", {"computerName", "adminUsername", "linuxConfiguration", "secrets", "windowsConfiguration"}, {"computerName", "adminUsername", "linuxConfiguration", "secrets", "windowsConfiguration"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded osProfile",{"linuxConfiguration", "secrets"}),
|
||||
#"Expanded windowsConfiguration" = Table.ExpandRecordColumn(#"Removed Columns1", "windowsConfiguration", {"provisionVMAgent", "enableAutomaticUpdates"}, {"provisionVMAgent", "enableAutomaticUpdates"}),
|
||||
#"Expanded networkProfile" = Table.ExpandRecordColumn(#"Expanded windowsConfiguration", "networkProfile", {"networkInterfaces"}, {"networkInterfaces"}),
|
||||
#"Expanded networkInterfaces" = Table.ExpandListColumn(#"Expanded networkProfile", "networkInterfaces"),
|
||||
#"Expanded networkInterfaces1" = Table.ExpandRecordColumn(#"Expanded networkInterfaces", "networkInterfaces", {"id"}, {"id"}),
|
||||
#"Renamed Columns5" = Table.RenameColumns(#"Expanded networkInterfaces1",{{"id", "Network Inteface Id"}}),
|
||||
#"Expanded diagnosticsProfile" = Table.ExpandRecordColumn(#"Renamed Columns5", "diagnosticsProfile", {"bootDiagnostics"}, {"bootDiagnostics"}),
|
||||
#"Expanded bootDiagnostics" = Table.ExpandRecordColumn(#"Expanded diagnosticsProfile", "bootDiagnostics", {"enabled", "storageUri"}, {"enabled", "storageUri"}),
|
||||
#"Expanded resources" = Table.ExpandListColumn(#"Expanded bootDiagnostics", "resources"),
|
||||
#"Expanded resources1" = Table.ExpandRecordColumn(#"Expanded resources", "resources", {"id"}, {"id"}),
|
||||
#"Renamed Columns6" = Table.RenameColumns(#"Expanded resources1",{{"id", "Extensions Resource Id"}}),
|
||||
#"Expanded tags" = Table.ExpandRecordColumn(#"Renamed Columns6", "tags", {"creationSource", "orchestrator", "poolName", "resourceNameSuffix"}, {"creationSource", "orchestrator", "poolName", "resourceNameSuffix"})
|
||||
in
|
||||
#"Expanded tags"
|
||||
|
||||
in
|
||||
ListVirtualMachines
|
||||
|
||||
// Containers VMs
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListVirtualMachines", each ListVirtualMachines([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListVirtualMachines"}),
|
||||
#"Expanded ListVirtualMachines" = Table.ExpandTableColumn(#"Removed Errors", "ListVirtualMachines", {"Availability Set Id", "vmSize", "publisher", "offer", "sku", "version", "osType", "name", "createOption", "vhd uri", "caching", "diskSizeGB", "storageAccountType", "Managed Disk Id", "lun", "name.1", "createOption.1", "Data vhd uri", "caching.1", "diskSizeGB.1", "computerName", "adminUsername", "provisionVMAgent", "enableAutomaticUpdates", "Network Inteface Id", "provisioningState", "enabled", "storageUri", "Extensions Resource Id", "type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "VM Resource Id", "VM Name"}, {"Availability Set Id", "vmSize", "publisher", "offer", "sku", "version", "osType", "name", "createOption", "vhd uri", "caching", "diskSizeGB", "storageAccountType", "Managed Disk Id", "lun", "name.1", "createOption.1", "Data vhd uri", "caching.1", "diskSizeGB.1", "computerName", "adminUsername", "provisionVMAgent", "enableAutomaticUpdates", "Network Inteface Id", "provisioningState", "enabled", "storageUri", "Extensions Resource Id", "type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "VM Resource Id", "VM Name"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListVirtualMachines",{"subscriptionId", "Subscription Name"}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Removed Columns", {"VM Resource Id"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Removed Duplicates", "VM Resource Id", "VM Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "VM Resource Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"VM Resource Id - Copy.1", "VM Resource Id - Copy.2", "VM Resource Id - Copy.3", "VM Resource Id - Copy.4", "VM Resource Id - Copy.5", "VM Resource Id - Copy.6", "VM Resource Id - Copy.7", "VM Resource Id - Copy.8", "VM Resource Id - Copy.9"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"VM Resource Id - Copy.1", type text}, {"VM Resource Id - Copy.2", type text}, {"VM Resource Id - Copy.3", type text}, {"VM Resource Id - Copy.4", type text}, {"VM Resource Id - Copy.5", type text}, {"VM Resource Id - Copy.6", type text}, {"VM Resource Id - Copy.7", type text}, {"VM Resource Id - Copy.8", type text}, {"VM Resource Id - Copy.9", type text}}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Changed Type",{{"VM Resource Id - Copy.5", "Resource Group Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns1",{"VM Resource Id - Copy.1", "VM Resource Id - Copy.2", "VM Resource Id - Copy.3", "VM Resource Id - Copy.4", "VM Resource Id - Copy.6", "VM Resource Id - Copy.7", "VM Resource Id - Copy.8", "VM Resource Id - Copy.9"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Columns1", "Is Using Managed Disks", each if [Managed Disk Id] = null then false else true),
|
||||
#"Duplicated Column1" = Table.DuplicateColumn(#"Added Conditional Column", "Extensions Resource Id", "Extensions Resource Id - Copy"),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Duplicated Column1", "Extensions Resource Id - Copy", Splitter.SplitTextByDelimiter("/extensions/", QuoteStyle.Csv), {"Extensions Resource Id - Copy.1", "Extensions Resource Id - Copy.2"}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Split Column by Delimiter1",{"Extensions Resource Id - Copy.1"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Removed Columns2",{{"Extensions Resource Id - Copy.2", "VM Extension"}}),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Renamed Columns2", "IsRunningContainers", each if [orchestrator] = null then "VM without Containers" else "VM with Containers"),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Added Conditional Column1",null,"Custom",Replacer.ReplaceValue,{"offer"}),
|
||||
#"Added Conditional Column2" = Table.AddColumn(#"Replaced Value", "OS Type", each if [osType] = "Windows" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/WindowsLogo.svg?sanitize=true" else if [osType] = "Linux" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/dbf1dcabfb992474849157c48596a5f05c9512b1/LinuxLogo.svg?sanitize=true" else null),
|
||||
#"Changed Type1" = Table.TransformColumnTypes(#"Added Conditional Column2",{{"OS Type", type text}}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Changed Type1", each ([IsRunningContainers] = "VM with Containers"))
|
||||
in
|
||||
#"Filtered Rows"
|
|
@ -1,177 +0,0 @@
|
|||
// Virtual Networks
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}}),
|
||||
#"List VirtualNetworks" = Table.AddColumn(#"Renamed Columns", "ListVirtualNetworks", each ListVirtualNetworks([SubscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"List VirtualNetworks", {"ListVirtualNetworks"}),
|
||||
#"Expanded ListVirtualNetworks" = Table.ExpandTableColumn(#"Removed Errors", "ListVirtualNetworks", {"VNET Name", "VNET Id", "location", "provisioningState", "resourceGuid", "VNET addressPrefixes", "Subnet Name", "Subnet Id", "Subnet addressPrefix", "IP Configuration Id", "serviceEndpoints", "Route Table id", "VNET Peering Name", "VNET Peering Id", "VNET peeringState", "Remote VNET Id", "allowVirtualNetworkAccess", "allowForwardedTraffic", "allowGatewayTransit", "useRemoteGateways", "Remote VNET addressPrefixes", "enableDdosProtection", "enableVmProtection", "dnsServers", "Resource Group"}, {"VNET Name", "VNET Id", "location", "provisioningState", "resourceGuid", "VNET addressPrefixes", "Subnet Name", "Subnet Id", "Subnet addressPrefix", "IP Configuration Id", "serviceEndpoints", "Route Table id", "VNET Peering Name", "VNET Peering Id", "VNET peeringState", "Remote VNET Id", "allowVirtualNetworkAccess", "allowForwardedTraffic", "allowGatewayTransit", "useRemoteGateways", "Remote VNET addressPrefixes", "enableDdosProtection", "enableVmProtection", "dnsServers", "Resource Group"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded ListVirtualNetworks",{{"Column1.displayName", "Subscription Name"}}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Renamed Columns1",{{"Subnet addressPrefix", "Subnet Address Prefix"}}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Renamed Columns2", "Available IPs", each if Text.Contains([Subnet Address Prefix], "/24") then 251 else if Text.Contains([Subnet Address Prefix], "/25") then 122 else if Text.Contains([Subnet Address Prefix], "/16") then 65530 else if Text.Contains([Subnet Address Prefix], "/26") then 58 else if Text.Contains([Subnet Address Prefix], "/27") then 26 else if Text.Contains([Subnet Address Prefix], "/28") then 10 else if Text.Contains([Subnet Address Prefix], "/29") then 4 else if Text.Contains([Subnet Address Prefix], "/23") then 506 else if Text.Contains([Subnet Address Prefix], "/22") then 1018 else if Text.Contains([Subnet Address Prefix], "/21") then 2042 else if Text.Contains([Subnet Address Prefix], "/20") then 4090 else if Text.Contains([Subnet Address Prefix], "/11") then 16777210 else if Text.Contains([Subnet Address Prefix], "/12") then 1048570 else null),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Added Conditional Column", "IP", each if [IP Configuration Id] = null then 0 else 1),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Added Conditional Column1",{{"IP", Int64.Type}, {"Available IPs", Int64.Type}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Changed Type", "Remote VNET Id", "Remote VNET Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(Table.TransformColumnTypes(#"Duplicated Column", {{"Remote VNET Id - Copy", type text}}, "en-US"), "Remote VNET Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"Remote VNET Id - Copy.1", "Remote VNET Id - Copy.2", "Remote VNET Id - Copy.3", "Remote VNET Id - Copy.4", "Remote VNET Id - Copy.5", "Remote VNET Id - Copy.6", "Remote VNET Id - Copy.7", "Remote VNET Id - Copy.8", "Remote VNET Id - Copy.9"}),
|
||||
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Remote VNET Id - Copy.1", type text}, {"Remote VNET Id - Copy.2", type text}, {"Remote VNET Id - Copy.3", type text}, {"Remote VNET Id - Copy.4", type text}, {"Remote VNET Id - Copy.5", type text}, {"Remote VNET Id - Copy.6", type text}, {"Remote VNET Id - Copy.7", type text}, {"Remote VNET Id - Copy.8", type text}, {"Remote VNET Id - Copy.9", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type1",{"Remote VNET Id - Copy.1", "Remote VNET Id - Copy.2", "Remote VNET Id - Copy.3", "Remote VNET Id - Copy.4", "Remote VNET Id - Copy.5", "Remote VNET Id - Copy.6", "Remote VNET Id - Copy.7", "Remote VNET Id - Copy.8"}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Removed Columns",{{"Remote VNET Id - Copy.9", "Remote VNET Name"}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Renamed Columns3",{"SubscriptionId", "Subscription Name"}),
|
||||
#"Duplicated Column1" = Table.DuplicateColumn(#"Removed Columns1", "IP Configuration Id", "IP Configuration Id - Copy"),
|
||||
#"Split Column by Delimiter1" = Table.SplitColumn(#"Duplicated Column1", "IP Configuration Id - Copy", Splitter.SplitTextByDelimiter("/ipConfigurations", QuoteStyle.Csv), {"IP Configuration Id - Copy.1", "IP Configuration Id - Copy.2"}),
|
||||
#"Changed Type2" = Table.TransformColumnTypes(#"Split Column by Delimiter1",{{"IP Configuration Id - Copy.1", type text}, {"IP Configuration Id - Copy.2", type text}}),
|
||||
#"Renamed Columns4" = Table.RenameColumns(#"Changed Type2",{{"IP Configuration Id - Copy.1", "NIC Id"}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Renamed Columns4",{"IP Configuration Id - Copy.2"}),
|
||||
#"Replaced Value" = Table.ReplaceValue(#"Removed Columns2","Null","Azure Provided",Replacer.ReplaceText,{"dnsServers"}),
|
||||
#"Renamed Columns5" = Table.RenameColumns(#"Replaced Value",{{"enableDdosProtection", "DDoS Protection"}}),
|
||||
#"Changed Type3" = Table.TransformColumnTypes(#"Renamed Columns5",{{"DDoS Protection", type text}}),
|
||||
#"Replaced Value1" = Table.ReplaceValue(#"Changed Type3","false","Disabled",Replacer.ReplaceText,{"DDoS Protection"}),
|
||||
#"Replaced Value2" = Table.ReplaceValue(#"Replaced Value1","true","Enabled",Replacer.ReplaceText,{"DDoS Protection"})
|
||||
in
|
||||
#"Replaced Value2"
|
||||
|
||||
// ListVirtualNetworks
|
||||
let ListVirtualNetworks = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/providers/Microsoft.Network/virtualNetworks?api-version=2017-09-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"name", "id", "etag", "type", "location", "properties", "tags"}, {"name", "id", "etag", "type", "location", "properties", "tags"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"name", "VNET Name"}, {"id", "VNET Id"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns",{"etag"}),
|
||||
#"Expanded properties" = Table.ExpandRecordColumn(#"Removed Columns", "properties", {"provisioningState", "resourceGuid", "addressSpace", "subnets", "virtualNetworkPeerings", "enableDdosProtection", "enableVmProtection", "dhcpOptions"}, {"provisioningState", "resourceGuid", "addressSpace", "subnets", "virtualNetworkPeerings", "enableDdosProtection", "enableVmProtection", "dhcpOptions"}),
|
||||
#"Expanded addressSpace" = Table.ExpandRecordColumn(#"Expanded properties", "addressSpace", {"addressPrefixes"}, {"addressPrefixes"}),
|
||||
#"Extracted Values" = Table.TransformColumns(#"Expanded addressSpace", {"addressPrefixes", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Expanded subnets" = Table.ExpandListColumn(#"Extracted Values", "subnets"),
|
||||
#"Expanded subnets1" = Table.ExpandRecordColumn(#"Expanded subnets", "subnets", {"name", "id", "properties"}, {"name", "id", "properties"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded subnets1",{{"name", "Subnet Name"}, {"id", "Subnet Id"}}),
|
||||
#"Expanded properties1" = Table.ExpandRecordColumn(#"Renamed Columns1", "properties", {"provisioningState", "addressPrefix", "ipConfigurations", "serviceEndpoints", "routeTable"}, {"provisioningState.1", "addressPrefix", "ipConfigurations", "serviceEndpoints", "routeTable"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Expanded properties1",{"provisioningState.1"}),
|
||||
#"Expanded ipConfigurations" = Table.ExpandListColumn(#"Removed Columns1", "ipConfigurations"),
|
||||
#"Expanded ipConfigurations1" = Table.ExpandRecordColumn(#"Expanded ipConfigurations", "ipConfigurations", {"id"}, {"id"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Expanded ipConfigurations1",{{"id", "IP Configuration Id"}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Renamed Columns2", "VNET Id", "VNET Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "VNET Id - Copy", Splitter.SplitTextByDelimiter("/", QuoteStyle.Csv), {"VNET Id - Copy.1", "VNET Id - Copy.2", "VNET Id - Copy.3", "VNET Id - Copy.4", "VNET Id - Copy.5", "VNET Id - Copy.6", "VNET Id - Copy.7", "VNET Id - Copy.8", "VNET Id - Copy.9"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"VNET Id - Copy.1", type text}, {"VNET Id - Copy.2", type text}, {"VNET Id - Copy.3", type text}, {"VNET Id - Copy.4", type text}, {"VNET Id - Copy.5", type text}, {"VNET Id - Copy.6", type text}, {"VNET Id - Copy.7", type text}, {"VNET Id - Copy.8", type text}, {"VNET Id - Copy.9", type text}}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Changed Type",{{"VNET Id - Copy.3", "Subscription Id"}}),
|
||||
#"Removed Columns2" = Table.RemoveColumns(#"Renamed Columns3",{"VNET Id - Copy.1", "VNET Id - Copy.2"}),
|
||||
#"Renamed Columns4" = Table.RenameColumns(#"Removed Columns2",{{"VNET Id - Copy.5", "Resource Group"}}),
|
||||
#"Removed Columns3" = Table.RemoveColumns(#"Renamed Columns4",{"VNET Id - Copy.4", "VNET Id - Copy.6", "VNET Id - Copy.7", "VNET Id - Copy.8", "VNET Id - Copy.9"}),
|
||||
#"Expanded virtualNetworkPeerings" = Table.ExpandListColumn(#"Removed Columns3", "virtualNetworkPeerings"),
|
||||
#"Expanded virtualNetworkPeerings1" = Table.ExpandRecordColumn(#"Expanded virtualNetworkPeerings", "virtualNetworkPeerings", {"name", "id", "etag", "properties"}, {"name", "id", "etag", "properties"}),
|
||||
#"Renamed Columns5" = Table.RenameColumns(#"Expanded virtualNetworkPeerings1",{{"id", "VNET Peering Id"}, {"name", "VNET Peering Name"}}),
|
||||
#"Removed Columns4" = Table.RemoveColumns(#"Renamed Columns5",{"etag"}),
|
||||
#"Expanded properties2" = Table.ExpandRecordColumn(#"Removed Columns4", "properties", {"provisioningState", "peeringState", "remoteVirtualNetwork", "allowVirtualNetworkAccess", "allowForwardedTraffic", "allowGatewayTransit", "useRemoteGateways", "remoteAddressSpace"}, {"provisioningState.1", "peeringState", "remoteVirtualNetwork", "allowVirtualNetworkAccess", "allowForwardedTraffic", "allowGatewayTransit", "useRemoteGateways", "remoteAddressSpace"}),
|
||||
#"Removed Columns5" = Table.RemoveColumns(#"Expanded properties2",{"provisioningState.1"}),
|
||||
#"Renamed Columns6" = Table.RenameColumns(#"Removed Columns5",{{"peeringState", "VNET peeringState"}}),
|
||||
#"Expanded remoteVirtualNetwork" = Table.ExpandRecordColumn(#"Renamed Columns6", "remoteVirtualNetwork", {"id"}, {"id"}),
|
||||
#"Renamed Columns7" = Table.RenameColumns(#"Expanded remoteVirtualNetwork",{{"id", "Remote VNET Id"}}),
|
||||
#"Expanded remoteAddressSpace" = Table.ExpandRecordColumn(#"Renamed Columns7", "remoteAddressSpace", {"addressPrefixes"}, {"addressPrefixes.1"}),
|
||||
#"Extracted Values1" = Table.TransformColumns(#"Expanded remoteAddressSpace", {"addressPrefixes.1", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Replaced Errors" = Table.ReplaceErrorValues(#"Extracted Values1", {{"addressPrefixes.1", "Null"}}),
|
||||
#"Removed Columns6" = Table.RemoveColumns(#"Replaced Errors",{"tags"}),
|
||||
#"Expanded dhcpOptions" = Table.ExpandRecordColumn(#"Removed Columns6", "dhcpOptions", {"dnsServers"}, {"dnsServers"}),
|
||||
#"Extracted Values2" = Table.TransformColumns(#"Expanded dhcpOptions", {"dnsServers", each Text.Combine(List.Transform(_, Text.From)), type text}),
|
||||
#"Replaced Errors1" = Table.ReplaceErrorValues(#"Extracted Values2", {{"dnsServers", "Null"}}),
|
||||
#"Removed Columns7" = Table.RemoveColumns(#"Replaced Errors1",{"type"}),
|
||||
#"Renamed Columns8" = Table.RenameColumns(#"Removed Columns7",{{"addressPrefixes", "VNET addressPrefixes"}, {"addressPrefix", "Subnet addressPrefix"}}),
|
||||
#"Expanded routeTable" = Table.ExpandRecordColumn(#"Renamed Columns8", "routeTable", {"id"}, {"id"}),
|
||||
#"Renamed Columns9" = Table.RenameColumns(#"Expanded routeTable",{{"id", "Route Table id"}, {"addressPrefixes.1", "Remote VNET addressPrefixes"}})
|
||||
in
|
||||
#"Renamed Columns9"
|
||||
in
|
||||
ListVirtualNetworks
|
||||
|
||||
// Resources
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId", "displayName"}, {"subscriptionId", "displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"displayName", "Subscription Name"}}),
|
||||
#"Invoked Custom Function" = Table.AddColumn(#"Renamed Columns", "ListResources", each ListResources([subscriptionId])),
|
||||
#"Removed Errors" = Table.RemoveRowsWithErrors(#"Invoked Custom Function", {"ListResources"}),
|
||||
#"Expanded ListResources" = Table.ExpandTableColumn(#"Removed Errors", "ListResources", {"Resource Id", "Resource Name", "Resource Type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1", "name", "tier", "capacity", "size", "family", "kind", "name.1", "promotionCode", "product", "publisher", "managedBy", "Resource Group Id"}, {"Resource Id", "Resource Name", "Resource Type", "location", "creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1", "name", "tier", "capacity", "size", "family", "kind", "name.1", "promotionCode", "product", "publisher", "managedBy", "Resource Group Id"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListResources",{"subscriptionId", "Subscription Name"}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Removed Columns", each true),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Filtered Rows", "Container Type", each if Text.Contains([Resource Type], "containerGroups") then "ACI" else if Text.Contains([Resource Type], "managedClusters") then "AKS" else if Text.Contains([Resource Type], "containerServices") then "ACS" else null),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Added Conditional Column", "Resource Group Id", "Resource Group Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Group Id - Copy", Splitter.SplitTextByDelimiter("/resourceGroups/", QuoteStyle.Csv), {"Resource Group Id - Copy.1", "Resource Group Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Group Id - Copy.1", type text}, {"Resource Group Id - Copy.2", type text}}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Changed Type",{"Resource Group Id - Copy.1"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns1",{{"Resource Group Id - Copy.2", "Resource Group Name"}})
|
||||
in
|
||||
#"Renamed Columns1"
|
||||
|
||||
// ListResources
|
||||
let ListResources = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/resources?api-version=2017-05-10")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"id", "name", "type", "location", "tags", "sku", "kind", "plan", "managedBy"}, {"id", "name", "type", "location", "tags", "sku", "kind", "plan", "managedBy"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"id", "Resource Id"}, {"name", "Resource Name"}, {"type", "Resource Type"}}),
|
||||
#"Expanded tags" = Table.ExpandRecordColumn(#"Renamed Columns", "tags", {"creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroups/WebappforcontainersCedwards/providers/Microsoft.Web/serverfarms/ServicePlanb8fd2fe5-b45f", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGroups/WebAppRG/providers/Microsoft.Web/serverfarms/cedwardWebApp1"}, {"creationSource", "orchestrator", "poolName", "resourceNameSuffix", "created-by", "displayName", "ms-resource-usage", "ContainerTag", "service", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourcegroup", "hidden-related:/subscriptions/02fd7403-de8f-4ea6-8ab4-6f00f0b4a808/resourceGro.1"}),
|
||||
#"Expanded sku" = Table.ExpandRecordColumn(#"Expanded tags", "sku", {"name", "tier", "capacity", "size", "family"}, {"name", "tier", "capacity", "size", "family"}),
|
||||
#"Expanded plan" = Table.ExpandRecordColumn(#"Expanded sku", "plan", {"name", "promotionCode", "product", "publisher"}, {"name.1", "promotionCode", "product", "publisher"}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Expanded plan", "Resource Id", "Resource Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "Resource Id - Copy", Splitter.SplitTextByDelimiter("/providers", QuoteStyle.Csv), {"Resource Id - Copy.1", "Resource Id - Copy.2"}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"Resource Id - Copy.1", type text}, {"Resource Id - Copy.2", type text}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Changed Type",{"Resource Id - Copy.2"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{"Resource Id - Copy.1", "Resource Group Id"}})
|
||||
in
|
||||
#"Renamed Columns1"in
|
||||
ListResources
|
||||
|
||||
// VNET Peerings
|
||||
let
|
||||
Source = Table.NestedJoin(#"Virtual Networks",{"Remote VNET Id"},Resources,{"Resource Id"},"Resources",JoinKind.LeftOuter),
|
||||
#"Expanded Resources" = Table.ExpandTableColumn(Source, "Resources", {"location"}, {"location.1"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Resources",{{"location.1", "Remote VNET Location"}}),
|
||||
#"Filtered Rows" = Table.SelectRows(#"Renamed Columns", each [VNET Peering Id] <> null and [VNET Peering Id] <> ""),
|
||||
#"Merged Queries" = Table.NestedJoin(#"Filtered Rows",{"location"},#"Azure Regions",{"AzureLocation"},"Azure Regions",JoinKind.LeftOuter),
|
||||
#"Expanded Azure Regions" = Table.ExpandTableColumn(#"Merged Queries", "Azure Regions", {"Longitude", "Latitude"}, {"Longitude", "Latitude"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Expanded Azure Regions",{{"Longitude", "Source Longitude"}, {"Latitude", "Source Latitude"}}),
|
||||
#"Merged Queries1" = Table.NestedJoin(#"Renamed Columns1",{"Remote VNET Location"},#"Azure Regions",{"AzureLocation"},"Azure Regions",JoinKind.LeftOuter),
|
||||
#"Expanded Azure Regions1" = Table.ExpandTableColumn(#"Merged Queries1", "Azure Regions", {"Longitude", "Latitude"}, {"Longitude", "Latitude"}),
|
||||
#"Renamed Columns2" = Table.RenameColumns(#"Expanded Azure Regions1",{{"Longitude", "Remote Longitude"}, {"Latitude", "Remote Latitude"}}),
|
||||
#"Changed Type" = Table.TransformColumnTypes(#"Renamed Columns2",{{"Source Longitude", type number}, {"Source Latitude", type number}, {"Remote Longitude", type number}, {"Remote Latitude", type number}}),
|
||||
#"Duplicated Column" = Table.DuplicateColumn(#"Changed Type", "VNET Id", "VNET Id - Copy"),
|
||||
#"Split Column by Delimiter" = Table.SplitColumn(#"Duplicated Column", "VNET Id - Copy", Splitter.SplitTextByDelimiter("/resourceGroup", QuoteStyle.Csv), {"VNET Id - Copy.1", "VNET Id - Copy.2"}),
|
||||
#"Changed Type1" = Table.TransformColumnTypes(#"Split Column by Delimiter",{{"VNET Id - Copy.1", type text}, {"VNET Id - Copy.2", type text}}),
|
||||
#"Renamed Columns3" = Table.RenameColumns(#"Changed Type1",{{"VNET Id - Copy.1", "Subscription Id"}}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Renamed Columns3",{"VNET Id - Copy.2"}),
|
||||
#"Added Conditional Column" = Table.AddColumn(#"Removed Columns", "Peering Type", each if [location] = [Remote VNET Location] then "VNET Peering" else "Global VNET Peering"),
|
||||
#"Added Conditional Column1" = Table.AddColumn(#"Added Conditional Column", "PeeringImage", each if [Peering Type] = "VNET Peering" then "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/VNETPeering.svg?sanitize=true" else "https://raw.githubusercontent.com/JSFCES/DashboardImages/master/GlobalVNETPeering.svg?sanitize=true")
|
||||
in
|
||||
#"Added Conditional Column1"
|
||||
|
||||
// Azure Regions
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions?api-version=2016-06-01")),
|
||||
value = Source[value],
|
||||
#"Converted to Table" = Table.FromList(value, Splitter.SplitByNothing(), null, null, ExtraValues.Error),
|
||||
#"Expanded Column1" = Table.ExpandRecordColumn(#"Converted to Table", "Column1", {"subscriptionId","displayName"}, {"Column1.subscriptionId","Column1.displayName"}),
|
||||
#"Renamed Columns" = Table.RenameColumns(#"Expanded Column1",{{"Column1.subscriptionId", "SubscriptionId"}, {"Column1.displayName", "Subscription Name"}}),
|
||||
#"List AzureLocations" = Table.AddColumn(#"Renamed Columns", " ListAzureLocations", each ListAzureLocations([SubscriptionId])),
|
||||
#"Expanded ListAzureLocations" = Table.ExpandTableColumn(#"List AzureLocations", " ListAzureLocations", {"Name", "Value.id", "Value.name", "Value.displayName", "Value.longitude", "Value.latitude"}, {" ListAzureLocations.Name", " ListAzureLocations.Value.id", " ListAzureLocations.Value.name", " ListAzureLocations.Value.displayName", " ListAzureLocations.Value.longitude", " ListAzureLocations.Value.latitude"}),
|
||||
#"Removed Columns" = Table.RemoveColumns(#"Expanded ListAzureLocations",{" ListAzureLocations.Name", " ListAzureLocations.Value.id"}),
|
||||
#"Renamed Columns1" = Table.RenameColumns(#"Removed Columns",{{" ListAzureLocations.Value.name", "AzureLocation"}, {" ListAzureLocations.Value.displayName", "Azure Location Display Name"}, {" ListAzureLocations.Value.longitude", "Longitude"}, {" ListAzureLocations.Value.latitude", "Latitude"}}),
|
||||
#"Removed Duplicates" = Table.Distinct(#"Renamed Columns1", {"AzureLocation"}),
|
||||
#"Removed Columns1" = Table.RemoveColumns(#"Removed Duplicates",{"SubscriptionId", "Subscription Name"})
|
||||
in
|
||||
#"Removed Columns1"
|
||||
|
||||
// ListAzureLocations
|
||||
let ListAzureLocations = (subscriptionId as text) =>
|
||||
let
|
||||
Source = Json.Document(Web.Contents("https://management.azure.com/subscriptions/"&subscriptionId&"/locations?api-version=2016-06-01")),
|
||||
#"Converted to Table" = Record.ToTable(Source),
|
||||
#"Expanded Value" = Table.ExpandListColumn(#"Converted to Table", "Value"),
|
||||
#"Expanded Value1" = Table.ExpandRecordColumn(#"Expanded Value", "Value", {"id", "name", "displayName", "longitude", "latitude"}, {"Value.id", "Value.name", "Value.displayName", "Value.longitude", "Value.latitude"})
|
||||
in
|
||||
#"Expanded Value1"
|
||||
in
|
||||
ListAzureLocations
|