diff --git a/README.md b/README.md
index dd927795..7bf25ac4 100644
--- a/README.md
+++ b/README.md
@@ -36,34 +36,62 @@ Included in the Microsoft Cloud Adoption Framework´s [Strategy-Plan-Ready-Gov](
-## AzGovViz release history
+## Table of contents
+* [Release history](#release-history)
+* [Demo](#demo)
+* [Features](#features)
+* [Screenshots](#screenshots)
+* [Outputs](#outputs)
+* [Slideset](#slideset)
+* [Technical documentation](#technical-documentation)
+ * [Permissions overview](#permissions-overview)
+ * [Required permissions in Azure](#required-permissions-in-azure)
+ * [Required permissions in Azure Active Directory](#required-permissions-in-azure-active-directory)
+ * [PowerShell](#powershell)
+ * [Parameters](#parameters)
+* [AzGovViz step by step](#azgovviz-step-by-step)
+ * [AzGovViz in Azure DevOps](#azgovviz-in-azure-devops)
+* [Integrate with AzOps](#integrate-with-azops)
+* [Security](#security)
+* [Facts](#facts)
+* [Contributions](#contributions)
+* [AzAdvertizer](#azadvertizer)
+* [Final note](#final-note)
-__Changes__ (2021-July-07 / Major)
+
+
+## Release history
-* Replaced parameters `-NoScopeInsights`, `-RBACAtScopeOnly` and `-PolicyAtScopeOnly` with `-LargeTenant`. A large tenant is a tenant with more than ~500 Subscriptions - the HTML output for large tenants simply becomes too big, therefore will not create __ScopeInsights__ and will not show inheritance for Policy and Role assignments in the __TenantSummary__ (html) output
-* Add Tenant to __HierarchyMap__ including count of Role assignments
-* Executing against any child Management Group will show all parent Management Groups in __HierarchyMap__
-* Cosmetics / Icons
+__Changes__ (2021-July-22 / Major)
+
+* Full blown JSON definition output. Leveraging Git with this new capability you can easily track any changes that occurred in between the previous and last AzGovViz run.
+![newBuiltInRoleDefinition](img/gitdiff600.jpg)
+_* a new BuiltIn RBAC Role definition was added_
+* Renamed parameter `-PolicyIncludeResourceGroups` to , `-DoNotIncludeResourceGroupsOnPolicy` (from now Policy assignments on ResourceGroups will be included by default)
+* Renamed parameter `-RBACIncludeResourceGroupsAndResources` to , `-DoNotIncludeResourceGroupsAndResourcesOnRBAC` (from now Role assignments on ResourceGroups and Resources will be included by default)
+* New parameter `-HtmlTableRowsLimit`. Although the parameter `-LargeTenant` was introduced recently, still the html output may become too large to be processed properly. The new parameter defines the limit of rows - if for the html processing part the limit is reached then the html table will not be created (csv and json output will still be created). Default rows limit is 40.000.
+* Added NonCompliance Message for Policy assignments
+* Cosmetics
* Bugfixes
-* Performance optimization - optimized data collection to reduce memory utilization -> __big, fat 'Thank You'__ to Tim Wanierke and Brooks Vaughn
+* Performance optimization
[Release history](history.md)
-## AzGovViz in Action
+## Demo
-![Demo](img/demo4_66.png)
+![Demo](img/demo4_66.png)
-[Demo (v5_major_20210607_2)](https://www.azadvertizer.net/azgovvizv4/demo/AzGovViz_Enterprise-Scale_WingTip_v5_major_20210607_2.html)
+[Demo (v5_major_20210721_1)](https://www.azadvertizer.net/azgovvizv4/demo/AzGovViz_Enterprise-Scale_WingTip_v5_major_202107021_1.html)
Enterprise-Scale ([WingTip](https://github.com/Azure/Enterprise-Scale/blob/main/docs/reference/wingtip/README.md)) implementation
-### Features
+## Features
* __Hierarchy of Management Groups__
- * Builds a visual hierarchy of your Management Group setup including count of linked Subscriptions
+ * Builds a visual hierarchy of your Management Group setup including counts on linked Subscriptions, Policy assignments, scoped Policy/Set definitions and Role assignments per Management Group
* __Azure Policy__
* Custom Policy definitions
* Scope information
@@ -71,7 +99,7 @@ Enterprise-Scale ([WingTip](https://github.com/Azure/Enterprise-Scale/blob/main/
* If Policy effect is DeployIfNotExists (DINE) will show the specified RBAC Role
* List of assignments
* Usage in custom PolicySet definitions
- * System metadata 'createdOn, createdBy, updatedOn, updatedBy'
+ * System metadata 'createdOn, createdBy, updatedOn, updatedBy' ('createdBy', 'updatedBy' identity is fully resolved)
* Orphaned custom Policy definitions
* List of custom Policy definitions that matches the following criteria:
* Policy definition is not used in any custom PolicySet definition
@@ -88,19 +116,20 @@ Enterprise-Scale ([WingTip](https://github.com/Azure/Enterprise-Scale/blob/main/
* Lists all Exemptions (scopes: Management Groups, Subscriptions, ResourceGroups, Resources)
* Enrich information on Exemption scope
* Summary on expired Exemptions
- * Policy assignments throughout the entirety of scopes (Management Groups, Subscriptions)
+ * Policy assignments throughout the entirety of scopes (Management Groups, Subscriptions and Resource Groups)
* Core information on Policy assignments
+ * NonCompliance Message on Policy assignment for a PolicySet will only show the default non-compliance message
* Advanced/enriched information on Policy assignments
* Policy assignment scope (at scope/inheritance)
* Indicates if scope is excluded from Policy assignment
* Indicates if Exemption applies for scope
* Policy/Resource Compliance (Policy: NonCompliant, Compliant; Resource: NonCompliant, Compliant, Conflicting)
* Related RBAC Role assignments (if Policy effect is DeployIfNotExists (DINE))
- * System metadata 'createdOn, createdBy, updatedOn, updatedBy'
+ * System metadata 'createdOn, createdBy, updatedOn, updatedBy' ('createdBy', 'updatedBy' identity is fully resolved)
* __Role-Based Access Control (RBAC)__
* Custom Role definitions
* List assignable scopes
- * System metadata 'createdOn, createdBy, updatedOn, updatedBy'
+ * System metadata 'createdOn, createdBy, updatedOn, updatedBy' ('createdBy', 'updatedBy' identity is fully resolved)
* Orphaned custom Role definitions
* List of custom Role definitions that matches the following criteria:
* Role definition is not used in any Role assignment
@@ -109,7 +138,7 @@ Enterprise-Scale ([WingTip](https://github.com/Azure/Enterprise-Scale/blob/main/
* List of Role assignments that matches the following criteria:
* Role definition was deleted although and assignment existed
* Role assignmet's target identity (User, Group, ServicePrincipal) was deleted
- * Role assignments throughout the entirety of scopes (Management Groups, Subscriptions)
+ * Role assignments throughout the entirety of scopes (Management Groups, Subscriptions, Resource Groups and Resources)
* Core information on Role assignments
* Advanced information on Role assignments
* Role assignment scope (at scope / inheritance)
@@ -117,7 +146,7 @@ Enterprise-Scale ([WingTip](https://github.com/Azure/Enterprise-Scale/blob/main/
* For identity-type == 'ServicePrincipal' the type (Application/ManagedIdentity) will be reported
* For identity-type == 'User' the userType (Member/Guest) will be reported
* Related Policy assignments (Policy assignment of a Policy definition that uses the DeployIfNotExists (DINE) effect)
- * System metadata 'createdOn, createdBy'
+ * System metadata 'createdOn, createdBy' ('createdBy' identity is fully resolved)
* Role assignments ClassicAdministrators
* Security & Best practice analysis
* Existence of custom Role definition that reflect 'Owner' permissions
@@ -193,7 +222,7 @@ Enterprise-Scale ([WingTip](https://github.com/Azure/Enterprise-Scale/blob/main/
-### Screenshots
+## Screenshots
HTML file
@@ -211,8 +240,10 @@ markdown in Azure DevOps Wiki as Code
![alt text](img/AzDO_md_v4.png "Azure DevOps Wiki as Code")
*_IDs from screenshot are randomized_
+> Note: there is some fixing ongoing at the mermaid project to optimize the graphical experience:
+
-### Outputs
+## Outputs
* CSV file
* HTML file
@@ -220,16 +251,19 @@ markdown in Azure DevOps Wiki as Code
* Browsers tested: Edge, new Edge and Chrome
* MD (Markdown) file
* for use with Azure DevOps Wiki leveraging the [Mermaid](https://docs.microsoft.com/en-us/azure/devops/release-notes/2019/sprint-158-update#mermaid-diagram-support-in-wiki) plugin
-* JSON file (_experimental_)
- * export of ManagementGroup Hierarchy including all MG/Sub Policy/RBAC definitions, Policy/RBAC assignments and some more relevant information to JSON
-> Note: there is some fixing ongoing at the mermaid project to optimize the graphical experience:
-
+* JSON folder containing
+ * all Policy and Role assignments (Scopes: Tenant, Management Groups and Subscriptions)
+ * all BuiltIn and Custom Policy/Set definitions (Scopes: Management Groups and Subscriptions)
+ * all BuiltIn and Custom Role definitions
+ * JSON file of ManagementGroup Hierarchy including all Custom Policy/Set and RBAC definitions, Policy and Role assignments and some more relevant information
+ * Tenant tree including all Policy and Role assignments AND all Custom Policy/Set and Role definitions
+ ![alt text](img/jsonfolderfull450.jpg "JSONFolder")
-## AzGovViz slideset
+## Slideset
Short presentation on AzGovViz [Download](slides/AzGovViz_intro.pdf)
-## AzGovViz technical documentation
+## Technical documentation
### Permissions overview
@@ -348,9 +382,7 @@ This permission is mandatory in each and every scenario!
-### Usage
-
-#### PowerShell
+### PowerShell
* Requires PowerShell 7 (minimum supported version 7.0.3)
* [Get PowerShell](https://github.com/PowerShell/PowerShell#get-powershell)
@@ -361,9 +393,10 @@ This permission is mandatory in each and every scenario!
* Az.Resources
* ~~Az.ResourceGraph~~
* [Install the Azure Az PowerShell module](https://docs.microsoft.com/en-us/powershell/azure/install-az-ps)
-* Usage
+* Usage/command
* `.\AzGovVizParallel.ps1 -ManagementGroupId `
-* Parameters
+
+### Parameters
* `-ManagementGroupId` Management Group Id (Root Management Group Id equals your Tenant Id)
* `-CsvDelimiter` the world is split into two kinds of delimiters - comma and semicolon - choose yours (default is semicolon ';')
* `-OutputPath`
@@ -383,24 +416,29 @@ This permission is mandatory in each and every scenario!
* `-NoAzureConsumption` Azure Consumption data should not be collected/reported
* `-AzureConsumptionPeriod` define for which time period Azure Consumption data should be gathered; default is 1 day
* `-NoAzureConsumptionReportExportToCSV` Azure Consumption data should not be exported (CSV)
- * ~~`-NoScopeInsights`~~ Use `-LargeTenant` - Q: Why would you want to do this? A: In larger tenants the ScopeInsights section blows up the html file (up to unusable due to html file size)
+ * `-NoScopeInsights` - Q: Why would you want to do this? A: In larger tenants the ScopeInsights section blows up the html file (up to unusable due to html file size). Use `-LargeTenant` to further reduce the output.
* `-ThrottleLimit` - leveraging PowerShell´s parallel capability you can define the ThrottleLimit (default=5; 💡 values from 5 up to 15 proved to perform best)
* `-DoTranscript` - log the console output
* `-SubscriptionId4AzContext` - Define the Subscription Id to use for AzContext (default is to use a random Subscription Id)
* ~~`-PolicyAtScopeOnly`~~ Use `-LargeTenant` - removing 'inherited' lines in the HTML file for 'Policy Assignments'; use this parameter if you run against a larger tenants
* ~~`-RBACAtScopeOnly`~~ Use `-LargeTenant` - removing 'inherited' lines in the HTML file for 'Role Assignments'; use this parameter if you run against a larger tenants
* ~~`-CsvExport`~~ `-NoCsvExport` - do not export enriched data for 'Role assignments', 'Policy assignments' data and 'all resources' (subscriptionId, managementGroup path, resourceType, id, name, location, tags, createdTime, changedTime)
- * `-PolicyIncludeResourceGroups` - include Policy assignments on ResourceGroups
- * `-RBACIncludeResourceGroupsAndResources` - include Role assignments on ResourceGroups and Resources
+ * ~~`-PolicyIncludeResourceGroups`~~ `-DoNotIncludeResourceGroupsOnPolicy` - do not include Policy assignments on ResourceGroups
+ * ~~`-RBACIncludeResourceGroupsAndResources`~~ `-DoNotIncludeResourceGroupsAndResourcesOnRBAC` - do not include Role assignments on ResourceGroups and Resources
* `-ChangeTrackingDays` - define the period for Change tracking on newly created and updated custom Policy, PolicySet and RBAC Role definitions and Policy/RBAC Role assignments (default is '14')
* `-FileTimeStampFormat`- define the time format for the output files (default is `yyyyMMdd_HHmmss`)
* ~~`-JsonExport`~~ `-NoJsonExport` - do not enable export of ManagementGroup Hierarchy including all MG/Sub Policy/RBAC definitions, Policy/RBAC assignments and some more relevant information to JSON
- * `-LargeTenant` - A large tenant is a tenant with more than ~500 Subscriptions - the HTML output for large tenants simply becomes too big, therefore will not create __ScopeInsights__ and will not show inheritance for Policy and Role assignments in the __TenantSummary__ (html) output
+ * `-LargeTenant` - a large tenant is a tenant with more than ~500 Subscriptions - the HTML output for large tenants simply becomes too big, therefore will not create __ScopeInsights__ and will not show inheritance for Policy and Role assignments in the __TenantSummary__ (html) output
+ * `-HtmlTableRowsLimit` - Although the parameter `-LargeTenant` was introduced recently, still the html output may become too large to be processed properly. The new parameter defines the limit of rows - if for the html processing part the limit is reached then the html table will not be created (csv and json output will still be created). Default rows limit is 40.000.
* Passed tests: Powershell Core 7.1.2 on Windows
* Passed tests: Powershell Core 7.1.3 Azure DevOps hosted ubuntu-18.04
-#### Azure DevOps Pipeline
+## AzGovViz step by step
+
+Detailed __[Setup](setup.md) instructions__
+
+### AzGovViz in Azure DevOps
The provided example Pipeline is configured to run based on a [schedule](https://docs.microsoft.com/en-us/azure/devops/pipelines/process/scheduled-triggers) (every 12 hours). It will push the AzGovViz markdown output file to the 'wiki' folder in the 'Azure-MG-Sub-Governance-Reporting' Repository which will feed your Wiki.
@@ -414,20 +452,33 @@ The provided example Pipeline is configured to run based on a [schedule](https:/
> Make sure your Service Connection´s Service Principal has been granted with the required permissions (see [__Required permissions in Azure Active Directory__](#required-permissions-in-azure-active-directory)).
-## AzGovViz sidenotes
+## Integrate with AzOps
+
+Did you know you can run AzOps from Azure DevOps? Check [AzOps Accellerator](https://github.com/Azure/AzOps-Accelerator).
+You can integrate AzGovViz (same project as AzOps) by adding the following code to the AzGovViz pipeline (yml).
+
+```yaml
+ pipelines:
+ - pipeline: 'Push'
+ source: 'AzOps - Push'
+ trigger:
+ branches:
+ include:
+ - master
+```
-### Security
+## Security
AzGovViz creates very detailed information about your Azure Governance setup. In your organization's best interest the __outputs should be protected from not authorized access!__
-### Facts
+## Facts
Disabled Subscriptions and Subscriptions where Quota Id starts with with "AAD_" are being skipped, all others are queried. More info on Quota Id / Offer numbers: Supported Microsoft Azure offers
.
ARM Limits are not acquired programmatically, they are hardcoded. The links used to check related Limits are commented in the param section of the script.
-### Contributions
+## Contributions
Please feel free to contribute. Thanks to so many supporters - testing, giving feedback, making suggestions, presenting use-case, posting/blogging articles, refactoring code - THANK YOU!
diff --git a/history.md b/history.md
index 34d617d1..880e5b13 100644
--- a/history.md
+++ b/history.md
@@ -4,9 +4,22 @@
### AzGovViz version 5
+__Changes__ (2021-July-22 / Major)
+
+* Full blown JSON definition output. Leveraging Git with this new capability you can easily track any changes that occurred in between the previous and last AzGovViz run.
+![newBuiltInRoleDefinition](img/gitdiff600.jpg)
+_* a new BuiltIn RBAC Role definition was added_
+* Renamed parameter `-PolicyIncludeResourceGroups` to , `-DoNotIncludeResourceGroupsOnPolicy` (from now Policy assignments on ResourceGroups will be included by default)
+* Renamed parameter `-RBACIncludeResourceGroupsAndResources` to , `-DoNotIncludeResourceGroupsAndResourcesOnRBAC` (from now Role assignments on ResourceGroups and Resources will be included by default)
+* New parameter `-HtmlTableRowsLimit`. Although the parameter `-LargeTenant` was introduced recently, still the html output may become too large to be processed properly. The new parameter defines the limit of rows - if for the html processing part the limit is reached then the html table will not be created (csv and json output will still be created). Default rows limit is 40.000.
+* Added NonCompliance Message for Policy assignments
+* Cosmetics
+* Bugfixes
+* Performance optimization
+
__Changes__ (2021-July-07 / Major)
-* Replaced parameters `-NoScopeInsights`, `-RBACAtScopeOnly` and `-PolicyAtScopeOnly` with `-LargeTenant`. A large tenant is a tenant with more than ~500 Subscriptions - the HTML output for large tenants simply becomes too big, therefore will not create __ScopeInsights__ and will not show inheritance for Policy and Role assignments in the __TenantSummary__ (html) output
+* Replaced parameters ~~`-NoScopeInsights`,~~ `-RBACAtScopeOnly` and `-PolicyAtScopeOnly` with `-LargeTenant`. A large tenant is a tenant with more than ~500 Subscriptions - the HTML output for large tenants simply becomes too big, therefore will not create __ScopeInsights__ and will not show inheritance for Policy and Role assignments in the __TenantSummary__ (html) output
* Add Tenant to __HierarchyMap__ including count of Role assignments
* Executing against any child Management Group will show all parent Management Groups in __HierarchyMap__
* Cosmetics / Icons
diff --git a/img/HierarchyMap.png b/img/HierarchyMap.png
index ad43ac21..956af2ef 100644
Binary files a/img/HierarchyMap.png and b/img/HierarchyMap.png differ
diff --git a/img/TenantSummary.png b/img/TenantSummary.png
index 23162f1a..4b6b26a3 100644
Binary files a/img/TenantSummary.png and b/img/TenantSummary.png differ
diff --git a/img/gitdiff600.jpg b/img/gitdiff600.jpg
new file mode 100644
index 00000000..18259f49
Binary files /dev/null and b/img/gitdiff600.jpg differ
diff --git a/img/jsonfolderfull450.jpg b/img/jsonfolderfull450.jpg
new file mode 100644
index 00000000..dbfb63c5
Binary files /dev/null and b/img/jsonfolderfull450.jpg differ
diff --git a/pipeline/AzGovViz.yml b/pipeline/AzGovViz.yml
index 3dcb4dbe..9c21e115 100644
--- a/pipeline/AzGovViz.yml
+++ b/pipeline/AzGovViz.yml
@@ -1,11 +1,11 @@
-# AzGovViz v5_major_20210707_3
+# AzGovViz v5_major_20210722_1
# First things first:
-# 1. edit line 52 and line 53
-# 2. check line 67 if branch 'master' is applicable
+# 1. edit line 54 and line 55
+# 2. check line 69 and 80 if branch 'master' is applicable
# Documentation: https://github.com/JulianHayward/Azure-MG-Sub-Governance-Reporting
# Also check https://www.azadvertizer.net - AzAdvertizer helps you to keep up with the pace by providing overview and insights on new releases and changes/updates for Azure Governance capabilities such as Azure Policy's policy definitions, initiatives (set definitions), aliases and Azure RBAC's role definitions and resource provider operations.
#
-# Parameters reference (use in line 102)
+# Parameters reference (use in line 105)
# LimitCriticalPercentage | default is '80' | example: -LimitCriticalPercentage 90 | WhatDoesItDo? marks capabilities that approch limits e.g. limit 100, usage 80 will mark with warning
# SubscriptionQuotaIdWhitelist | default is 'undefined' | example: -SubscriptionQuotaIdWhitelist MSDN_, EnterpriseAgreement_ | WhatDoesItDo? processes only subscriptions that startWith the given QuotaIds
# HierarchyMapOnly | switch | example: -HierarchyMapOnly | WhatDoesItDo? only creates the Hierarchy Tree
@@ -27,12 +27,14 @@
# AzureDevOpsWikiHierarchyDirection | example: -AzureDevOpsWikiHierarchyDirection "LR" | WhatDoesItDo? Define the direction the Hierarchy should be built in Azure DevOps WokiAsCode (Markdown) TD = TopDown (Horizontal), LR = LeftRight (Vertical)
# SubscriptionId4AzContext | example: -SubscriptionId4AzContext "" | WhatDoesItDo? Define the Subscription Id to use for AzContext (default is to use a random Subscription Id)
# NoCsvExport | example: -NoCsvExport | WhatDoesItDo? Do not export enriched 'Role assignments' data, enriched 'Policy assignments' data and 'all resources' (subscriptionId, resourceType, id, name, location, tags, createdTime, changedTime)
-# PolicyIncludeResourceGroups | example: -PolicyIncludeResourceGroups | WhatDoesItDo? Include Policy assignments on ResourceGroups
-# RBACIncludeResourceGroupsAndResources | example: -RBACIncludeResourceGroupsAndResources | WhatDoesItDo? Include Role assignments on ResourceGroups and Resources
+# DoNotIncludeResourceGroupsOnPolicy | example: -DoNotIncludeResourceGroupsOnPolicy | WhatDoesItDo? Do not include Policy assignments on ResourceGroups
+# DoNotIncludeResourceGroupsAndResourcesOnRBAC | example: -DoNotIncludeResourceGroupsAndResourcesOnRBAC | WhatDoesItDo? Do not include Role assignments on ResourceGroups and Resources
# ChangeTrackingDays | example: -ChangeTrackingDays 30 | WhatDoesItDo? Tracks newly created and updated custom Policy, PolicySet and RBAC Role definitions, Policy/RBAC Role assignments and Resources that occured within the last 14 days (default)
# FileTimeStampFormat | example: -FileTimeStampFormat "yyyyMM-dd_HHmm" | WhatDoesItDo? Time format for the output files (default is `yyyyMMdd_HHmmss`)
# NoJsonExport | example: -JsonExport | WhatDoesItDo? Do not export of ManagementGroup Hierarchy including all MG/Sub Policy/RBAC definitions, Policy/RBAC assignments and some more relevant information to JSON
+# NoScopeInsights | example: -NoScopeInsights | WhatDoesItDo? and why would you want to do this? In larger tenants the ScopeInsights section blows up the html file (up to unusable due to html file size). To further reduce the output use parameter -LargeTenant
# LargeTenant | example: -LargeTenant | WhatDoesItDo? A large tenant is a tenant with more than ~500 Subscriptions - the HTML output for large tenants simply becomes too big, therefore will not create ScopeInsights and will not show inheritance for Policy and Role assignments in the TenantSummary (html) output
+# HtmlTableRowsLimit | example: -HtmlTableRowsLimit | WhatDoesItDo? Although the parameter -LargeTenant was introduced recently, still the html output may become too large to be processed properly. The new parameter defines the limit of rows - if for the html processing part the limit is reached then the html table will not be created (csv and json output will still be created). Default rows limit is 40.000
trigger: none
@@ -66,7 +68,8 @@ schedules:
include:
- master
-#running ESLZ / AzOps? Run AzGovViz after Push ..
+#Running AzOps? Run AzGovViz after 'AzOps - Push' ..
+#AzOps Accellerator https://github.com/Azure/AzOps-Accelerator
#resources:
# pipelines:
# - pipeline: 'Push'
@@ -74,7 +77,7 @@ schedules:
# trigger:
# branches:
# include:
-# - main
+# - master
jobs:
- job: AzGovViz
diff --git a/pwsh/AzGovVizParallel.ps1 b/pwsh/AzGovVizParallel.ps1
index f6ee5a27..296da1ed 100644
--- a/pwsh/AzGovVizParallel.ps1
+++ b/pwsh/AzGovVizParallel.ps1
@@ -30,9 +30,6 @@
.PARAMETER NoASCSecureScore
default is to query all Subscriptions for Azure Security Center Secure Score. As the API is in preview you may want to disable it.
-.PARAMETER NoResourceProvidersDetailed
- default is to output all ResourceProvider states for all Subscriptions. In large Tenants this can become time consuming.
-
.PARAMETER AzureDevOpsWikiAsCode
use this parameter when running AzGovViz in Azure DevOps (AzDO) pipeline
default is to Throw at error, whilst in AzDO we will Write-Error "Error"
@@ -86,11 +83,11 @@
.PARAMETER NoCsvExport
Export enriched 'Role assignments' data, enriched 'Policy assignments' data and 'all resources' (subscriptionId, mgPath, resourceType, id, name, location, tags, createdTime, changedTime)
-.PARAMETER PolicyIncludeResourceGroups
- Include Policy assignments on ResourceGroups
+.PARAMETER DoNotIncludeResourceGroupsOnPolicy
+ Do not include Policy assignments on ResourceGroups
-.PARAMETER RBACIncludeResourceGroupsAndResources
- Include Role assignments on ResourceGroups and Resources
+.PARAMETER DoNotIncludeResourceGroupsAndResourcesOnRBAC
+ Do not include Role assignments on ResourceGroups and Resources
.PARAMETER ChangeTrackingDays
Define the period for Change tracking on newly created and updated custom Policy, PolicySet and RBAC Role definitions and Policy/RBAC Role assignments (default is '14')
@@ -104,6 +101,14 @@
.PARAMETER LargeTenant
A large tenant is a tenant with more than ~500 Subscriptions - the HTML output for large tenants simply becomes too big, therefore will not create ScopeInsights and will not show inheritance for Policy and Role assignments in the TenantSummary (html) output
+.PARAMETER NoResourceProvidersDetailed
+ Note if you use parameter -LargeTenant then parameter -NoResourceProvidersDetailed will be set to true
+ default is to output all ResourceProvider states for all Subscriptions in the TenantSummary. In large Tenants this can become time consuming and may blow off the html file.
+
+.PARAMETER NoScopeInsights
+ Note if you use parameter -LargeTenant then parameter -NoScopeInsights will be set to true
+ Q: Why would you want to do this? A: In larger tenants the ScopeInsights section blows up the html file (up to unusable due to html file size)
+
.EXAMPLE
Define the ManagementGroup ID
@@ -124,9 +129,6 @@
Define if ASC SecureScore should be queried for Subscriptions
PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -NoASCSecureScore
- Define if a detailed summary on Resource Provider states per Subscription should be created in the TenantSummary section
- PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -NoResourceProvidersDetailed
-
Define if the script runs in AzureDevOps.
PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -AzureDevOpsWikiAsCode
@@ -175,11 +177,11 @@
Do not Export enriched 'Role assignments' data, enriched 'Policy assignments' data and 'all resources' (subscriptionId, mgPath, resourceType, id, name, location, tags, createdTime, changedTime)
PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -NoCsvExport
- Include Policy assignments on ResourceGroups
- PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -PolicyIncludeResourceGroups
+ Do not include Policy assignments on ResourceGroups
+ PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -DoNotIncludeResourceGroupsOnPolicy
- Include Role assignments on ResourceGroups and Resources
- PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -RBACIncludeResourceGroupsAndResources
+ Do not include Role assignments on ResourceGroups and Resources
+ PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -DoNotIncludeResourceGroupsAndResourcesOnRBAC
Define the period for Change tracking on newly created and updated custom Policy, PolicySet and RBAC Role definitions and Policy/RBAC Role assignments (default is '14')
PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -ChangeTrackingDays 30
@@ -193,18 +195,27 @@
A large tenant is a tenant with more than ~500 Subscriptions - the HTML output for large tenants simply becomes too big, therefore will not create ScopeInsights and will not show inheritance for Policy and Role assignments in the TenantSummary (html) output
PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -LargeTenant
+ Define if a detailed summary on Resource Provider states per Subscription should be created in the TenantSummary section
+ Note if you use parameter -LargeTenant then parameter -NoResourceProvidersDetailed will be set to true
+ PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -NoResourceProvidersDetailed
+
+ Define if ScopeInsights should be created or not. Q: Why would you want to do this? A: In larger tenants the ScopeInsights section blows up the html file (up to unusable due to html file size)
+ Note if you use parameter -LargeTenant then parameter -NoScopeInsights will be set to true
+ PS C:\>.\AzGovVizParallel.ps1 -ManagementGroupId -NoScopeInsights
+
.NOTES
AUTHOR: Julian Hayward - Customer Engineer - Customer Success Unit | Azure Infrastucture/Automation/Devops/Governance | Microsoft
.LINK
https://github.com/JulianHayward/Azure-MG-Sub-Governance-Reporting
+ https://github.com/microsoft/CloudAdoptionFramework/tree/master/govern/AzureGovernanceVisualizer
Please note that while being developed by a Microsoft employee, AzGovViz is not a Microsoft service or product. AzGovViz is a personal/community driven project, there are none implicit or explicit obligations related to this project, it is provided 'as is' with no warranties and confer no rights.
#>
[CmdletBinding()]
Param
(
- [string]$AzGovVizVersion = "v5_major_202107015_2",
+ [string]$AzGovVizVersion = "v5_major_20210722_1",
[string]$ManagementGroupId,
[switch]$AzureDevOpsWikiAsCode,
[switch]$DebugAzAPICall,
@@ -228,17 +239,18 @@ Param
[int]$AzureConsumptionPeriod = 1,
[switch]$NoAzureConsumptionReportExportToCSV,
[switch]$DoTranscript,
- [int]$TFCriticalRowsCount = 40000, #HTML ScopeInsights Role Assignments -> becomes unresponsive depending on client device performance. A recommendation will be shown to download the CSV instead of opening the TF table
+ [int]$HtmlTableRowsLimit = 40000, #HTML ScopeInsights Role assignments -> becomes unresponsive depending on client device performance. A recommendation will be shown to download the CSV instead of opening the TF table
[int]$ThrottleLimit = 5,
[array]$ExludedResourceTypesDiagnosticsCapable = @("microsoft.web/certificates"),
- [switch]$PolicyIncludeResourceGroups,
- [switch]$RBACIncludeResourceGroupsAndResources,
+ [switch]$DoNotIncludeResourceGroupsOnPolicy,
+ [switch]$DoNotIncludeResourceGroupsAndResourcesOnRBAC,
[parameter(ValueFromPipeline)][ValidateSet("TD", "LR")][string]$AzureDevOpsWikiHierarchyDirection = "TD",
[string]$SubscriptionId4AzContext = "undefined",
[int]$ChangeTrackingDays = 14,
[string]$FileTimeStampFormat = "yyyyMMdd_HHmmss",
[switch]$NoJsonExport,
[switch]$LargeTenant,
+ [switch]$NoScopeInsights,
#https://docs.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#role-based-access-control-limits
[int]$LimitRBACCustomRoleDefinitionsTenant = 5000,
@@ -293,7 +305,7 @@ catch {
if ($DoTranscript) {
if ($ManagementGroupId) {
- $fileNameTranscript = "AzGovViz_$($AzGovVizVersion)_$($fileTimestamp)_$($ManagementGroupId)Log.txt"
+ $fileNameTranscript = "AzGovViz_$($AzGovVizVersion)_$($fileTimestamp)_$($ManagementGroupId)_Log.txt"
}
else {
$fileNameTranscript = "AzGovViz_$($AzGovVizVersion)_$($fileTimestamp)_Log.txt"
@@ -358,7 +370,8 @@ else {
$htParameters.NoASCSecureScore = $false
}
-if ($LargeTenant -eq $true){
+if ($LargeTenant -eq $true) {
+ $NoScopeInsights = $true
$NoResourceProvidersDetailed = $true
}
if ($NoResourceProvidersDetailed) {
@@ -382,18 +395,18 @@ else {
$htParameters.NoAzureConsumption = $false
}
-if ($PolicyIncludeResourceGroups) {
- $htParameters.PolicyIncludeResourceGroups = $true
+if ($DoNotIncludeResourceGroupsOnPolicy) {
+ $htParameters.DoNotIncludeResourceGroupsOnPolicy = $true
}
else {
- $htParameters.PolicyIncludeResourceGroups = $false
+ $htParameters.DoNotIncludeResourceGroupsOnPolicy = $false
}
-if ($RBACIncludeResourceGroupsAndResources) {
- $htParameters.RBACIncludeResourceGroupsAndResources = $true
+if ($DoNotIncludeResourceGroupsAndResourcesOnRBAC) {
+ $htParameters.DoNotIncludeResourceGroupsAndResourcesOnRBAC = $true
}
else {
- $htParameters.RBACIncludeResourceGroupsAndResources = $false
+ $htParameters.DoNotIncludeResourceGroupsAndResourcesOnRBAC = $false
}
if ($LargeTenant) {
@@ -842,7 +855,7 @@ function AzAPICall($uri, $method, $currentTask, $body, $listenOn, $getConsumptio
$null = $apiCallResultsCollection.Add([PSCustomObject]@{
"$($azAPIRequestConvertedFromJson.properties.columns.name[0])" = $consumptionline[0]
"$($azAPIRequestConvertedFromJson.properties.columns.name[1])" = $consumptionline[1]
- SubscriptionMgPath = ($htSubscriptionsMgPath.($consumptionline[1]).ParentNameChain).ToString()
+ SubscriptionMgPath = ($htSubscriptionsMgPath.($consumptionline[1]).ParentNameChainDelimited)
"$($azAPIRequestConvertedFromJson.properties.columns.name[2])" = $consumptionline[2]
"$($azAPIRequestConvertedFromJson.properties.columns.name[3])" = $consumptionline[3]
"$($azAPIRequestConvertedFromJson.properties.columns.name[4])" = $consumptionline[4]
@@ -1355,6 +1368,7 @@ function addRowToTable() {
[string]$PolicyAssignmentDisplayName = "",
[string]$PolicyAssignmentDescription = "",
[string]$PolicyAssignmentEnforcementMode = "",
+ $PolicyAssignmentNonComplianceMessages = "",
[string]$PolicyAssignmentIdentity = "",
[int]$PolicyAssigmentLimit = 0,
[int]$PolicyAssigmentCount = 0,
@@ -1439,6 +1453,7 @@ function addRowToTable() {
PolicyAssignmentDisplayName = $PolicyAssignmentDisplayName
PolicyAssignmentDescription = $PolicyAssignmentDescription
PolicyAssignmentEnforcementMode = $PolicyAssignmentEnforcementMode
+ PolicyAssignmentNonComplianceMessages = $PolicyAssignmentNonComplianceMessages
PolicyAssignmentIdentity = $PolicyAssignmentIdentity
PolicyAssigmentLimit = $PolicyAssigmentLimit
PolicyAssigmentCount = $PolicyAssigmentCount
@@ -1495,8 +1510,7 @@ function dataCollection($mgId) {
Write-Host " CustomDataCollection ManagementGroups"
$startMgLoop = get-date
- #$allManagementGroupsFromEntitiesChildOfRequestedMg = $arrayEntitiesFromAPI | Where-Object { $_.type -eq "Microsoft.Management/managementGroups" -and ($_.Name -eq $mgId -or $_.properties.parentNameChain -contains $mgId) } | Sort-Object -Property id -Unique
- $allManagementGroupsFromEntitiesChildOfRequestedMg = $arrayEntitiesFromAPI | Where-Object { $_.type -eq "Microsoft.Management/managementGroups" -and ($_.Name -eq $mgId -or $_.properties.parentNameChain -contains $mgId) }
+ $allManagementGroupsFromEntitiesChildOfRequestedMg = $arrayEntitiesFromAPI.where( { $_.type -eq "Microsoft.Management/managementGroups" -and ($_.Name -eq $mgId -or $_.properties.parentNameChain -contains $mgId) })
$allManagementGroupsFromEntitiesChildOfRequestedMgCount = ($allManagementGroupsFromEntitiesChildOfRequestedMg | Measure-Object).Count
$allManagementGroupsFromEntitiesChildOfRequestedMg | ForEach-Object -Parallel {
@@ -1547,16 +1561,15 @@ function dataCollection($mgId) {
$addRowToTableDone = $false
- $MgParentId = ($allManagementGroupsFromEntitiesChildOfRequestedMg | Where-Object { $_.Name -eq $mgdetail.Name }).properties.parent.Id -replace ".*/"
+ $MgParentId = ($allManagementGroupsFromEntitiesChildOfRequestedMg.where( { $_.Name -eq $mgdetail.Name })).properties.parent.Id -replace ".*/"
if ([string]::IsNullOrEmpty($MgParentId)) {
$MgParentId = "TenantRoot"
$MgParentName = "TenantRoot"
}
else {
- #$MgParentName = ($arrayEntitiesFromAPI | Where-Object { $_.Name -eq $MgParentId } | Sort-Object -Property id -Unique).Name
$MgParentName = $htManagementGroupsMgPath.($MgParentId).DisplayName
}
- $hierarchyLevel = (($allManagementGroupsFromEntitiesChildOfRequestedMg | Where-Object { $_.Name -eq $mgdetail.Name }).properties.parentNameChain | Measure-Object).Count
+ $hierarchyLevel = (($allManagementGroupsFromEntitiesChildOfRequestedMg.where( { $_.Name -eq $mgdetail.Name })).properties.parentNameChain | Measure-Object).Count
$rndom = Get-Random -Minimum 10 -Maximum 750
start-sleep -Millisecond $rndom
@@ -1564,7 +1577,7 @@ function dataCollection($mgId) {
if ($htParameters.HierarchyMapOnly -eq $false) {
- $mgPath = $htManagementGroupsMgPath.($mgdetail.Name).path -join "/"
+ $mgPath = $htManagementGroupsMgPath.($mgdetail.Name).pathDelimited
$currentTask = "getDiagnosticSettingsMg '$($mgdetail.properties.displayName)' ('$($mgdetail.Name)')"
$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementGroups/$($mgdetail.Name)/providers/microsoft.insights/diagnosticSettings?api-version=2020-01-01-preview"
$method = "GET"
@@ -1738,7 +1751,8 @@ function dataCollection($mgId) {
#MGCustomPolicies
$currentTask = "Custom Policy definitions '$($mgdetail.properties.displayName)' ('$($mgdetail.Name)')"
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01"
+ #$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01"
+ $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyDefinitions?api-version=2020-09-01"
#$path = "/providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01"
$method = "GET"
@@ -1838,7 +1852,8 @@ function dataCollection($mgId) {
#MGPolicySets
$currentTask = "Custom PolicySet definitions '$($mgdetail.properties.displayName)' ('$($mgdetail.Name)')"
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01"
+ #$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01"
+ $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policySetDefinitions?api-version=2020-09-01"
#$path = "/providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01"
$method = "GET"
@@ -1881,7 +1896,6 @@ function dataCollection($mgId) {
else {
($script:htCacheDefinitions).policySet.(($mgPolicySetDefinition.Id).ToLower()).Preview = $false
}
-
}
}
@@ -1893,10 +1907,10 @@ function dataCollection($mgId) {
#MgPolicyAssignments
$currentTask = "Policy assignments '$($mgdetail.properties.displayName)' ('$($mgdetail.Name)')"
if ($htParameters.LargeTenant -eq $false) {
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyAssignments?`$filter=atscope()&api-version=2019-09-01"
+ $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyAssignments?`$filter=atscope()&api-version=2020-09-01"
}
else {
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyAssignments?`$filter=atExactScope()&api-version=2019-09-01"
+ $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyAssignments?`$filter=atExactScope()&api-version=2020-09-01"
}
#$path = "/providers/Microsoft.Management/managementgroups/$($mgdetail.Name)/providers/Microsoft.Authorization/policyAssignments?`$filter=atscope()&api-version=2019-09-01"
$method = "GET"
@@ -1983,6 +1997,13 @@ function dataCollection($mgId) {
}
}
+ if ($L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages.Message){
+ $nonComplianceMessage = $L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages.Message
+ }
+ else{
+ $nonComplianceMessage = ""
+ }
+
$addRowToTableDone = $true
addRowToTable `
-level $hierarchyLevel `
@@ -2013,6 +2034,7 @@ function dataCollection($mgId) {
-PolicyAssignmentDisplayName $PolicyAssignmentDisplayName `
-PolicyAssignmentDescription $PolicyAssignmentDescription `
-PolicyAssignmentEnforcementMode $L0mgmtGroupPolicyAssignment.Properties.EnforcementMode `
+ -PolicyAssignmentNonComplianceMessages $nonComplianceMessage `
-PolicyAssignmentIdentity $PolicyAssignmentIdentity `
-PolicyAssigmentLimit $LimitPOLICYPolicyAssignmentsManagementGroup `
-PolicyAssigmentCount $L0mgmtGroupPolicyAssignmentsPolicyCount `
@@ -2035,7 +2057,6 @@ function dataCollection($mgId) {
$Id = ($L0mgmtGroupPolicyAssignment.properties.policydefinitionid).ToLower()
$Def = ($htCacheDefinitions).($definitiontype).($Id)
$PolicyAssignmentScope = $L0mgmtGroupPolicyAssignment.Properties.Scope
- #$PolicyAssignmentNotScopes = $L0mgmtGroupPolicyAssignment.Properties.NotScopes -join "$CsvDelimiterOpposite "
$PolicyAssignmentId = ($L0mgmtGroupPolicyAssignment.Id).ToLower()
$PolicyAssignmentName = $L0mgmtGroupPolicyAssignment.Name
$PolicyAssignmentDisplayName = $L0mgmtGroupPolicyAssignment.Properties.DisplayName
@@ -2086,6 +2107,13 @@ function dataCollection($mgId) {
$updatedOn = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn.ToString("yyyy-MM-dd HH:mm:ss")
}
}
+
+ if (($L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages.where({-not $_.policyDefinitionReferenceId})).Message){
+ $nonComplianceMessage = ($L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages.where({-not $_.policyDefinitionReferenceId})).Message
+ }
+ else{
+ $nonComplianceMessage = ""
+ }
$addRowToTableDone = $true
addRowToTable `
@@ -2117,6 +2145,7 @@ function dataCollection($mgId) {
-PolicyAssignmentDisplayName $PolicyAssignmentDisplayName `
-PolicyAssignmentDescription $PolicyAssignmentDescription `
-PolicyAssignmentEnforcementMode $L0mgmtGroupPolicyAssignment.Properties.EnforcementMode `
+ -PolicyAssignmentNonComplianceMessages $nonComplianceMessage `
-PolicyAssignmentIdentity $PolicyAssignmentIdentity `
-PolicyAssigmentLimit $LimitPOLICYPolicyAssignmentsManagementGroup `
-PolicyAssigmentCount $L0mgmtGroupPolicyAssignmentsPolicyCount `
@@ -2481,7 +2510,7 @@ function dataCollection($mgId) {
$hierarchyLevel = $hierarchyInfo.level
$childMgId = $hierarchyInfo.Parent
$childMgDisplayName = $hierarchyInfo.ParentName
- $childMgMgPath = $hierarchyInfo.path -join "/"
+ $childMgMgPath = $hierarchyInfo.pathDelimited
$childMgParentInfo = $htManagementGroupsMgPath.($childMgId)
$childMgParentId = $childMgParentInfo.Parent
#$childMgParentName = $childMgParentInfo.ParentName
@@ -2507,6 +2536,7 @@ function dataCollection($mgId) {
ScopeName = $childMgSubDisplayName
ScopeId = $childMgSubId
ScopeMgPath = $childMgMgPath
+ SubMgParent = $childMgId
DiagnosticsPresent = "false"
})
}
@@ -2540,6 +2570,7 @@ function dataCollection($mgId) {
ScopeName = $childMgSubDisplayName
ScopeId = $childMgSubId
ScopeMgPath = $childMgMgPath
+ SubMgParent = $childMgId
DiagnosticsPresent = "true"
DiagnosticSettingName = $diagnosticSetting.name
DiagnosticTargetType = "LA"
@@ -2554,6 +2585,7 @@ function dataCollection($mgId) {
ScopeName = $childMgSubDisplayName
ScopeId = $childMgSubId
ScopeMgPath = $childMgMgPath
+ SubMgParent = $childMgId
DiagnosticsPresent = "true"
DiagnosticSettingName = $diagnosticSetting.name
DiagnosticTargetType = "SA"
@@ -2568,6 +2600,7 @@ function dataCollection($mgId) {
ScopeName = $childMgSubDisplayName
ScopeId = $childMgSubId
ScopeMgPath = $childMgMgPath
+ SubMgParent = $childMgId
DiagnosticsPresent = "true"
DiagnosticSettingName = $diagnosticSetting.name
DiagnosticTargetType = "EH"
@@ -3039,7 +3072,8 @@ function dataCollection($mgId) {
#SubscriptionPolicies
$currentTask = "Policy definitions '$($childMgSubDisplayName)' ('$childMgSubId')"
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01"
+ #$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01"
+ $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyDefinitions?api-version=2020-09-01"
#$path = "/subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01"
$method = "GET"
@@ -3140,7 +3174,8 @@ function dataCollection($mgId) {
#SubscriptionPolicySets
$currentTask = "PolicySet definitions '$($childMgSubDisplayName)' ('$childMgSubId')"
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01"
+ #$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01"
+ $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policySetDefinitions?api-version=2020-09-01"
#$path = "/subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01"
$method = "GET"
@@ -3195,24 +3230,12 @@ function dataCollection($mgId) {
#SubscriptionPolicyAssignments
$currentTask = "Policy assignments '$($childMgSubDisplayName)' ('$childMgSubId')"
- if ($htParameters.LargeTenant -eq $false) {
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyAssignments?api-version=2019-09-01"
- }
- else {
- <#if ($htParameters.PolicyIncludeResourceGroups -eq $true) {
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyAssignments?api-version=2019-09-01"
- }
- else{
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyAssignments?`$filter=atExactScope()&api-version=2019-09-01"
- }
- #>
- $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyAssignments?api-version=2019-09-01"
-
- }
+ #$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyAssignments?api-version=2019-09-01"
+ $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyAssignments?api-version=2020-09-01"
#$path = "/subscriptions/$($childMgSubId)/providers/Microsoft.Authorization/policyAssignments?api-version=2019-09-01"
$method = "GET"
- if ($htParameters.PolicyIncludeResourceGroups -eq $true) {
+ if ($htParameters.DoNotIncludeResourceGroupsOnPolicy -eq $false) {
$L1mgmtGroupSubPolicyAssignments = ((AzAPICall -uri $uri -method $method -currentTask $currentTask -caller "CustomDataCollection"))
$L1mgmtGroupSubPolicyAssignmentsPolicyCount = (($L1mgmtGroupSubPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/" }) | measure-object).count
$L1mgmtGroupSubPolicyAssignmentsPolicySetCount = (($L1mgmtGroupSubPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/" }) | measure-object).count
@@ -3317,7 +3340,6 @@ function dataCollection($mgId) {
}
}
- #$PolicyAssignmentNotScopes = $L1mgmtGroupSubPolicyAssignment.Properties.NotScopes -join "$CsvDelimiterOpposite "
$PolicyAssignmentId = ($L1mgmtGroupSubPolicyAssignment.Id).ToLower()
$PolicyAssignmentName = $L1mgmtGroupSubPolicyAssignment.Name
$PolicyAssignmentDisplayName = $L1mgmtGroupSubPolicyAssignment.Properties.DisplayName
@@ -3357,6 +3379,13 @@ function dataCollection($mgId) {
$updatedOn = $L1mgmtGroupSubPolicyAssignment.properties.metadata.updatedOn.ToString("yyyy-MM-dd HH:mm:ss")
}
}
+
+ if ($L1mgmtGroupSubPolicyAssignment.Properties.nonComplianceMessages.Message){
+ $nonComplianceMessage = $L1mgmtGroupSubPolicyAssignment.Properties.nonComplianceMessages.Message
+ }
+ else{
+ $nonComplianceMessage = ""
+ }
$addRowToTableDone = $true
addRowToTable `
@@ -3395,6 +3424,7 @@ function dataCollection($mgId) {
-PolicyAssignmentDisplayName $PolicyAssignmentDisplayName `
-PolicyAssignmentDescription $PolicyAssignmentDescription `
-PolicyAssignmentEnforcementMode $L1mgmtGroupSubPolicyAssignment.Properties.EnforcementMode `
+ -PolicyAssignmentNonComplianceMessages $nonComplianceMessage `
-PolicyAssignmentIdentity $PolicyAssignmentIdentity `
-PolicyAssigmentLimit $LimitPOLICYPolicyAssignmentsSubscription `
-PolicyAssigmentCount $L1mgmtGroupSubPolicyAssignmentsPolicyCount `
@@ -3434,7 +3464,7 @@ function dataCollection($mgId) {
}
}
}
- #$PolicyAssignmentNotScopes = $L1mgmtGroupSubPolicyAssignment.Properties.NotScopes -join "$CsvDelimiterOpposite "
+
$PolicyAssignmentId = ($L1mgmtGroupSubPolicyAssignment.Id).ToLower()
$PolicyAssignmentName = $L1mgmtGroupSubPolicyAssignment.Name
$PolicyAssignmentDisplayName = $L1mgmtGroupSubPolicyAssignment.Properties.DisplayName
@@ -3486,6 +3516,13 @@ function dataCollection($mgId) {
}
}
+ if (($L1mgmtGroupSubPolicyAssignment.Properties.nonComplianceMessages.where({-not $_.policyDefinitionReferenceId})).Message){
+ $nonComplianceMessage = ($L1mgmtGroupSubPolicyAssignment.Properties.nonComplianceMessages.where({-not $_.policyDefinitionReferenceId})).Message
+ }
+ else{
+ $nonComplianceMessage = ""
+ }
+
$addRowToTableDone = $true
addRowToTable `
-level $hierarchyLevel `
@@ -3523,6 +3560,7 @@ function dataCollection($mgId) {
-PolicyAssignmentDisplayName $PolicyAssignmentDisplayName `
-PolicyAssignmentDescription $PolicyAssignmentDescription `
-PolicyAssignmentEnforcementMode $L1mgmtGroupSubPolicyAssignment.Properties.EnforcementMode `
+ -PolicyAssignmentNonComplianceMessages $nonComplianceMessage `
-PolicyAssignmentIdentity $PolicyAssignmentIdentity `
-PolicyAssigmentLimit $LimitPOLICYPolicyAssignmentsSubscription `
-PolicyAssigmentCount $L1mgmtGroupSubPolicyAssignmentsPolicyCount `
@@ -3605,7 +3643,7 @@ function dataCollection($mgId) {
}
until($errorOccurred -eq "no")
- if ($htParameters.RBACIncludeResourceGroupsAndResources -eq $false) {
+ if ($htParameters.DoNotIncludeResourceGroupsAndResourcesOnRBAC -eq $true) {
foreach ($L1mgmtGroupSubRoleAssignmentOnRg in $L1mgmtGroupSubRoleAssignments | Where-Object { $_.RoleAssignmentId -match "/subscriptions/$($childMgSubId)/resourcegroups/" }) {
#$null = $script:arrayCacheRoleAssignmentsResourceGroups.Add($L1mgmtGroupSubRoleAssignmentOnRg)
if (-not ($htCacheAssignments).rbacOnResourceGroupsAndResources.($L1mgmtGroupSubRoleAssignmentOnRg.RoleAssignmentId)) {
@@ -3615,22 +3653,20 @@ function dataCollection($mgId) {
}
if ($htParameters.LargeTenant -eq $false) {
- if ($htParameters.RBACIncludeResourceGroupsAndResources -eq $true) {
+ if ($htParameters.DoNotIncludeResourceGroupsAndResourcesOnRBAC -eq $false) {
$assignmentsScope = $L1mgmtGroupSubRoleAssignments
}
else {
$assignmentsScope = $L1mgmtGroupSubRoleAssignments | Where-Object { $_.RoleAssignmentId -notmatch "/subscriptions/$($childMgSubId)/resourcegroups/" }
}
-
}
else {
- if ($htParameters.RBACIncludeResourceGroupsAndResources -eq $true) {
+ if ($htParameters.DoNotIncludeResourceGroupsAndResourcesOnRBAC -eq $false) {
$assignmentsScope = $L1mgmtGroupSubRoleAssignments
}
else {
$assignmentsScope = $L1mgmtGroupSubRoleAssignments | Where-Object { $_.Scope -eq "/subscriptions/$($childMgSubId)" }
}
-
}
foreach ($L1mgmtGroupSubRoleAssignment in $assignmentsScope) {
@@ -3643,8 +3679,6 @@ function dataCollection($mgId) {
continue
}
-
-
$Id = $L1mgmtGroupSubRoleAssignment.RoleDefinitionId
$definitiontype = "role"
@@ -3719,7 +3753,6 @@ function dataCollection($mgId) {
}
}
-
$RoleSecurityCustomRoleOwner = 0
if (($htCacheDefinitions).$definitiontype.$($Id).Actions -eq '*' -and ((($htCacheDefinitions).$definitiontype.$($Id).NotActions)).length -eq 0 -and ($htCacheDefinitions).$definitiontype.$($Id).IsCustom -eq $True) {
$RoleSecurityCustomRoleOwner = 1
@@ -3833,65 +3866,11 @@ function dataCollection($mgId) {
$endSubLoop = get-date
Write-Host " CustomDataCollection Subscriptions processing duration: $((NEW-TIMESPAN -Start $startSubLoop -End $endSubLoop).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startSubLoop -End $endSubLoop).TotalSeconds) seconds)"
}
-
}
#endregion Function_dataCollection
#HTML
-#
-function createMgPath($mgid) {
- $script:mgPathArray = @()
- $script:mgPathArray += "'$mgid'"
- if ($mgid -ne $mgSubPathTopMg) {
- do {
- $parentId = ($optimizedTableForPathQuery | Where-Object { $_.mgid -eq $mgid } | Sort-Object -Unique).mgParentId
- $mgid = $parentId
- $script:mgPathArray += "'$parentId'"
- }
- until($parentId -eq $mgSubPathTopMg)
- }
-}
-
-function createMgPathSub($subid) {
- $script:submgPathArray = @()
- $script:submgPathArray += "'$subid'"
- #
- Write-Host " function createMgPathSub - TopMGId: $mgSubPathTopMg"
- Write-Host " function createMgPathSub - subId: $subid"
- #
- $mgid = ($optimizedTableForPathQuery | Where-Object { $_.subscriptionId -eq $subid }).mgId
- #
- Write-Host " function createMgPathSub - mgId: $mgid"
- #
- $script:submgPathArray += "'$mgid'"
- #
- Write-Host " function createMgPathSub - subMgPath: $($script:submgPathArray -join ", ")"
- $iteration = 0
- #
- if ($mgid -ne $mgSubPathTopMg) {
- #
- Write-Host " function createMgPathSub - mgId: $mgid notEqual '$mgSubPathTopMg')"
- #
- do {
- $iteration++
- Write-Host " function createMgPathSub - iteration:$iteration"
- $parentId = ($optimizedTableForPathQueryMg | Where-Object { $_.mgid -eq $mgid } | Sort-Object -Unique).mgParentId
- #
- Write-Host " function createMgPathSub - mgId: $mgid - parentId: $parentId"
- #
- $mgid = $parentId
- #
- Write-Host " function createMgPathSub - next mgId: $mgid"
- #
- $script:submgPathArray += "'$parentId'"
- #
- Write-Host " function createMgPathSub - subMgPath: $($script:submgPathArray -join ", ")"
- #
- }
- until($parentId -eq $mgSubPathTopMg)
- }
-}
function hierarchyMgHTML($mgChild) {
$mgDetails = ($optimizedTableForPathQueryMg | Where-Object { $_.MgId -eq "$mgChild" }) | Get-Unique
@@ -3905,10 +3884,6 @@ function hierarchyMgHTML($mgChild) {
else {
$class = "class=`"tenantRootGroup mgnonradius`""
}
-
- #$liclass = "class=`"first`""
- #$liId = "id=`"first`""
- #$tenantDisplayNameAndDefaultDomain = $tenantDetailsDisplay
}
else {
if ($mgId -eq $defaultManagementGroupId) {
@@ -3919,7 +3894,6 @@ function hierarchyMgHTML($mgChild) {
}
$liclass = ""
$liId = ""
- #$tenantDisplayNameAndDefaultDomain = ""
}
if ($mgName -eq $mgId) {
$mgNameAndOrId = $mgName
@@ -4104,7 +4078,7 @@ function tableMgHTML($mgChild, $mgChildOf) {
"6" { $levelSpacing = "|- - - - - - " }
}
- $mgPath = $htManagementGroupsMgPath.($mgChild).path -join "/"
+ $mgPath = $htManagementGroupsMgPath.($mgChild).pathDelimited
$mgLinkedSubsCount = ((($optimizedTableForPathQuery | Where-Object { $_.MgId -eq $mgChild -and -not [String]::IsNullOrEmpty($_.SubscriptionId) }).SubscriptionId | Get-Unique) | measure-object).count
$subscriptionsOutOfScopelinkedCount = ($outOfScopeSubscriptions | Where-Object { $_.ManagementGroupId -eq $mgChild } | Measure-Object).count
@@ -4175,7 +4149,7 @@ function tableSubForMgHTML($mgChild) {
Download CSV semicolon | comma *Depending on the number of rows and your computer´s performance the table may respond with delay, download the csv for better filtering experience
@@ -5880,6 +5854,7 @@ extensions: [{ name: 'sort' }]
Download CSV semicolon | comma *Depending on the number of rows and your computer´s performance the table may respond with delay, download the csv for better filtering experience
@@ -6999,7 +6979,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: {
}
else {
[void]$htmlScopeInsights.AppendLine(@"
-
$(($rbacAll | measure-object).count) Role Assignments
+
$(($rbacAll | measure-object).count) Role assignments