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) {
"@ foreach ($subEntry in $subscriptions | sort-object -Property subscription, subscriptionId) { - $subPath = $htSubscriptionsMgPath.($subEntry.subscriptionId).path -join "/" + $subPath = $htSubscriptionsMgPath.($subEntry.subscriptionId).pathDelimited if ($subscriptionLinkedCount -gt 1) { $script:html += @" @@ -4370,8 +4344,8 @@ function tableMgSubDetailsHTML($mgOrSub, $mgChild, $subscriptionId) { "@) $htmlScopeInsightsDiagnosticsSub = $null - $htmlScopeInsightsDiagnosticsSub = foreach ($entry in ($htDiagnosticSettingsMgSub).sub.($subscriptionId).keys) { - foreach ($diagset in ($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.keys) { + $htmlScopeInsightsDiagnosticsSub = foreach ($entry in ($htDiagnosticSettingsMgSub).sub.($subscriptionId).keys | Sort-Object) { + foreach ($diagset in ($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.keys | Sort-Object) { @" $(($htDiagnosticSettingsMgSub).sub.($subscriptionId).$entry.$diagset.DiagnosticSettingName) @@ -4609,7 +4583,7 @@ extensions: [{ name: 'sort' }] "@) $htmlScopeInsightsTagsUsage = $null - $htmlScopeInsightsTagsUsage = foreach ($tagEntry in $arrayTagListSubscription | Sort-Object Scope, TagName) { + $htmlScopeInsightsTagsUsage = foreach ($tagEntry in $arrayTagListSubscription | Sort-Object Scope, TagName -CaseSensitive) { @" $($tagEntry.Scope) @@ -5076,8 +5050,8 @@ extensions: [{ name: 'sort' }] "@) $htmlScopeInsightsDiagnosticsMg = $null - $htmlScopeInsightsDiagnosticsMg = foreach ($entry in ($htDiagnosticSettingsMgSub).mg.($mgChild).keys) { - foreach ($diagset in ($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.keys) { + $htmlScopeInsightsDiagnosticsMg = foreach ($entry in ($htDiagnosticSettingsMgSub).mg.($mgChild).keys | Sort-Object) { + foreach ($diagset in ($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.keys | Sort-Object) { @" $(($htDiagnosticSettingsMgSub).mg.($mgChild).$entry.$diagset.DiagnosticSettingName) @@ -5864,7 +5838,7 @@ extensions: [{ name: 'sort' }] $noteOrNot = "" } [void]$htmlScopeInsights.AppendLine(@" - +
   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' }] Category Effect Enforcement +NonCompliance Message "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -5919,6 +5894,7 @@ extensions: [{ name: 'sort' }] $($policyAssignment.PolicyCategory) $($policyAssignment.Effect) $($policyAssignment.PolicyAssignmentEnforcementMode) +$($policyAssignment.PolicyAssignmentNonComplianceMessages) "@ if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -5998,6 +5974,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { 'caseinsensitivestring', 'caseinsensitivestring', 'caseinsensitivestring', + 'caseinsensitivestring', "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -6031,7 +6008,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { } else { [void]$htmlScopeInsights.AppendLine(@" -

$(($policiesAssigned | measure-object).count) Policy Assignments

+

$(($policiesAssigned | measure-object).count) Policy assignments

"@) } [void]$htmlScopeInsights.AppendLine(@" @@ -6108,7 +6085,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { $noteOrNot = "" } [void]$htmlScopeInsights.AppendLine(@" - +
   Download CSV semicolon | comma @@ -6121,6 +6098,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { + "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -6148,7 +6126,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { "@) $htmlScopeInsightsPolicySetAssignments = $null - $htmlScopeInsightsPolicySetAssignments = foreach ($policyAssignment in $policySetsAssigned | sort-object -Property Level, MgName, MgId, SubscriptionName, SubscriptionId) { + $htmlScopeInsightsPolicySetAssignments = foreach ($policyAssignment in $policySetsAssigned | sort-object -Property Level, PolicyAssignmentId) { @" @@ -6158,6 +6136,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { + "@ if ($htParameters.NoPolicyComplianceStates -eq $false) { @" @@ -6231,6 +6210,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { 'caseinsensitivestring', 'caseinsensitivestring', 'caseinsensitivestring', + 'caseinsensitivestring', "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -6262,7 +6242,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { } else { [void]$htmlScopeInsights.AppendLine(@" -

$(($policySetsAssigned | measure-object).count) PolicySet Assignments

+

$(($policySetsAssigned | measure-object).count) PolicySet assignments

"@) } [void]$htmlScopeInsights.AppendLine(@" @@ -6358,8 +6338,8 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { - - + + @@ -6488,7 +6468,7 @@ extensions: [{ name: 'sort' }] - + @@ -6881,7 +6861,7 @@ extensions: [{ name: 'sort' }] } [void]$htmlScopeInsights.AppendLine(@" - +
   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

"@) } @@ -7032,7 +7012,7 @@ function summary() { #region tenantSummaryPre $startRoleAssignmentsAllPre = get-date $roleAssignmentsallCount = ($rbacBaseQuery | Measure-Object).count - Write-Host " processing TenantSummary RoleAssignments (all $roleAssignmentsallCount)" + Write-Host " processing (pre) TenantSummary RoleAssignments (all $roleAssignmentsallCount)" #region RelatedPolicyAssignments $startRelatedPolicyAssignmentsAll = get-date @@ -7184,17 +7164,17 @@ function summary() { if ($htAADGroupsDetails.($rbac.RoleAssignmentIdentityObjectId).MembersAllCount -gt 0) { $null = $script:rbacAll.Add([PSCustomObject]@{ - Level = $rbac.Level - RoleAssignmentId = $rbac.RoleAssignmentId - RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName - CreatedBy = $rbac.RoleAssignmentCreatedBy - CreatedOn = $rbac.RoleAssignmentCreatedOn - #UpdatedBy = $rbac.RoleAssignmentUpdatedBy - #UpdatedOn = $rbac.RoleAssignmentUpdatedOn - MgId = $rbac.MgId - MgName = $rbac.MgName - MgParentId = $rbac.MgParentId - MgParentName = $rbac.MgParentName + Level = $rbac.Level + RoleAssignmentId = $rbac.RoleAssignmentId + RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName + CreatedBy = $rbac.RoleAssignmentCreatedBy + CreatedOn = $rbac.RoleAssignmentCreatedOn + #UpdatedBy = $rbac.RoleAssignmentUpdatedBy + #UpdatedOn = $rbac.RoleAssignmentUpdatedOn + MgId = $rbac.MgId + MgName = $rbac.MgName + MgParentId = $rbac.MgParentId + MgParentName = $rbac.MgParentName SubscriptionId = $rbac.SubscriptionId SubscriptionName = $rbac.Subscription Scope = $scope @@ -7284,17 +7264,17 @@ function summary() { } $null = $script:rbacAll.Add([PSCustomObject]@{ - Level = $rbac.Level - RoleAssignmentId = $rbac.RoleAssignmentId - RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName - CreatedBy = $rbac.RoleAssignmentCreatedBy - CreatedOn = $rbac.RoleAssignmentCreatedOn - #UpdatedBy = $rbac.RoleAssignmentUpdatedBy - #UpdatedOn = $rbac.RoleAssignmentUpdatedOn - MgId = $rbac.MgId - MgName = $rbac.MgName - MgParentId = $rbac.MgParentId - MgParentName = $rbac.MgParentName + Level = $rbac.Level + RoleAssignmentId = $rbac.RoleAssignmentId + RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName + CreatedBy = $rbac.RoleAssignmentCreatedBy + CreatedOn = $rbac.RoleAssignmentCreatedOn + #UpdatedBy = $rbac.RoleAssignmentUpdatedBy + #UpdatedOn = $rbac.RoleAssignmentUpdatedOn + MgId = $rbac.MgId + MgName = $rbac.MgName + MgParentId = $rbac.MgParentId + MgParentName = $rbac.MgParentName SubscriptionId = $rbac.SubscriptionId SubscriptionName = $rbac.Subscription Scope = $scope @@ -7350,17 +7330,17 @@ function summary() { } $null = $script:rbacAll.Add([PSCustomObject]@{ - Level = $rbac.Level - RoleAssignmentId = $rbac.RoleAssignmentId - RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName - CreatedBy = $rbac.RoleAssignmentCreatedBy - CreatedOn = $rbac.RoleAssignmentCreatedOn - #UpdatedBy = $rbac.RoleAssignmentUpdatedBy - #UpdatedOn = $rbac.RoleAssignmentUpdatedOn - MgId = $rbac.MgId - MgName = $rbac.MgName - MgParentId = $rbac.MgParentId - MgParentName = $rbac.MgParentName + Level = $rbac.Level + RoleAssignmentId = $rbac.RoleAssignmentId + RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName + CreatedBy = $rbac.RoleAssignmentCreatedBy + CreatedOn = $rbac.RoleAssignmentCreatedOn + #UpdatedBy = $rbac.RoleAssignmentUpdatedBy + #UpdatedOn = $rbac.RoleAssignmentUpdatedOn + MgId = $rbac.MgId + MgName = $rbac.MgName + MgParentId = $rbac.MgParentId + MgParentName = $rbac.MgParentName SubscriptionId = $rbac.SubscriptionId SubscriptionName = $rbac.Subscription Scope = $scope @@ -7416,17 +7396,17 @@ function summary() { } $null = $script:rbacAll.Add([PSCustomObject]@{ - Level = $rbac.Level - RoleAssignmentId = $rbac.RoleAssignmentId - RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName - CreatedBy = $rbac.RoleAssignmentCreatedBy - CreatedOn = $rbac.RoleAssignmentCreatedOn - #UpdatedBy = $rbac.RoleAssignmentUpdatedBy - #UpdatedOn = $rbac.RoleAssignmentUpdatedOn - MgId = $rbac.MgId - MgName = $rbac.MgName - MgParentId = $rbac.MgParentId - MgParentName = $rbac.MgParentName + Level = $rbac.Level + RoleAssignmentId = $rbac.RoleAssignmentId + RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName + CreatedBy = $rbac.RoleAssignmentCreatedBy + CreatedOn = $rbac.RoleAssignmentCreatedOn + #UpdatedBy = $rbac.RoleAssignmentUpdatedBy + #UpdatedOn = $rbac.RoleAssignmentUpdatedOn + MgId = $rbac.MgId + MgName = $rbac.MgName + MgParentId = $rbac.MgParentId + MgParentName = $rbac.MgParentName SubscriptionId = $rbac.SubscriptionId SubscriptionName = $rbac.Subscription Scope = $scope @@ -7482,17 +7462,17 @@ function summary() { #noaadgroupmemberresolve $null = $script:rbacAll.Add([PSCustomObject]@{ - Level = $rbac.Level - RoleAssignmentId = $rbac.RoleAssignmentId - RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName - CreatedBy = $rbac.RoleAssignmentCreatedBy - CreatedOn = $rbac.RoleAssignmentCreatedOn - #UpdatedBy = $rbac.RoleAssignmentUpdatedBy - #UpdatedOn = $rbac.RoleAssignmentUpdatedOn - MgId = $rbac.MgId - MgName = $rbac.MgName - MgParentId = $rbac.MgParentId - MgParentName = $rbac.MgParentName + Level = $rbac.Level + RoleAssignmentId = $rbac.RoleAssignmentId + RoleAssignmentScopeName = $rbac.RoleAssignmentScopeName + CreatedBy = $rbac.RoleAssignmentCreatedBy + CreatedOn = $rbac.RoleAssignmentCreatedOn + #UpdatedBy = $rbac.RoleAssignmentUpdatedBy + #UpdatedOn = $rbac.RoleAssignmentUpdatedOn + MgId = $rbac.MgId + MgName = $rbac.MgName + MgParentId = $rbac.MgParentId + MgParentName = $rbac.MgParentName SubscriptionId = $rbac.SubscriptionId SubscriptionName = $rbac.Subscription Scope = $scope @@ -7694,8 +7674,13 @@ function summary() { foreach ($customPolicy in ($customPoliciesArrayFromHtValues | Sort-Object @{Expression = { $_.DisplayName } }, @{Expression = { $_.PolicyDefinitionId } })) { #uniqueAssignments - $policyUniqueAssignments = ($policyPolicyBaseQueryUniqueAssignmentsArrayList.where( { $_.PolicyDefinitionId -eq $customPolicy.PolicyDefinitionId })).PolicyAssignmentId - $policyUniqueAssignmentsCount = ($policyUniqueAssignments | measure-object).count + if ($htPolicyWithAssignmentsBase.($customPolicy.PolicyDefinitionId)) { + $policyUniqueAssignments = $htPolicyWithAssignmentsBase.($customPolicy.PolicyDefinitionId).Assignments + $policyUniqueAssignmentsCount = ($policyUniqueAssignments).count + } + else { + $policyUniqueAssignmentsCount = 0 + } $uniqueAssignments = $null if ($policyUniqueAssignmentsCount -gt 0) { @@ -7710,7 +7695,7 @@ function summary() { $usedInPolicySet = "0" if (($htPoliciesUsedInPolicySets).($customPolicy.PolicyDefinitionId)) { $hlpPolicySetUsed = ($htPoliciesUsedInPolicySets).($customPolicy.PolicyDefinitionId) - $usedInPolicySet = "$(($hlpPolicySetUsed.PolicySet | Measure-Object).Count) ($($hlpPolicySetUsed.PolicySet -join "$CsvDelimiterOpposite ")" + $usedInPolicySet = "$(($hlpPolicySetUsed.PolicySet | Measure-Object).Count) ($(($hlpPolicySetUsed.PolicySet | Sort-Object) -join "$CsvDelimiterOpposite ")" } #policyEffect @@ -7731,10 +7716,16 @@ function summary() { ($htCacheDefinitions).role.($roleDefinitionId -replace ".*/").Name } } + $policyRoleDefinitionsClearArray = @() + $policyRoleDefinitionsClearArray = foreach ($roleDefinitionId in $customPolicy.RoleDefinitionIds | Sort-Object) { + ($htCacheDefinitions).role.($roleDefinitionId -replace ".*/").Name + } $policyRoleDefinitions = $policyRoleDefinitionsArray -join "$CsvDelimiterOpposite " + $policyRoleDefinitionsClear = $policyRoleDefinitionsClearArray -join "$CsvDelimiterOpposite " } else { $policyRoleDefinitions = "n/a" + $policyRoleDefinitionsClear = "n/a" } $createdOn = "" @@ -7772,6 +7763,7 @@ function summary() { PolicyEffect = $effect PolicyCategory = $customPolicy.Category RoleDefinitions = $policyRoleDefinitions + RoleDefinitionsClear = $policyRoleDefinitionsClear UniqueAssignments = $uniqueAssignments UsedInPolicySets = $usedInPolicySet UsedInPolicySetsClean = $usedInPolicySet -replace "" -replace "" @@ -7790,7 +7782,7 @@ function summary() { else { $csvFilename = "AzGovViz_$($AzGovVizVersion)_$($fileTimestamp)_$($ManagementGroupIdCaseSensitived)_PolicyDefinitions" } - $script:customPoliciesDetailed | Select-Object -ExcludeProperty UsedInPolicySets | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter $csvDelimiter -Encoding utf8 -NoTypeInformation + $customPoliciesDetailed | Sort-Object -Property Scope, PolicyDefinitionId | Select-Object -ExcludeProperty UsedInPolicySets, RoleDefinitions | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter $csvDelimiter -Encoding utf8 -NoTypeInformation } if ($getMgParentName -eq "Tenant Root") { @@ -7811,8 +7803,8 @@ function summary() {
- - + + @@ -7959,8 +7951,8 @@ extensions: [{ name: 'sort' }] - - + + @@ -8094,8 +8086,7 @@ extensions: [{ name: 'sort' }] #rgchange $arrayCustomPoliciesOrphanedFinalIncludingResourceGroups = [System.Collections.ArrayList]@() foreach ($customPolicyOrphanedFinal in $arrayCustomPoliciesOrphanedFinal) { -#if ($arrayCachePolicyAssignmentsResourceGroupsAndResources.properties.PolicyDefinitionId -notcontains $customPolicyOrphanedFinal.PolicyDefinitionId) { - if (($htCacheAssignments).policyOnResourceGroupsAndResources.values.properties.PolicyDefinitionId -notcontains $customPolicyOrphanedFinal.PolicyDefinitionId) { + if (($htCacheAssignments).policyOnResourceGroupsAndResources.values.properties.PolicyDefinitionId -notcontains $customPolicyOrphanedFinal.PolicyDefinitionId) { $null = $arrayCustomPoliciesOrphanedFinalIncludingResourceGroups.Add($customPolicyOrphanedFinal) } } @@ -8104,7 +8095,7 @@ extensions: [{ name: 'sort' }] $tfCount = ($arrayCustomPoliciesOrphanedFinalIncludingResourceGroups | measure-object).count $htmlTableId = "TenantSummary_customPoliciesOrphaned" [void]$htmlTenantSummary.AppendLine(@" - +
Download CSV semicolon | comma
Type Category EnforcementNonCompliance Message
$($policyAssignment.Inheritance)$($policyAssignment.PolicyType) $($policyAssignment.PolicyCategory) $($policyAssignment.PolicyAssignmentEnforcementMode)$($policyAssignment.PolicyAssignmentNonComplianceMessages)PolicyId Category Policy effectRole DefinitionsUnique AssignmentsRole definitionsUnique assignments Used in PolicySets
PolicySet DisplayName PolicySetId CategoryUnique AssignmentsUnique assignments Policies Used
PolicyId Category EffectRole DefinitionsUnique AssignmentsRole definitionsUnique assignments Used in PolicySets CreatedOn CreatedByPolicyId Category Policy EffectRole DefinitionsUnique AssignmentsRole definitionsUnique assignments Used in PolicySets CreatedOn CreatedBy
@@ -8117,7 +8108,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYCustomPoliciesOrphandedTenantRoot = $null - $htmlSUMMARYCustomPoliciesOrphandedTenantRoot = foreach ($customPolicyOrphaned in $arrayCustomPoliciesOrphanedFinalIncludingResourceGroups | sort-object @{Expression = { $_.DisplayName } }, @{Expression = { $_.PolicyDefinitionId } }) { + $htmlSUMMARYCustomPoliciesOrphandedTenantRoot = foreach ($customPolicyOrphaned in $arrayCustomPoliciesOrphanedFinalIncludingResourceGroups | sort-object @{Expression = { $_.PolicyDefinitionId } }, @{Expression = { $_.DisplayName } }) { @" @@ -8218,8 +8209,7 @@ extensions: [{ name: 'sort' }] $arrayCustomPoliciesOrphanedFinalIncludingResourceGroups = [System.Collections.ArrayList]@() foreach ($customPolicyOrphanedFinal in $arrayCustomPoliciesOrphanedFinal) { -#if ($arrayCachePolicyAssignmentsResourceGroupsAndResources.properties.PolicyDefinitionId -notcontains $customPolicyOrphanedFinal.PolicyDefinitionId) { - if (($htCacheAssignments).policyOnResourceGroupsAndResources.values.properties.PolicyDefinitionId -notcontains $customPolicyOrphanedFinal.PolicyDefinitionId) { + if (($htCacheAssignments).policyOnResourceGroupsAndResources.values.properties.PolicyDefinitionId -notcontains $customPolicyOrphanedFinal.PolicyDefinitionId) { $null = $arrayCustomPoliciesOrphanedFinalIncludingResourceGroups.Add($customPolicyOrphanedFinal) } } @@ -8228,7 +8218,7 @@ extensions: [{ name: 'sort' }] $tfCount = ($arrayCustomPoliciesOrphanedFinalIncludingResourceGroups | measure-object).count $htmlTableId = "TenantSummary_customPoliciesOrphaned" [void]$htmlTenantSummary.AppendLine(@" - +
Download CSV semicolon | comma
$($customPolicyOrphaned.DisplayName)
@@ -8241,7 +8231,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYCustomPoliciesOrphandedTenantRoot = $null - $htmlSUMMARYCustomPoliciesOrphandedTenantRoot = foreach ($customPolicyOrphaned in $arrayCustomPoliciesOrphanedFinalIncludingResourceGroups | sort-object @{Expression = { $_.DisplayName } }, @{Expression = { $_.PolicyDefinitionId } }) { + $htmlSUMMARYCustomPoliciesOrphandedTenantRoot = foreach ($customPolicyOrphaned in $arrayCustomPoliciesOrphanedFinalIncludingResourceGroups | sort-object @{Expression = { $_.PolicyDefinitionId } }, @{Expression = { $_.DisplayName } }) { @" @@ -8307,6 +8297,7 @@ extensions: [{ name: 'sort' }] Write-Host " processing TenantSummary Custom Policy definitions orphaned duration: $((NEW-TIMESPAN -Start $startcustpolorph -End $endcustpolorph).TotalSeconds) seconds" #region SUMMARYtenanttotalcustompolicySets + $startCustPolSetLoop = get-date Write-Host " processing TenantSummary Custom PolicySet definitions" $script:customPolicySetsDetailed = [System.Collections.ArrayList]@() $custompolicySetsInScopeArray = [System.Collections.ArrayList]@() @@ -8414,7 +8405,7 @@ extensions: [{ name: 'sort' }] else { $csvFilename = "AzGovViz_$($AzGovVizVersion)_$($fileTimestamp)_$($ManagementGroupIdCaseSensitived)_PolicySetDefinitions" } - $script:customPolicySetsDetailed | Select-Object -ExcludeProperty PoliciesUsed | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter $csvDelimiter -Encoding utf8 -NoTypeInformation + $customPolicySetsDetailed | Sort-Object -Property Scope, PolicySetDefinitionId | Select-Object -ExcludeProperty PoliciesUsed | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter $csvDelimiter -Encoding utf8 -NoTypeInformation } if ($getMgParentName -eq "Tenant Root") { @@ -8440,7 +8431,7 @@ extensions: [{ name: 'sort' }] - + @@ -8563,7 +8554,7 @@ extensions: [{ name: 'sort' }] - + @@ -8654,6 +8645,8 @@ extensions: [{ name: 'sort' }] "@) } } + $endCustPolSetLoop = get-date + Write-Host " Custom PolicySet processing duration: $((NEW-TIMESPAN -Start $startCustPolSetLoop -End $endCustPolSetLoop).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startCustPolSetLoop -End $endCustPolSetLoop).TotalSeconds) seconds)" #endregion SUMMARYtenanttotalcustompolicySets #region SUMMARYCustompolicySetOrphandedTenantRoot @@ -8673,8 +8666,8 @@ extensions: [{ name: 'sort' }] $arraycustompolicySetSetsOrphanedFinalIncludingResourceGroups = [System.Collections.ArrayList]@() foreach ($customPolicySetOrphaned in $custompolicySetSetsOrphaned) { -#if ($arrayCachePolicyAssignmentsResourceGroupsAndResources.properties.PolicyDefinitionId -notcontains $customPolicySetOrphaned.PolicyDefinitionId) { - if (($htCacheAssignments).policyOnResourceGroupsAndResources.values.properties.PolicyDefinitionId -notcontains $customPolicySetOrphaned.PolicyDefinitionId) { + #if ($arrayCachePolicyAssignmentsResourceGroupsAndResources.properties.PolicyDefinitionId -notcontains $customPolicySetOrphaned.PolicyDefinitionId) { + if (($htCacheAssignments).policyOnResourceGroupsAndResources.values.properties.PolicyDefinitionId -notcontains $customPolicySetOrphaned.PolicyDefinitionId) { $null = $arraycustompolicySetSetsOrphanedFinalIncludingResourceGroups.Add($customPolicySetOrphaned) } } @@ -8683,7 +8676,7 @@ extensions: [{ name: 'sort' }] $tfCount = ($arraycustompolicySetSetsOrphanedFinalIncludingResourceGroups | measure-object).count $htmlTableId = "TenantSummary_customPolicySetsOrphaned" [void]$htmlTenantSummary.AppendLine(@" - +
Download CSV semicolon | comma
$($customPolicyOrphaned.DisplayName)PolicySet DisplayName PolicySetId CategoryUnique AssignmentsUnique assignments Policies used in PolicySet CreatedOn CreatedByPolicySet DisplayName PolicySetId CategoryUnique AssignmentsUnique assignments Policies used in PolicySet CreatedOn CreatedBy
@@ -8696,7 +8689,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYCustompolicySetOrphandedTenantRoot = $null - $htmlSUMMARYCustompolicySetOrphandedTenantRoot = foreach ($custompolicySetOrphaned in $arraycustompolicySetSetsOrphanedFinalIncludingResourceGroups | sort-object @{Expression = { $_.DisplayName } }, @{Expression = { $_.policyDefinitionId } }) { + $htmlSUMMARYCustompolicySetOrphandedTenantRoot = foreach ($custompolicySetOrphaned in $arraycustompolicySetSetsOrphanedFinalIncludingResourceGroups | sort-object @{Expression = { $_.PolicyDefinitionId } }, @{Expression = { $_.DisplayName } }) { @" @@ -8789,8 +8782,8 @@ extensions: [{ name: 'sort' }] } if ($isInScope -eq "inScope") { -#if ($arrayCachePolicyAssignmentsResourceGroupsAndResources.properties.PolicyDefinitionId -notcontains $custompolicySetAll.PolicyDefinitionId) { - if (($htCacheAssignments).policyOnResourceGroupsAndResources.values.properties.PolicyDefinitionId -notcontains $custompolicySetAll.PolicyDefinitionId) { + #if ($arrayCachePolicyAssignmentsResourceGroupsAndResources.properties.PolicyDefinitionId -notcontains $custompolicySetAll.PolicyDefinitionId) { + if (($htCacheAssignments).policyOnResourceGroupsAndResources.values.properties.PolicyDefinitionId -notcontains $custompolicySetAll.PolicyDefinitionId) { $null = $arraycustompolicySetsOrphanedFinalIncludingResourceGroups.Add($custompolicySetAll) } } @@ -8801,7 +8794,7 @@ extensions: [{ name: 'sort' }] $tfCount = ($arraycustompolicySetsOrphanedFinalIncludingResourceGroups | measure-object).count $htmlTableId = "TenantSummary_customPolicySetsOrphaned" [void]$htmlTenantSummary.AppendLine(@" - +
Download CSV semicolon | comma
$($custompolicySetOrphaned.DisplayName)
@@ -8814,7 +8807,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYCustompolicySetOrphandedTenantRoot = $null - $htmlSUMMARYCustompolicySetOrphandedTenantRoot = foreach ($custompolicySetOrphaned in $arraycustompolicySetsOrphanedFinalIncludingResourceGroups | sort-object @{Expression = { $_.DisplayName } }, @{Expression = { $_.policyDefinitionId } }) { + $htmlSUMMARYCustompolicySetOrphandedTenantRoot = foreach ($custompolicySetOrphaned in $arraycustompolicySetsOrphanedFinalIncludingResourceGroups | sort-object @{Expression = { $_.PolicyDefinitionId } }, @{Expression = { $_.DisplayName } }) { @" @@ -9009,7 +9002,7 @@ extensions: [{ name: 'sort' }] foreach ($polsetPolDefId in $($htCacheDefinitions).policySet.(($hlpAssignmentDeprecatedPolicy.PolicyDefinitionId)).PolicySetPolicyIds) { $hlpDeprecatedAssignment = (($htCacheDefinitions).policy.(($polsetPolDefId))) if ($hlpDeprecatedAssignment.type -eq "BuiltIn") { - if ($hlpDeprecatedAssignment.Deprecated -eq $true -or ($hlpDeprecatedAssignment.displayname).StartsWith("[Deprecated]", "CurrentCultureIgnoreCase")) { + if ($hlpDeprecatedAssignment.Deprecated -eq $true) { $null = $policyAssignmentsDeprecated.Add([PSCustomObject]@{ PolicyAssignmentDisplayName = $hlpAssignmentDeprecatedPolicy.PolicyAssignmentDisplayName PolicyAssignmentId = $policyAssignmentAll @@ -9029,7 +9022,7 @@ extensions: [{ name: 'sort' }] $hlpDeprecatedAssignmentPol = ($htCacheDefinitions).policy.(($hlpAssignmentDeprecatedPolicy.PolicyDefinitionId)) if ($hlpDeprecatedAssignmentPol) { if ($hlpDeprecatedAssignmentPol.type -eq "BuiltIn") { - if ($hlpDeprecatedAssignmentPol.Deprecated -eq $true -or ($hlpDeprecatedAssignmentPol.DisplayName).StartsWith("[Deprecated]", "CurrentCultureIgnoreCase")) { + if ($hlpDeprecatedAssignmentPol.Deprecated -eq $true) { $null = $policyAssignmentsDeprecated.Add([PSCustomObject]@{ PolicyAssignmentDisplayName = $hlpAssignmentDeprecatedPolicy.PolicyAssignmentDisplayName PolicyAssignmentId = $policyAssignmentAll @@ -9049,7 +9042,7 @@ extensions: [{ name: 'sort' }] $tfCount = ($policyAssignmentsDeprecated | measure-object).count $htmlTableId = "TenantSummary_policyAssignmentsDeprecated" [void]$htmlTenantSummary.AppendLine(@" -
Download CSV semicolon | comma @@ -9070,12 +9063,6 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYPolicyAssignmentsDeprecatedPolicy = $null $htmlSUMMARYPolicyAssignmentsDeprecatedPolicy = foreach ($policyAssignmentDeprecated in $policyAssignmentsDeprecated | sort-object @{Expression = { $_.PolicyAssignmentDisplayName } }, @{Expression = { $_.PolicyAssignmentId } }) { - if ($policyAssignmentDeprecated.DeprecatedProperty -eq $true) { - $deprecatedProperty = "true" - } - else { - $deprecatedProperty = "false" - } @"
@@ -9085,7 +9072,7 @@ extensions: [{ name: 'sort' }] - + "@ } @@ -9144,7 +9131,7 @@ extensions: [{ name: 'sort' }] } else { [void]$htmlTenantSummary.AppendLine(@" -

$(($policyAssignmentsDeprecated | measure-object).count) Policy Assignments / deprecated Built-in Policy

+

$(($policyAssignmentsDeprecated | measure-object).count) Policy assignments / deprecated Built-in Policy

"@) } #endregion SUMMARYPolicyAssignmentsDeprecatedPolicy @@ -9152,7 +9139,7 @@ extensions: [{ name: 'sort' }] Write-Host " processing PolicyAssignmentsDeprecatedPolicy duration: $((NEW-TIMESPAN -Start $startcustpolassdeprpol -End $endcustpolassdeprpol).TotalSeconds) seconds" #region SUMMARYPolicyExemptions - Write-Host " processing TenantSummary Policy Exemptions" + Write-Host " processing TenantSummary Policy exemptions" $policyExemptionsCount = ($htPolicyAssignmentExemptions.Keys | Measure-Object).Count if ($policyExemptionsCount -gt 0) { @@ -9162,7 +9149,7 @@ extensions: [{ name: 'sort' }] $expiredExemptionsCount = ($htPolicyAssignmentExemptions.Keys | where-object { $htPolicyAssignmentExemptions.($_).exemption.properties.expiresOn -and $htPolicyAssignmentExemptions.($_).exemption.properties.expiresOn -lt (Get-Date).ToUniversalTime() } | Measure-Object).count [void]$htmlTenantSummary.AppendLine(@" -
Download CSV semicolon | comma @@ -9330,7 +9317,7 @@ extensions: [{ name: 'sort' }] } else { [void]$htmlTenantSummary.AppendLine(@" -

$($policyExemptionsCount) Policy Exemptions

+

$($policyExemptionsCount) Policy exemptions

"@) } #endregion SUMMARYPolicyExemptions @@ -9393,7 +9380,7 @@ extensions: [{ name: 'sort' }] } } } - if (-not $RBACIncludeResourceGroupsAndResources) { + if ($DoNotIncludeResourceGroupsAndResourcesOnRBAC) { foreach ($roleassignmentId in ($htCacheAssignments).rbacOnResourceGroupsAndResources.keys | Sort-Object) { $roleAssignment = ($htCacheAssignments).rbacOnResourceGroupsAndResources.($roleassignmentId) @@ -9544,6 +9531,7 @@ extensions: [{ name: 'sort' }] $starttest2 = get-date foreach ($policyAssignmentAll in $policyBaseQuery) { + $cnter++ if ($cnter % 1000 -eq 0) { $etappeSummaryPolicyAssignmentsAll = get-date @@ -9724,18 +9712,19 @@ extensions: [{ name: 'sort' }] } $null = $script:arrayPolicyAssignmentsEnriched.Add([PSCustomObject]@{ - Level = $policyAssignmentAll.Level - MgId = $policyAssignmentAll.MgId - MgName = $policyAssignmentAll.MgName - MgParentId = $policyAssignmentAll.MgParentId - MgParentName = $policyAssignmentAll.MgParentName - subscriptionId = $policyAssignmentAll.SubscriptionId - subscriptionName = $policyAssignmentAll.Subscription - PolicyAssignmentId = (($policyAssignmentAll.PolicyAssignmentId).ToLower()) - PolicyAssignmentScopeName = $policyAssignmentAll.PolicyAssignmentScopeName + Level = $policyAssignmentAll.Level + MgId = $policyAssignmentAll.MgId + MgName = $policyAssignmentAll.MgName + MgParentId = $policyAssignmentAll.MgParentId + MgParentName = $policyAssignmentAll.MgParentName + subscriptionId = $policyAssignmentAll.SubscriptionId + subscriptionName = $policyAssignmentAll.Subscription + PolicyAssignmentId = (($policyAssignmentAll.PolicyAssignmentId).ToLower()) + PolicyAssignmentScopeName = $policyAssignmentAll.PolicyAssignmentScopeName PolicyAssignmentDisplayName = $policyAssignmentAll.PolicyAssignmentDisplayName PolicyAssignmentDescription = $policyAssignmentAll.PolicyAssignmentDescription PolicyAssignmentEnforcementMode = $policyAssignmentAll.PolicyAssignmentEnforcementMode + PolicyAssignmentNonComplianceMessages = $policyAssignmentAll.PolicyAssignmentNonComplianceMessages PolicyAssignmentNotScopes = $policyAssignmentNotScopes AssignedBy = $policyAssignmentAll.PolicyAssignmentAssignedBy CreatedOn = $policyAssignmentAll.PolicyAssignmentCreatedOn @@ -9765,18 +9754,19 @@ extensions: [{ name: 'sort' }] } else { $null = $script:arrayPolicyAssignmentsEnriched.Add([PSCustomObject]@{ - Level = $policyAssignmentAll.Level - MgId = $policyAssignmentAll.MgId - MgName = $policyAssignmentAll.MgName - MgParentId = $policyAssignmentAll.MgParentId - MgParentName = $policyAssignmentAll.MgParentName - subscriptionId = $policyAssignmentAll.SubscriptionId - subscriptionName = $policyAssignmentAll.Subscription - PolicyAssignmentId = (($policyAssignmentAll.PolicyAssignmentId).ToLower()) - PolicyAssignmentScopeName = $policyAssignmentAll.PolicyAssignmentScopeName + Level = $policyAssignmentAll.Level + MgId = $policyAssignmentAll.MgId + MgName = $policyAssignmentAll.MgName + MgParentId = $policyAssignmentAll.MgParentId + MgParentName = $policyAssignmentAll.MgParentName + subscriptionId = $policyAssignmentAll.SubscriptionId + subscriptionName = $policyAssignmentAll.Subscription + PolicyAssignmentId = (($policyAssignmentAll.PolicyAssignmentId).ToLower()) + PolicyAssignmentScopeName = $policyAssignmentAll.PolicyAssignmentScopeName PolicyAssignmentDisplayName = $policyAssignmentAll.PolicyAssignmentDisplayName PolicyAssignmentDescription = $policyAssignmentAll.PolicyAssignmentDescription PolicyAssignmentEnforcementMode = $policyAssignmentAll.PolicyAssignmentEnforcementMode + PolicyAssignmentNonComplianceMessages = $policyAssignmentAll.PolicyAssignmentNonComplianceMessages PolicyAssignmentNotScopes = $policyAssignmentNotScopes AssignedBy = $policyAssignmentAll.PolicyAssignmentAssignedBy CreatedOn = $policyAssignmentAll.PolicyAssignmentCreatedOn @@ -9907,8 +9897,6 @@ extensions: [{ name: 'sort' }] } } resolveIdentitiesPolicy -currentTask "resolveObjectbyId PolicyAssignment #1" - #resolveIdentitiesPolicy -currentTask "resolveObjectbyId PolicyAssignment #2" - #resolveIdentitiesPolicy -currentTask "resolveObjectbyId PolicyAssignment #3" foreach ($policyAssignment in $script:arrayPolicyAssignmentsEnriched.where( { -not [string]::IsNullOrEmpty($_.CreatedBy) -and $_.CreatedBy -notlike "ObjectType*" })) { if ($htResolvedIdentitiesPolicy.($policyAssignment.CreatedBy)) { @@ -9937,11 +9925,11 @@ extensions: [{ name: 'sort' }] $policyAssignmentsUniqueCount = ($arrayPolicyAssignmentsEnriched | Sort-Object -Property PolicyAssignmentId -Unique | measure-object).count - if ($LargeTenant){ + if ($LargeTenant) { $policyAssignmentsCount = $policyAssignmentsUniqueCount $tfCount = $policyAssignmentsCount } - else{ + else { $policyAssignmentsCount = ($arrayPolicyAssignmentsEnriched | measure-object).count $tfCount = $policyAssignmentsCount } @@ -9956,7 +9944,7 @@ extensions: [{ name: 'sort' }] } [void]$htmlTenantSummary.AppendLine(@" -
Download CSV semicolon | comma
@@ -9980,6 +9968,7 @@ extensions: [{ name: 'sort' }]
+ "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -10020,10 +10009,10 @@ extensions: [{ name: 'sort' }] $csvFilename = "AzGovViz_$($AzGovVizVersion)_$($fileTimestamp)_$($ManagementGroupIdCaseSensitived)_PolicyAssignments" } if ($CsvExportUseQuotesAsNeeded) { - $arrayPolicyAssignmentsEnriched | Select-Object -ExcludeProperty PolicyName, RelatedRoleAssignments | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded + $arrayPolicyAssignmentsEnriched | Sort-Object -Property Level, MgId, SubscriptionId, PolicyAssignmentId | Select-Object -ExcludeProperty PolicyName, RelatedRoleAssignments | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded } else { - $arrayPolicyAssignmentsEnriched | Select-Object -ExcludeProperty PolicyName, RelatedRoleAssignments | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation + $arrayPolicyAssignmentsEnriched | Sort-Object -Property Level, MgId, SubscriptionId, PolicyAssignmentId | Select-Object -ExcludeProperty PolicyName, RelatedRoleAssignments | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation } } @@ -10051,6 +10040,7 @@ extensions: [{ name: 'sort' }] + "@ if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -10157,6 +10147,7 @@ extensions: [{ name: 'sort' }] 'caseinsensitivestring', 'caseinsensitivestring', 'caseinsensitivestring', + 'caseinsensitivestring', "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -10184,12 +10175,12 @@ extensions: [{ name: 'sort' }] if ($htParameters.NoPolicyComplianceStates -eq $false) { [void]$htmlTenantSummary.AppendLine(@" - watermark: ['', '', '', 'try [nonempty]', '', 'thisScope', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', ''], + watermark: ['', '', '', 'try [nonempty]', '', 'thisScope', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', '', ''], "@) } else { [void]$htmlTenantSummary.AppendLine(@" - watermark: ['', '', '', 'try [nonempty]', '', 'thisScope', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''], + watermark: ['', '', '', 'try [nonempty]', '', 'thisScope', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''], "@) } @@ -10201,12 +10192,12 @@ extensions: [{ name: 'sort' }] if ($htParameters.NoPolicyComplianceStates -eq $false) { [void]$htmlTenantSummary.AppendLine(@" - at_start: [9, 22, 23], + at_start: [9, 23, 24], "@) } else { [void]$htmlTenantSummary.AppendLine(@" - at_start: [9, 17, 18], + at_start: [9, 18, 19], "@) } @@ -10225,7 +10216,7 @@ extensions: [{ name: 'sort' }] } else { [void]$htmlTenantSummary.AppendLine(@" -

$(($arrayPolicyAssignmentsEnriched | measure-object).count) Policy Assignments

+

$(($arrayPolicyAssignmentsEnriched | measure-object).count) Policy assignments

"@) } $endSummaryPolicyAssignmentsAll = get-date @@ -10386,7 +10377,7 @@ extensions: [{ name: 'sort' }] if (($tenantCustomRolesArray | Measure-Object).count -gt 0) { $mgSubRoleAssignmentsArrayRoleDefinitionIdUnique = $mgSubRoleAssignmentsArrayFromHTValues.RoleDefinitionId | sort-object -Unique - if (-not $RBACIncludeResourceGroupsAndResources) { + if ($DoNotIncludeResourceGroupsAndResourcesOnRBAC) { $rgResRoleAssignmentsArrayRoleDefinitionIdUnique = $rgResRoleAssignmentsArrayFromHTValues.RoleDefinitionId | sort-object -Unique } foreach ($customRoleAll in $tenantCustomRolesArray) { @@ -10395,7 +10386,7 @@ extensions: [{ name: 'sort' }] $roleIsUsed = $true } - if (-not $RBACIncludeResourceGroupsAndResources) { + if ($DoNotIncludeResourceGroupsAndResourcesOnRBAC) { if ($roleIsUsed -eq $false) { if (($rgResRoleAssignmentsArrayRoleDefinitionIdUnique) -contains ($customRoleAll.Id)) { $roleIsUsed = $true @@ -10420,7 +10411,7 @@ extensions: [{ name: 'sort' }] $tfCount = ($arrayCustomRolesOrphanedFinalIncludingResourceGroups | measure-object).count $htmlTableId = "TenantSummary_customRolesOrphaned" [void]$htmlTenantSummary.AppendLine(@" -
Download CSV semicolon | comma @@ -10503,7 +10494,7 @@ extensions: [{ name: 'sort' }] $arrayCustomRolesOrphanedFinalIncludingResourceGroups = [System.Collections.ArrayList]@() $mgSubRoleAssignmentsArrayRoleDefinitionIdUnique = $mgSubRoleAssignmentsArrayFromHTValues.RoleDefinitionId | sort-object -Unique - if (-not $RBACIncludeResourceGroupsAndResources) { + if ($DoNotIncludeResourceGroupsAndResourcesOnRBAC) { $rgResRoleAssignmentsArrayRoleDefinitionIdUnique = $rgResRoleAssignmentsArrayFromHTValues.RoleDefinitionId | sort-object -Unique } if (($tenantCustomRolesArray | Measure-Object).count -gt 0) { @@ -10525,7 +10516,7 @@ extensions: [{ name: 'sort' }] $roleIsUsed = $true } } - if (-not $RBACIncludeResourceGroupsAndResources) { + if ($DoNotIncludeResourceGroupsAndResourcesOnRBAC) { if ($roleIsUsed -eq $false) { if (($rgResRoleAssignmentsArrayRoleDefinitionIdUnique) -contains ($customRoleAll.Id)) { $roleIsUsed = $true @@ -10548,7 +10539,7 @@ extensions: [{ name: 'sort' }] $tfCount = ($arrayCustomRolesOrphanedFinalIncludingResourceGroups | measure-object).count $htmlTableId = "TenantSummary_customRolesOrphaned" [void]$htmlTenantSummary.AppendLine(@" -
Download CSV semicolon | comma @@ -10639,7 +10630,7 @@ extensions: [{ name: 'sort' }] $tfCount = ($roleAssignmentsOrphanedUnique | measure-object).count $htmlTableId = "TenantSummary_roleAssignmnetsOrphaned" [void]$htmlTenantSummary.AppendLine(@" -
Download CSV semicolon | comma @@ -10718,13 +10709,14 @@ extensions: [{ name: 'sort' }] } else { [void]$htmlTenantSummary.AppendLine(@" -

$(($roleAssignmentsOrphanedUnique | measure-object).count) Orphaned Role Assignments ($scopeNamingSummary)

+

$(($roleAssignmentsOrphanedUnique | measure-object).count) Orphaned Role assignments ($scopeNamingSummary)

"@) } #endregion SUMMARYOrphanedRoleAssignments #region SUMMARYRoleAssignmentsAll $startRoleAssignmentsAll = get-date + Write-Host " processing TenantSummary RoleAssignments" $startCreateRBACAllHTMLbeforeForeach = get-date @@ -10740,38 +10732,69 @@ extensions: [{ name: 'sort' }] $uniqueRoleAssignmentsCount = ($rbacAll.RoleAssignmentId | sort-object -Unique | Measure-Object).count $tfCount = $rbacAllCount - $htmlTableId = "TenantSummary_roleAssignmentsAll" - if (-not $NoAADServicePrincipalResolve) { - $noteOrNot = "" - } - else { - $noteOrNot = "" + + if (-not $NoCsvExport) { + $startCreateRBACAllCSV = get-date + + if ($htParameters.AzureDevOpsWikiAsCode -eq $true) { + $csvFilename = "AzGovViz_$($ManagementGroupIdCaseSensitived)_RoleAssignments" + } + else { + $csvFilename = "AzGovViz_$($AzGovVizVersion)_$($fileTimestamp)_$($ManagementGroupIdCaseSensitived)_RoleAssignments" + } + if ($CsvExportUseQuotesAsNeeded) { + if ($LargeTenant) { + $rbacAllAtScope | Sort-Object -Property Level, RoleAssignmentId, MgId, SubscriptionId, RoleClear, ObjectId | Select-Object -ExcludeProperty Role, RbacRelatedPolicyAssignment | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded + } + else { + $rbacAll | Sort-Object -Property Level, RoleAssignmentId, MgId, SubscriptionId, RoleClear, ObjectId | Select-Object -ExcludeProperty Role, RbacRelatedPolicyAssignment | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded + } + } + else { + if ($LargeTenant) { + $rbacAllAtScope | Sort-Object -Property Level, RoleAssignmentId, MgId, SubscriptionId, RoleClear, ObjectId | Select-Object -ExcludeProperty Role, RbacRelatedPolicyAssignment | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation + } + else { + $rbacAll | Sort-Object -Property Level, RoleAssignmentId, MgId, SubscriptionId, RoleClear, ObjectId | Select-Object -ExcludeProperty Role, RbacRelatedPolicyAssignment | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation + } + } + + $endCreateRBACAllCSV = get-date + Write-Host " CreateRBACAll CSV duration: $((NEW-TIMESPAN -Start $startCreateRBACAllCSV -End $endCreateRBACAllCSV).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startCreateRBACAllCSV -End $endCreateRBACAllCSV).TotalSeconds) seconds)" } - if ($tfCount -gt $TFCriticalRowsCount) { + if ($tfCount -gt $HtmlTableRowsLimit) { + Write-Host " !Skipping TenantSummary RoleAssignments HTML processing as $tfCount lines is exceeding the critical rows limit of $HtmlTableRowsLimit" -ForegroundColor Yellow [void]$htmlTenantSummary.AppendLine(@" - -
- Lots of data here! You might be better off downloading the CSV..
- Download CSV semicolon | comma
- -
+
+ Output of $tfCount lines would exceed the html rows limit of $HtmlTableRowsLimit (html file would become unresponsive). Work with the CSV file $($csvFilename) | Note: the CSV file will only exist if you did NOT use parameter -NoCsvExport
+ You can adjust the html row limit by using parameter -HtmlTableRowsLimit
+ You can reduce the number of lines by using parameter -LargeTenant and/or -DoNotIncludeResourceGroupsAnsResourcesOnRBAC
+ Check the parameters documentation AzGovViz docs +
"@) } - - if ($tfCount -le $TFCriticalRowsCount) { + else { + $htmlTableId = "TenantSummary_roleAssignmentsAll" + if (-not $NoAADServicePrincipalResolve) { + $noteOrNot = "" + } + else { + $noteOrNot = "" + } [void]$htmlTenantSummary.AppendLine(@" -
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 "@) - } + - [void]$htmlTenantSummary.AppendLine(@" + [void]$htmlTenantSummary.AppendLine(@"
$($custompolicySetOrphaned.DisplayName)
$($policyAssignmentDeprecated.PolicyAssignmentDisplayName)$($policyAssignmentDeprecated.PolicySetId) $($policyAssignmentDeprecated.PolicyDisplayName) $($policyAssignmentDeprecated.PolicyId)$deprecatedProperty$($policyAssignmentDeprecated.DeprecatedProperty)
Category Effect EnforcementNonCompliance Message$($policyAssignment.PolicyCategory) $($policyAssignment.Effect) $($policyAssignment.PolicyAssignmentEnforcementMode)$($policyAssignment.PolicyAssignmentNonComplianceMessages)
@@ -10799,73 +10822,43 @@ extensions: [{ name: 'sort' }] "@) - $cnter = 0 - $roleAssignmentsAllCount = $rbacAllCount - $htmlSummaryRoleAssignmentsAll = $null - $htmlTenantSummary | Add-Content -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).html" -Encoding utf8 -Force - $htmlTenantSummary = [System.Text.StringBuilder]::new() - - if (-not $NoCsvExport) { - $startCreateRBACAllCSV = get-date + $cnter = 0 + $roleAssignmentsAllCount = $rbacAllCount + $htmlSummaryRoleAssignmentsAll = $null + $htmlTenantSummary | Add-Content -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).html" -Encoding utf8 -Force + $htmlTenantSummary = [System.Text.StringBuilder]::new() - if ($htParameters.AzureDevOpsWikiAsCode -eq $true) { - $csvFilename = "AzGovViz_$($ManagementGroupIdCaseSensitived)_RoleAssignments" - } - else { - $csvFilename = "AzGovViz_$($AzGovVizVersion)_$($fileTimestamp)_$($ManagementGroupIdCaseSensitived)_RoleAssignments" - } - if ($CsvExportUseQuotesAsNeeded) { - if ($LargeTenant) { - $rbacAllAtScope | Select-Object -ExcludeProperty Role, RbacRelatedPolicyAssignment | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded - } - else { - $rbacAll | Select-Object -ExcludeProperty Role, RbacRelatedPolicyAssignment | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded - } + $endCreateRBACAllHTMLbeforeForeach = get-date + Write-Host " CreateRBACAll HTML before Foreach duration: $((NEW-TIMESPAN -Start $startCreateRBACAllHTMLbeforeForeach -End $endCreateRBACAllHTMLbeforeForeach).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startCreateRBACAllHTMLbeforeForeach -End $endCreateRBACAllHTMLbeforeForeach).TotalSeconds) seconds)" + + $startSortRBACAll = get-date + if ($LargeTenant) { + $rbacAllSorted = $rbacAllAtScope | sort-object -Property Level, MgName, MgId, SubscriptionName, SubscriptionId, Scope, Role, ObjectDisplayName, RoleAssignmentId } else { - if ($LargeTenant) { - $rbacAllAtScope | Select-Object -ExcludeProperty Role, RbacRelatedPolicyAssignment | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation - } - else { - $rbacAll | Select-Object -ExcludeProperty Role, RbacRelatedPolicyAssignment | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($csvFilename).csv" -Delimiter "$csvDelimiter" -NoTypeInformation - } + $rbacAllSorted = $rbacAll | sort-object -Property Level, MgName, MgId, SubscriptionName, SubscriptionId, Scope, Role, ObjectDisplayName, RoleAssignmentId } - - $endCreateRBACAllCSV = get-date - Write-Host " CreateRBACAll CSV duration: $((NEW-TIMESPAN -Start $startCreateRBACAllCSV -End $endCreateRBACAllCSV).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startCreateRBACAllCSV -End $endCreateRBACAllCSV).TotalSeconds) seconds)" - } - - $endCreateRBACAllHTMLbeforeForeach = get-date - Write-Host " CreateRBACAll HTML before Foreach duration: $((NEW-TIMESPAN -Start $startCreateRBACAllHTMLbeforeForeach -End $endCreateRBACAllHTMLbeforeForeach).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startCreateRBACAllHTMLbeforeForeach -End $endCreateRBACAllHTMLbeforeForeach).TotalSeconds) seconds)" - - $startSortRBACAll = get-date - if ($LargeTenant) { - $rbacAllSorted = $rbacAllAtScope | sort-object -Property Level, MgName, MgId, SubscriptionName, SubscriptionId, Scope, Role, ObjectDisplayName, RoleAssignmentId - } - else { - $rbacAllSorted = $rbacAll | sort-object -Property Level, MgName, MgId, SubscriptionName, SubscriptionId, Scope, Role, ObjectDisplayName, RoleAssignmentId - } - $endSortRBACAll = get-date - Write-Host " Sort RBACAll duration: $((NEW-TIMESPAN -Start $startSortRBACAll -End $endSortRBACAll).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startSortRBACAll -End $endSortRBACAll).TotalSeconds) seconds)" + $endSortRBACAll = get-date + Write-Host " Sort RBACAll duration: $((NEW-TIMESPAN -Start $startSortRBACAll -End $endSortRBACAll).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startSortRBACAll -End $endSortRBACAll).TotalSeconds) seconds)" - $startCreateRBACAllHTMLForeach = get-date - $htmlSummaryRoleAssignmentsAll = [System.Text.StringBuilder]::new() - foreach ($roleAssignment in $rbacAllSorted) { - - $cnter++ - if ($cnter % 1000 -eq 0) { - Write-Host " create HTML $cnter of $rbacAllCount RoleAssignments processed" - if ($cnter % 5000 -eq 0) { - Write-Host " appending.." - #[void]$htmlTenantSummary.AppendLine($htmlSummaryRoleAssignmentsAll) - $htmlSummaryRoleAssignmentsAll | Add-Content -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).html" -Encoding utf8 -Force - $htmlSummaryRoleAssignmentsAll = [System.Text.StringBuilder]::new() - [System.GC]::Collect() - } - } - [void]$htmlSummaryRoleAssignmentsAll.AppendFormat( - @' + $startCreateRBACAllHTMLForeach = get-date + $htmlSummaryRoleAssignmentsAll = [System.Text.StringBuilder]::new() + foreach ($roleAssignment in $rbacAllSorted) { + + $cnter++ + if ($cnter % 1000 -eq 0) { + Write-Host " create HTML $cnter of $rbacAllCount RoleAssignments processed" + if ($cnter % 5000 -eq 0) { + Write-Host " appending.." + #[void]$htmlTenantSummary.AppendLine($htmlSummaryRoleAssignmentsAll) + $htmlSummaryRoleAssignmentsAll | Add-Content -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).html" -Encoding utf8 -Force + $htmlSummaryRoleAssignmentsAll = [System.Text.StringBuilder]::new() + [System.GC]::Collect() + } + } + [void]$htmlSummaryRoleAssignmentsAll.AppendFormat( + @' @@ -10889,81 +10882,74 @@ extensions: [{ name: 'sort' }] '@, $roleAssignment.TenOrMgOrSubOrRGOrRes, - $roleAssignment.MgId, - $roleAssignment.MgName, - $roleAssignment.SubscriptionId, - $roleAssignment.SubscriptionName, - $roleAssignment.Scope, - $roleAssignment.Role, - $roleAssignment.RoleId, - $roleAssignment.RoleType, - $roleAssignment.RoleDataRelated, - $roleAssignment.ObjectDisplayName, - $roleAssignment.ObjectSignInName, - $roleAssignment.ObjectId, - $roleAssignment.ObjectType, - $roleAssignment.AssignmentType, - $roleAssignment.AssignmentInheritFrom, - $roleAssignment.RoleAssignmentId, - $roleAssignment.RbacRelatedPolicyAssignment, - $roleAssignment.CreatedOn, - $roleAssignment.CreatedBy - ) - - } - $start = get-date - [void]$htmlTenantSummary.AppendLine($htmlSummaryRoleAssignmentsAll) + $roleAssignment.MgId, + $roleAssignment.MgName, + $roleAssignment.SubscriptionId, + $roleAssignment.SubscriptionName, + $roleAssignment.Scope, + $roleAssignment.Role, + $roleAssignment.RoleId, + $roleAssignment.RoleType, + $roleAssignment.RoleDataRelated, + $roleAssignment.ObjectDisplayName, + $roleAssignment.ObjectSignInName, + $roleAssignment.ObjectId, + $roleAssignment.ObjectType, + $roleAssignment.AssignmentType, + $roleAssignment.AssignmentInheritFrom, + $roleAssignment.RoleAssignmentId, + $roleAssignment.RbacRelatedPolicyAssignment, + $roleAssignment.CreatedOn, + $roleAssignment.CreatedBy + ) + + } + $start = get-date + [void]$htmlTenantSummary.AppendLine($htmlSummaryRoleAssignmentsAll) - $htmlTenantSummary | Add-Content -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).html" -Encoding utf8 -Force - $htmlSummaryRoleAssignmentsAll = $null #cleanup - $htmlTenantSummary = [System.Text.StringBuilder]::new() - $end = get-date + $htmlTenantSummary | Add-Content -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).html" -Encoding utf8 -Force + $htmlSummaryRoleAssignmentsAll = $null #cleanup + $htmlTenantSummary = [System.Text.StringBuilder]::new() + $end = get-date - $endCreateRBACAllHTMLForeach = get-date - Write-Host " CreateRBACAll HTML Foreach duration: $((NEW-TIMESPAN -Start $startCreateRBACAllHTMLForeach -End $endCreateRBACAllHTMLForeach).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startCreateRBACAllHTMLForeach -End $endCreateRBACAllHTMLForeach).TotalSeconds) seconds)" + $endCreateRBACAllHTMLForeach = get-date + Write-Host " CreateRBACAll HTML Foreach duration: $((NEW-TIMESPAN -Start $startCreateRBACAllHTMLForeach -End $endCreateRBACAllHTMLForeach).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startCreateRBACAllHTMLForeach -End $endCreateRBACAllHTMLForeach).TotalSeconds) seconds)" - [void]$htmlTenantSummary.AppendLine(@" + [void]$htmlTenantSummary.AppendLine(@"
{0} {1}{19}
-"@) - if ($tfCount -gt $TFCriticalRowsCount) { - [void]$htmlTenantSummary.AppendLine(@" -
-"@) - } - [void]$htmlTenantSummary.AppendLine(@" "@) + } } else { [void]$htmlTenantSummary.AppendLine(@" -

$($rbacAllCount) Role Assignments

+

$($rbacAllCount) Role assignments

"@) } + $endRoleAssignmentsAll = get-date Write-Host " SummaryRoleAssignmentsAll duration: $((NEW-TIMESPAN -Start $startRoleAssignmentsAll -End $endRoleAssignmentsAll).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startRoleAssignmentsAll -End $endRoleAssignmentsAll).TotalSeconds) seconds)" #endregion SUMMARYRoleAssignmentsAll @@ -11027,7 +11015,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { $tfCount = ($roleAssignmentsClassicGrouped | Measure-Object).Count $htmlTableId = "TenantSummary_roleAssignmnetsClassic" [void]$htmlTenantSummary.AppendLine(@" -
Download CSV semicolon | comma @@ -11106,13 +11094,13 @@ extensions: [{ name: 'sort' }] } else { [void]$htmlTenantSummary.AppendLine(@" -

No Classic Role Assignments ($scopeNamingSummary)

+

No Classic Role assignments ($scopeNamingSummary)

"@) } } else { [void]$htmlTenantSummary.AppendLine(@" -

No Classic Role Assignments ($scopeNamingSummary)

+

No Classic Role assignments ($scopeNamingSummary)

"@) } @@ -11135,14 +11123,14 @@ extensions: [{ name: 'sort' }] Role Name RoleId -Role Assignments +Role assignments Assignable Scopes "@) $htmlSUMMARYSecurityCustomRoles = $null - foreach ($customRole in ($customRolesOwnerHtAll | sort-object)) { + foreach ($customRole in ($customRolesOwnerHtAll | sort-object -Property Name, Id)) { $customRoleOwnersAllAssignmentsCount = ((($customRolesOwnerAll.where( { $_.RoleDefinitionId -eq $customRole.Id })).RoleAssignmentId | Sort-Object -Unique) | measure-object).count if ($customRoleOwnersAllAssignmentsCount -gt 0) { $customRoleRoleAssignmentsArray = [System.Collections.ArrayList]@() @@ -11540,8 +11528,8 @@ extensions: [{ name: 'sort' }] if (-not $NoAADGuestUsers) { $startSUMMARYSecurityGuestUserHighPriviledgesAssignments = get-date - Write-Host " processing TenantSummary RoleAssignments security (userAccessAdministrator notGroup)" - $highPriviledgedGuestUserRoleAssignments = $rbacAll.where( { $_.RoleId -eq "8e3af657-a8ff-443c-a75c-2fe8c4bcb635" -or $_.RoleId -eq "18d7d88d-d35e-4fb5-a5c3-7773c20a72d9" -and $_.ObjectType -eq "User (Guest)" }) | sort-object -property RoleAssignmentId, ObjectId -Unique + Write-Host " processing TenantSummary RoleAssignments security (high priviledged Guest User)" + $highPriviledgedGuestUserRoleAssignments = $rbacAll.where( { ($_.RoleId -eq "8e3af657-a8ff-443c-a75c-2fe8c4bcb635" -or $_.RoleId -eq "18d7d88d-d35e-4fb5-a5c3-7773c20a72d9") -and $_.ObjectType -eq "User Guest" }) | sort-object -property RoleAssignmentId, ObjectId -Unique $highPriviledgedGuestUserRoleAssignmentsCount = ($highPriviledgedGuestUserRoleAssignments | Measure-Object).Count if ($highPriviledgedGuestUserRoleAssignmentsCount -gt 0) { $tfCount = $highPriviledgedGuestUserRoleAssignmentsCount @@ -11689,7 +11677,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYBlueprintDefinitions = $null - $htmlSUMMARYBlueprintDefinitions = foreach ($blueprintDefinition in $blueprintDefinitions) { + $htmlSUMMARYBlueprintDefinitions = foreach ($blueprintDefinition in $blueprintDefinitions | Sort-Object -Property BlueprintName, BlueprintDisplayName) { @" $($blueprintDefinition.BlueprintName) @@ -11762,7 +11750,7 @@ extensions: [{ name: 'sort' }] if ($blueprintAssignmentsCount -gt 0) { $htmlTableId = "TenantSummary_BlueprintAssignments" [void]$htmlTenantSummary.AppendLine(@" - +
Download CSV semicolon | comma @@ -11779,7 +11767,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYBlueprintAssignments = $null - $htmlSUMMARYBlueprintAssignments = foreach ($blueprintAssignment in $blueprintAssignments) { + $htmlSUMMARYBlueprintAssignments = foreach ($blueprintAssignment in $blueprintAssignments | Sort-Object -Property level, BlueprintAssignmentId) { @" @@ -11843,7 +11831,7 @@ extensions: [{ name: 'sort' }] } else { [void]$htmlTenantSummary.AppendLine(@" -

$blueprintAssignmentsCount Blueprint Assignments

+

$blueprintAssignmentsCount Blueprint assignments

"@) } #endregion SUMMARYBlueprintAssignments @@ -12001,7 +11989,7 @@ extensions: [{ name: 'sort' }] $cnter = 0 $htmlSUMMARYManagementGroups = foreach ($summaryManagementGroup in $summaryManagementGroups) { - $mgPath = $htManagementGroupsMgPath.($summaryManagementGroup.mgId).path -join "/" + $mgPath = $htManagementGroupsMgPath.($summaryManagementGroup.mgId).pathDelimited if ($summaryManagementGroup.mgid -eq $mgSubPathTopMg -and ($checkContext).Tenant.Id -ne $ManagementGroupId) { $pathhlper = "$($mgPath)" @@ -12218,7 +12206,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYSubs = $null $htmlSUMMARYSubs = foreach ($summarySubscription in $summarySubscriptions) { - $subPath = $htSubscriptionsMgPath.($summarySubscription.subscriptionId).path -join "/" + $subPath = $htSubscriptionsMgPath.($summarySubscription.subscriptionId).pathDelimited $subscriptionTagsArray = [System.Collections.ArrayList]@() foreach ($tag in ($htSubscriptionTags).($summarySubscription.subscriptionId).keys) { $null = $subscriptionTagsArray.Add("'$($tag)':'$(($htSubscriptionTags).$($summarySubscription.subscriptionId).$tag)'") @@ -13122,7 +13110,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYDiagnosticsManagementGroups = $null - $htmlSUMMARYDiagnosticsManagementGroups = foreach ($entry in $diagnosticSettingsMg) { + $htmlSUMMARYDiagnosticsManagementGroups = foreach ($entry in $diagnosticSettingsMg | Sort-Object -Property ScopeMgPath) { @" @@ -13236,7 +13224,7 @@ extensions: [{ name: 'sort' }] $tfCount = $diagnosticSettingsMgNoDiagCount $htmlTableId = "TenantSummary_NoDiagnosticsManagementGroups" [void]$htmlTenantSummary.AppendLine(@" - +
Management Group Diagnostic Settings - Create Or Update - REST API docs
Download CSV semicolon | comma @@ -13251,7 +13239,7 @@ extensions: [{ name: 'sort' }]
"@) $htmlSUMMARYNoDiagnosticsManagementGroups = $null - $htmlSUMMARYNoDiagnosticsManagementGroups = foreach ($entry in $diagnosticSettingsMgNoDiag) { + $htmlSUMMARYNoDiagnosticsManagementGroups = foreach ($entry in $diagnosticSettingsMgNoDiag | Sort-Object -Property ScopeMgPath) { @" @@ -13338,6 +13326,7 @@ extensions: [{ name: 'sort' }] + @@ -13355,12 +13344,13 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYDiagnosticsSubscriptions = $null - $htmlSUMMARYDiagnosticsSubscriptions = foreach ($entry in $diagnosticSettingsSub) { + $htmlSUMMARYDiagnosticsSubscriptions = foreach ($entry in $diagnosticSettingsSub | Sort-Object -Property ScopeName, DiagnosticTargetType, DiagnosticSettingName) { @" + @@ -13417,9 +13407,9 @@ paging: {results_per_page: ['Records: ', [$spectrum]]},state: {types: ['local_st [void]$htmlTenantSummary.AppendLine(@" btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { delay: 1100 }, no_results_message: true, linked_filters: true, - col_3: 'select', + col_4: 'select', "@) - $cnt = 4 + $cnt = 5 foreach ($logCategory in $diagnosticSettingsSubCategories) { $cnt++ [void]$htmlTenantSummary.AppendLine(@" @@ -13433,6 +13423,7 @@ btn_reset: true, highlight_keywords: true, alternate_rows: true, auto_filter: { 'caseinsensitivestring', 'caseinsensitivestring', 'caseinsensitivestring', + 'caseinsensitivestring', "@) $cnt = 0 foreach ($logCategory in $diagnosticSettingsSubCategories) { @@ -13485,7 +13476,7 @@ extensions: [{ name: 'sort' }] "@) $htmlSUMMARYNoDiagnosticsSubscriptions = $null - $htmlSUMMARYNoDiagnosticsSubscriptions = foreach ($entry in $diagnosticSettingsSubNoDiag) { + $htmlSUMMARYNoDiagnosticsSubscriptions = foreach ($entry in $diagnosticSettingsSubNoDiag | Sort-Object -Property ScopeMgPath) { @" @@ -13940,12 +13931,12 @@ extensions: [{ name: 'sort' }] - + - + - + @@ -14162,7 +14153,7 @@ extensions: [{ name: 'sort' }] - + "@ } @@ -14681,7 +14672,7 @@ extensions: [{ name: 'sort' }] - + "@ } @@ -15193,7 +15184,7 @@ tf.init(); - + @@ -15205,7 +15196,7 @@ tf.init(); $spAlternativeNames = $htServicePrincipalsDetails.($serviceprincipalApp).spGraphDetails.alternativeNames if ($spAlternativeNames -like "*/providers/Microsoft.Authorization/policyAssignments/*") { - $usage = "Policy Assignments" + $usage = "Policy assignments" $policyAssignmentId = ($spAlternativeNames | Where-Object { $_ -like "*/providers/Microsoft.Authorization/policyAssignments/*" }).ToLower() if ($policyAssignmentId -like "/providers/Microsoft.Management/managementGroups/*") { @@ -15228,7 +15219,7 @@ tf.init(); } else { #rg - if (-not $PolicyIncludeResourceGroups) { + if ($DoNotIncludeResourceGroupsOnPolicy) { if (-not ($htCacheAssignments).policyOnResourceGroupsAndResources.($policyAssignmentId)) { $assignmentInfo = "n/a" } @@ -15260,7 +15251,7 @@ tf.init(); $policyAssignmentsPolicyVariant4ht = "policySet" } - if (-not $PolicyIncludeResourceGroups) { + if ($DoNotIncludeResourceGroupsOnPolicy) { $policyAssignmentsPolicyDefinitionId = ($assignmentInfo.properties.PolicyDefinitionId).tolower() $policyAssignmentspolicyDefinitionIdGuid = $policyAssignmentsPolicyDefinitionId -replace ".*/" @@ -15630,7 +15621,7 @@ tf.init(); $tfCount = $appsWithOtherOrgIdCount $htmlTableId = "TenantSummary_AADSPExternal" - if (-not $RBACIncludeResourceGroupsAndResources) { + if ($DoNotIncludeResourceGroupsAndResourcesOnRBAC) { $abbr = " " } else { @@ -15647,7 +15638,7 @@ tf.init(); - + @@ -15879,7 +15870,7 @@ tf.init(); $startChangeTracking = get-date $xdaysAgo = (get-date).AddDays(-$ChangeTrackingDays) - #policy + #region ctpolicydata write-host " processing Policy" $customPolicyCreatedOrUpdated = ($customPoliciesDetailed.where( { (-not [string]::IsNullOrEmpty($_.CreatedOn) -and [datetime]$_.CreatedOn -gt $xdaysAgo) -or (-not [string]::IsNullOrEmpty($_.UpdatedOn) -and [datetime]$_.UpdatedOn -gt $xdaysAgo) })) $customPolicyCreatedOrUpdatedCount = $customPolicyCreatedOrUpdated.Count @@ -15894,8 +15885,9 @@ tf.init(); $customPolicyUpdatedMgCount = ($customPolicyUpdatedMg).count $customPolicyUpdatedSub = ($customPolicyUpdatedMgSub.where( { $_.Scope -eq "Sub" })) $customPolicyUpdatedSubCount = ($customPolicyUpdatedSub).count + #endregion ctpolicydata - #policySet + #region ctpolicySetdata write-host " processing PolicySet" $customPolicySetCreatedOrUpdated = ($customPolicySetsDetailed.where( { (-not [string]::IsNullOrEmpty($_.CreatedOn) -and [datetime]$_.CreatedOn -gt $xdaysAgo) -or (-not [string]::IsNullOrEmpty($_.UpdatedOn) -and [datetime]$_.UpdatedOn -gt $xdaysAgo) })) $customPolicySetCreatedOrUpdatedCount = $customPolicySetCreatedOrUpdated.Count @@ -15911,8 +15903,9 @@ tf.init(); $customPolicySetUpdatedMgCount = ($customPolicySetUpdatedMg).count $customPolicySetUpdatedSub = ($customPolicySetUpdatedMgSub.where( { $_.Scope -eq "Sub" })) $customPolicySetUpdatedSubCount = ($customPolicySetUpdatedSub).count + #endregion ctpolicySetdata - #policyAssignments + #region ctpolicyAssignmentsData write-host " processing Policy assignment" $policyAssignmentsCreatedOrUpdated = (($arrayPolicyAssignmentsEnriched.where( { $_.Inheritance -notlike "inherited*" } )).where( { (-not [string]::IsNullOrEmpty($_.CreatedOn) -and [datetime]$_.CreatedOn -gt $xdaysAgo) -or (-not [string]::IsNullOrEmpty($_.UpdatedOn) -and [datetime]$_.UpdatedOn -gt $xdaysAgo) })) $policyAssignmentsCreatedOrUpdatedCount = $policyAssignmentsCreatedOrUpdated.Count @@ -15922,7 +15915,7 @@ tf.init(); $policyAssignmentsCreatedMgCount = ($policyAssignmentsCreatedMg).count $policyAssignmentsCreatedSub = ($policyAssignmentsCreatedMgSub.where( { $_.mgOrSubOrRG -eq "Sub" })) $policyAssignmentsCreatedSubCount = ($policyAssignmentsCreatedSub).count - if ($PolicyIncludeResourceGroups) { + if (-not $DoNotIncludeResourceGroupsOnPolicy) { $policyAssignmentsCreatedRg = ($policyAssignmentsUpdatedMgSub.where( { $_.mgOrSubOrRG -eq "RG" })) $policyAssignmentsCreatedRgCount = ($policyAssignmentsCreatedRg).count } @@ -15932,7 +15925,7 @@ tf.init(); $policyAssignmentsUpdatedMgCount = ($policyAssignmentsUpdatedMg).count $policyAssignmentsUpdatedSub = ($policyAssignmentsUpdatedMgSub.where( { $_.mgOrSubOrRG -eq "Sub" })) $policyAssignmentsUpdatedSubCount = ($policyAssignmentsUpdatedSub).count - if ($PolicyIncludeResourceGroups) { + if (-not $DoNotIncludeResourceGroupsOnPolicy) { $policyAssignmentsUpdatedRg = ($policyAssignmentsUpdatedMgSub.where( { $_.mgOrSubOrRG -eq "RG" })) $policyAssignmentsUpdatedRgCount = ($policyAssignmentsUpdatedRg).count } @@ -15940,7 +15933,7 @@ tf.init(); if ($customPolicyCreatedOrUpdatedCount -gt 0 -or $customPolicySetCreatedOrUpdatedCount -gt 0 -or $policyAssignmentsCreatedOrUpdatedCount -gt 0) { $ctContenIndicatorPolicy = "ctContenPolicyTrue" - if ($PolicyIncludeResourceGroups) { + if (-not $DoNotIncludeResourceGroupsOnPolicy) { $policyAssignmentSummaryCt = "(Mg: C:$($policyAssignmentsCreatedMgCount), U:$($policyAssignmentsUpdatedMgCount); Sub: C:$($policyAssignmentsCreatedSubCount), U:$($policyAssignmentsUpdatedSubCount)); RG: C:$($policyAssignmentsCreatedRgCount), U:$($policyAssignmentsUpdatedRgCount)" } else { @@ -15952,8 +15945,10 @@ tf.init(); $ctContenIndicatorPolicy = "ctContenPolicyFalse" $policyAssignmentSummaryCt = "" } + #endregion ctpolicyAssignmentsData ##RBAC + #region ctRbacData #rbac defs write-host " processing RBAC" $customRoleDefinitionsCreatedOrUpdated = $tenantCustomRolesArray.where( { $_.IsCustom -eq $true -and $_.Json.properties.createdOn -gt $xdaysAgo -or $_.Json.properties.updatedOn -gt $xdaysAgo }) @@ -15968,40 +15963,32 @@ tf.init(); write-host " processing RBAC Role definition updated" $customRoleDefinitionsUpdated = $customRoleDefinitionsCreatedOrUpdated.where( { $_.Json.properties.updatedOn -ne $_.Json.properties.createdOn -and $_.Json.properties.updatedOn -gt $xdaysAgo }) $customRoleDefinitionsUpdatedCount = $customRoleDefinitionsUpdated.Count + #endregion ctRbacData #region ctrbacassignments - #$roleAssignmentsCreated = $roleAssignmentsUniqueById.where({ $_.RoleAssignmentCreatedOnUnformatted -gt $xdaysAgo }) - #$roleAssignmentsCreatedCount = $roleAssignmentsCreated.Count - #$roleAssignmentsCreatedCount - #rbac roleassignments write-host " processing RBAC Role assignments" $roleAssignmentsCreated = ($rbacAll | Sort-Object -Property RoleAssignmentId, ObjectId -Unique).where( { -not [string]::IsNullOrEmpty($_.CreatedOn) -and [datetime]$_.CreatedOn -gt $xdaysAgo }) $roleAssignmentsCreatedUnique = ($roleAssignmentsCreated | sort-object -Property RoleAssignmentId -Unique) $roleAssignmentsCreatedCount = ($roleAssignmentsCreated | sort-object -Property RoleAssignmentId -Unique).Count $roleAssignmentsCreatedImpactedIdentitiesCount = $roleAssignmentsCreated.Count - #$roleAssignmentsCreatedCount #rbac assignments createdMg $roleAssignmentsCreatedMg = $roleAssignmentsCreatedUnique.where( { $_.TenOrMgOrSubOrRGOrRes -eq "MG" -or $_.TenOrMgOrSubOrRGOrRes -eq "Ten" }) $roleAssignmentsCreatedMgCount = $roleAssignmentsCreatedMg.Count - #write-host "mg $roleAssignmentsCreatedMgCount" #rbac assignments createdSub $roleAssignmentsCreatedSub = $roleAssignmentsCreatedUnique.where( { $_.TenOrMgOrSubOrRGOrRes -eq "Sub" }) $roleAssignmentsCreatedSubCount = $roleAssignmentsCreatedSub.Count - #write-host "sub $roleAssignmentsCreatedSubCount" - if ($RBACIncludeResourceGroupsAndResources) { + if (-not $DoNotIncludeResourceGroupsAndResourcesOnRBAC) { $roleAssignmentsCreatedSubRg = $roleAssignmentsCreatedUnique.where( { $_.TenOrMgOrSubOrRGOrRes -eq "RG" }) $roleAssignmentsCreatedSubRgCount = $roleAssignmentsCreatedSubRg.Count - #write-host "rg $roleAssignmentsCreatedSubRgCount" $roleAssignmentsCreatedSubRgRes = $roleAssignmentsCreatedUnique.where( { $_.TenOrMgOrSubOrRGOrRes -eq "Res" }) $roleAssignmentsCreatedSubRgResCount = $roleAssignmentsCreatedSubRgRes.Count - #write-host "res $roleAssignmentsCreatedSubRgResCount" } if ($customRoleDefinitionsCreatedOrUpdatedCount -gt 0 -or $roleAssignmentsCreatedCount -gt 0) { $ctContenIndicatorRBAC = "ctContenRBACTrue" - if ($RBACIncludeResourceGroupsAndResources) { + if (-not $DoNotIncludeResourceGroupsAndResourcesOnRBAC) { $rbacAssignmentSummaryCt = "(Mg: $roleAssignmentsCreatedMgCount; Sub: $roleAssignmentsCreatedSubCount; RG: $roleAssignmentsCreatedSubRgCount; Res: $roleAssignmentsCreatedSubRgResCount)" } else { @@ -16026,8 +16013,6 @@ tf.init(); $resourcesCreated = $resourcesCreatedOrChanged.where( { $_.createdTime -gt $xdaysAgo }) $resourcesCreatedCount = $resourcesCreated.Count $resourcesChanged = $resourcesCreatedOrChanged.where( { $_.changedTime -gt $xdaysAgo }) - #$resourcesChangedByType = $resourcesChanged | group-object -property type - #($resourcesChangedByType | sort-object -property Count -descending)[0..4] $resourcesChangedCount = $resourcesChanged.Count if ($resourcesCreatedOrChangedCount -gt 0) { @@ -16070,8 +16055,8 @@ tf.init(); - - + + @@ -16222,7 +16207,7 @@ tf.init(); - + @@ -16380,6 +16365,7 @@ tf.init(); + "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -16461,6 +16447,7 @@ tf.init(); + "@ if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -16534,12 +16521,12 @@ col_0: 'select', "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { [void]$htmlTenantSummary.AppendLine(@" - col_25: 'multiple', + col_26: 'multiple', "@) } else { [void]$htmlTenantSummary.AppendLine(@" - col_20: 'multiple', + col_21: 'multiple', "@) } [void]$htmlTenantSummary.AppendLine(@" @@ -16561,6 +16548,7 @@ col_0: 'select', 'caseinsensitivestring', 'caseinsensitivestring', 'caseinsensitivestring', + 'caseinsensitivestring', "@) if ($htParameters.NoPolicyComplianceStates -eq $false) { @@ -16589,12 +16577,12 @@ col_0: 'select', if ($htParameters.NoPolicyComplianceStates -eq $false) { [void]$htmlTenantSummary.AppendLine(@" - watermark: ['', '', '', 'try [nonempty]', '', 'thisScope', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', '', ''], + watermark: ['', '', '', 'try [nonempty]', '', 'thisScope', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', '', '', ''], "@) } else { [void]$htmlTenantSummary.AppendLine(@" - watermark: ['', '', '', 'try [nonempty]', '', 'thisScope', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''], + watermark: ['', '', '', 'try [nonempty]', '', 'thisScope', '', '', '', '', '', '','', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', ''], "@) } @@ -16688,7 +16676,12 @@ tf.init(); $updatedByRemoveNoiseOrNot = "" } else { - $createdOnUpdatedOn = "Created&Updated" + if ($createdOn -gt $xdaysAgo) { + $createdOnUpdatedOn = "Created&Updated" + } + else { + $createdOnUpdatedOn = "Updated" + } $updatedOnFormated = $updatedOn.ToString("yyyy-MM-dd HH:mm:ss") $updatedByRemoveNoiseOrNot = $entry.Json.properties.updatedBy if ($htIdentitiesWithRoleAssignmentsUnique.($updatedByRemoveNoiseOrNot)) { @@ -17314,7 +17307,7 @@ function definitionInsights() { if ($htPoliciesUsedInPolicySets.($policy.PolicyDefinitionId)) { $usedInPolicySet = "true" $usedInPolicySetCount = ($htPoliciesUsedInPolicySets.($policy.PolicyDefinitionId).policySet).Count - $usedInPolicySets = ($htPoliciesUsedInPolicySets.($policy.PolicyDefinitionId).policySet) -join "$CsvDelimiterOpposite " + $usedInPolicySets = ($htPoliciesUsedInPolicySets.($policy.PolicyDefinitionId).policySet | Sort-Object) -join "$CsvDelimiterOpposite " } @" @@ -18134,12 +18127,14 @@ foreach ($entity in $arrayEntitiesFromAPI) { if ($entity.Type -eq "/subscriptions") { $htSubscriptionsMgPath.($entity.name) = @{ } $htSubscriptionsMgPath.($entity.name).ParentNameChain = $entity.properties.parentNameChain + $htSubscriptionsMgPath.($entity.name).ParentNameChainDelimited = $entity.properties.parentNameChain -join "/" $htSubscriptionsMgPath.($entity.name).Parent = $entity.properties.parent.Id -replace ".*/" $htSubscriptionsMgPath.($entity.name).ParentName = $htEntitiesPlain.($entity.properties.parent.Id -replace ".*/").properties.displayName $htSubscriptionsMgPath.($entity.name).DisplayName = $entity.properties.displayName $array = $entity.properties.parentNameChain $array += $entity.name $htSubscriptionsMgPath.($entity.name).path = $array + $htSubscriptionsMgPath.($entity.name).pathDelimited = $array -join "/" $htSubscriptionsMgPath.($entity.name).level = (($entity.properties.parentNameChain).Count - 1) } if ($entity.Type -eq "Microsoft.Management/managementGroups") { @@ -18151,6 +18146,7 @@ foreach ($entity in $arrayEntitiesFromAPI) { } $htManagementGroupsMgPath.($entity.name) = @{ } $htManagementGroupsMgPath.($entity.name).ParentNameChain = $entity.properties.parentNameChain + $htManagementGroupsMgPath.($entity.name).ParentNameChainDelimited = $entity.properties.parentNameChain -join "/" $htManagementGroupsMgPath.($entity.name).ParentNameChainCount = ($entity.properties.parentNameChain | Measure-Object).Count $htManagementGroupsMgPath.($entity.name).Parent = $parent $htManagementGroupsMgPath.($entity.name).ChildMgsAll = ($arrayEntitiesFromAPI.where( { $_.Type -eq "Microsoft.Management/managementGroups" -and $_.properties.ParentNameChain -contains $entity.name } )).Name @@ -18159,6 +18155,7 @@ foreach ($entity in $arrayEntitiesFromAPI) { $array = $entity.properties.parentNameChain $array += $entity.name $htManagementGroupsMgPath.($entity.name).path = $array + $htManagementGroupsMgPath.($entity.name).pathDelimited = $array -join "/" } $htEntities.($entity.name) = @{ } @@ -18406,32 +18403,40 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $paramsUsed += "NoAzureConsumption: true " } - #new if ($LargeTenant) { Write-Host " TenantSummary Policy assignments and Role assignments will not include assignment information on scopes where assignment is inherited, ScopeInsights will not be created (-LargeTenant = $($LargeTenant))" -ForegroundColor Green $paramsUsed += "LargeTenant: true " } else { - Write-Host " TenantSummary Policy assignments and Role assignments will include assignment information on scopes where assignment is inherited, ScopeInsights will be created (-LargeTenant = $($LargeTenant)) Q: Why would you not want to show this information? A: In larger tenants the TenantSummary Policy assignments section may blow up the html file (up to unusable due to html file size)" -ForegroundColor Yellow + Write-Host " TenantSummary Policy assignments and Role assignments will include assignment information on scopes where assignment is inherited (-LargeTenant = $($LargeTenant)) Q: Why would you not want to show this information? A: In larger tenants showing the inheritance on each scope may blow up the html file (up to unusable due to html file size)" -ForegroundColor Yellow $paramsUsed += "LargeTenant: false " + + if ($NoScopeInsights){ + Write-Host " ScopeInsights will not be created (-NoScopeInsights = $($NoScopeInsights))" -ForegroundColor Green + $paramsUsed += "NoScopeInsights: true " + } + else{ + Write-Host " ScopeInsights will be created (-NoScopeInsights = $($NoScopeInsights)) Q: Why would you not want to show ScopeInsights? A: In larger tenants ScopeInsights may blow up the html file (up to unusable due to html file size)" -ForegroundColor Yellow + $paramsUsed += "NoScopeInsights: false " + } } - if ($PolicyIncludeResourceGroups) { - Write-Host " TenantSummary Policy assignments will also include assignments on ResourceGroups and Resources (-PolicyIncludeResourceGroups = $($PolicyIncludeResourceGroups))" -ForegroundColor Green - $paramsUsed += "PolicyIncludeResourceGroups: true " + if (-not $DoNotIncludeResourceGroupsOnPolicy) { + Write-Host " TenantSummary Policy assignments will also include assignments on ResourceGroups (DoNotIncludeResourceGroupsOnPolicy = $($DoNotIncludeResourceGroupsOnPolicy))" -ForegroundColor Yellow + $paramsUsed += "DoNotIncludeResourceGroupsOnPolicy: false " } else { - Write-Host " TenantSummary Policy assignments will not include assignments on ResourceGroups and Resources (-PolicyIncludeResourceGroups = $($PolicyIncludeResourceGroups))" -ForegroundColor Yellow - $paramsUsed += "PolicyIncludeResourceGroups: false " + Write-Host " TenantSummary Policy assignments will not include assignments on ResourceGroups (DoNotIncludeResourceGroupsOnPolicy = $($DoNotIncludeResourceGroupsOnPolicy))" -ForegroundColor Green + $paramsUsed += "DoNotIncludeResourceGroupsOnPolicy: true " } - if ($RBACIncludeResourceGroupsAndResources) { - Write-Host " TenantSummary RBAC Role assignments will also include assignments on ResourceGroups and Resources (-RBACIncludeResourceGroupsAndResources = $($RBACIncludeResourceGroupsAndResources))" -ForegroundColor Green - $paramsUsed += "RBACIncludeResourceGroupsAndResources: true " + if (-not $DoNotIncludeResourceGroupsAndResourcesOnRBAC) { + Write-Host " TenantSummary RBAC Role assignments will also include assignments on ResourceGroups and Resources (DoNotIncludeResourceGroupsAndResourcesOnRBAC = $($DoNotIncludeResourceGroupsAndResourcesOnRBAC))" -ForegroundColor Yellow + $paramsUsed += "DoNotIncludeResourceGroupsAndResourcesOnRBAC: false " } else { - Write-Host " TenantSummary RBAC Role assignments will not include assignments on ResourceGroups and Resources (-RBACIncludeResourceGroupsAndResources = $($RBACIncludeResourceGroupsAndResources))" -ForegroundColor Yellow - $paramsUsed += "RBACIncludeResourceGroupsAndResources: false " + Write-Host " TenantSummary RBAC Role assignments will not include assignments on ResourceGroups and Resources (DoNotIncludeResourceGroupsAndResourcesOnRBAC = $($DoNotIncludeResourceGroupsAndResourcesOnRBAC))" -ForegroundColor Green + $paramsUsed += "DoNotIncludeResourceGroupsAndResourcesOnRBAC: true " } if (-not $NoCsvExport) { @@ -18906,7 +18911,8 @@ if ($htParameters.HierarchyMapOnly -eq $false) { Write-Host "Caching built-in Policy and RBAC Role definitions" $currentTask = "Caching built-in Policy definitions" Write-Host " $currentTask" - $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01" + #$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01" + $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Authorization/policyDefinitions?api-version=2020-09-01" #$path = "/providers/Microsoft.Authorization/policyDefinitions?api-version=2019-09-01" $method = "GET" @@ -18987,7 +18993,8 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $currentTask = "Caching built-in PolicySet definitions" Write-Host " $currentTask" - $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01" + #$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01" + $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Authorization/policySetDefinitions?api-version=2020-09-01" #$path = "/providers/Microsoft.Authorization/policySetDefinitions?api-version=2019-09-01" $method = "GET" @@ -19076,206 +19083,209 @@ if ($htParameters.HierarchyMapOnly -eq $false) { } } - if ($htParameters.LargeTenant -eq $true) { - if (($checkContext).Tenant.Id -ne $ManagementGroupId) { - $currentTask = "Policy assignments ('$($ManagementGroupId)')" - $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($ManagementGroupId)/providers/Microsoft.Authorization/policyAssignments?`$filter=atScope()&api-version=2019-09-01" - $method = "GET" - $upperScopesPolicyAssignments = ((AzAPICall -uri $uri -method $method -currentTask $currentTask -caller "CustomDataCollection")) - $upperScopesPolicyAssignments = $upperScopesPolicyAssignments | where-object { $_.properties.scope -ne "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" } - $upperScopesPolicyAssignmentsPolicyCount = (($upperScopesPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/" }) | measure-object).count - $upperScopesPolicyAssignmentsPolicySetCount = (($upperScopesPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/" }) | measure-object).count - $upperScopesPolicyAssignmentsPolicyAtScopeCount = (($upperScopesPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/" -and $_.Id -match "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" }) | measure-object).count - $upperScopesPolicyAssignmentsPolicySetAtScopeCount = (($upperScopesPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/" -and $_.Id -match "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" }) | measure-object).count - $upperScopesPolicyAssignmentsPolicyAndPolicySetAtScopeCount = ($upperScopesPolicyAssignmentsPolicyAtScopeCount + $upperScopesPolicyAssignmentsPolicySetAtScopeCount) - foreach ($L0mgmtGroupPolicyAssignment in $upperScopesPolicyAssignments) { + if ($htParameters.LargeTenant -eq $true) { + if (($checkContext).Tenant.Id -ne $ManagementGroupId) { + $currentTask = "Policy assignments ('$($ManagementGroupId)')" + #$uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($ManagementGroupId)/providers/Microsoft.Authorization/policyAssignments?`$filter=atScope()&api-version=2019-09-01" + $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementgroups/$($ManagementGroupId)/providers/Microsoft.Authorization/policyAssignments?`$filter=atScope()&api-version=2020-09-01" + $method = "GET" + $upperScopesPolicyAssignments = ((AzAPICall -uri $uri -method $method -currentTask $currentTask -caller "CustomDataCollection")) + $upperScopesPolicyAssignments = $upperScopesPolicyAssignments | where-object { $_.properties.scope -ne "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" } + $upperScopesPolicyAssignmentsPolicyCount = (($upperScopesPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/" }) | measure-object).count + $upperScopesPolicyAssignmentsPolicySetCount = (($upperScopesPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/" }) | measure-object).count + $upperScopesPolicyAssignmentsPolicyAtScopeCount = (($upperScopesPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/" -and $_.Id -match "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" }) | measure-object).count + $upperScopesPolicyAssignmentsPolicySetAtScopeCount = (($upperScopesPolicyAssignments | Where-Object { $_.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/" -and $_.Id -match "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" }) | measure-object).count + $upperScopesPolicyAssignmentsPolicyAndPolicySetAtScopeCount = ($upperScopesPolicyAssignmentsPolicyAtScopeCount + $upperScopesPolicyAssignmentsPolicySetAtScopeCount) + foreach ($L0mgmtGroupPolicyAssignment in $upperScopesPolicyAssignments) { - if ($L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/" -OR $L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/") { - if ($L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/") { - $PolicyVariant = "Policy" - $definitiontype = "policy" - $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 - if (($L0mgmtGroupPolicyAssignment.Properties.Description).length -eq 0) { - $PolicyAssignmentDescription = "no description given" - } - else { - $PolicyAssignmentDescription = $L0mgmtGroupPolicyAssignment.Properties.Description - } + if ($L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/" -OR $L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/") { + if ($L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policyDefinitions/") { + $PolicyVariant = "Policy" + $definitiontype = "policy" + $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 + if (($L0mgmtGroupPolicyAssignment.Properties.Description).length -eq 0) { + $PolicyAssignmentDescription = "no description given" + } + else { + $PolicyAssignmentDescription = $L0mgmtGroupPolicyAssignment.Properties.Description + } + + if ($L0mgmtGroupPolicyAssignment.identity) { + $PolicyAssignmentIdentity = $L0mgmtGroupPolicyAssignment.identity.principalId + } + else { + $PolicyAssignmentIdentity = "n/a" + } + + if ($Def.Type -eq "Custom") { + $policyDefintionScope = $Def.Scope + $policyDefintionScopeMgSub = $Def.ScopeMgSub + $policyDefintionScopeId = $Def.ScopeId + } + else { + $policyDefintionScope = "n/a" + $policyDefintionScopeMgSub = "n/a" + $policyDefintionScopeId = "n/a" + } - if ($L0mgmtGroupPolicyAssignment.identity) { - $PolicyAssignmentIdentity = $L0mgmtGroupPolicyAssignment.identity.principalId + $assignedBy = "n/a" + $createdBy = "" + $createdOn = "" + $updatedBy = "" + $updatedOn = "" + if ($L0mgmtGroupPolicyAssignment.properties.metadata) { + if ($L0mgmtGroupPolicyAssignment.properties.metadata.assignedBy) { + $assignedBy = $L0mgmtGroupPolicyAssignment.properties.metadata.assignedBy } - else { - $PolicyAssignmentIdentity = "n/a" + if ($L0mgmtGroupPolicyAssignment.properties.metadata.createdBy) { + $createdBy = $L0mgmtGroupPolicyAssignment.properties.metadata.createdBy } - - if ($Def.Type -eq "Custom") { - $policyDefintionScope = $Def.Scope - $policyDefintionScopeMgSub = $Def.ScopeMgSub - $policyDefintionScopeId = $Def.ScopeId + if ($L0mgmtGroupPolicyAssignment.properties.metadata.createdOn) { + $createdOn = $L0mgmtGroupPolicyAssignment.properties.metadata.createdOn.ToString("yyyy-MM-dd HH:mm:ss") } - else { - $policyDefintionScope = "n/a" - $policyDefintionScopeMgSub = "n/a" - $policyDefintionScopeId = "n/a" + if ($L0mgmtGroupPolicyAssignment.properties.metadata.updatedBy) { + $updatedBy = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedBy } - - $assignedBy = "n/a" - $createdBy = "" - $createdOn = "" - $updatedBy = "" - $updatedOn = "" - if ($L0mgmtGroupPolicyAssignment.properties.metadata) { - if ($L0mgmtGroupPolicyAssignment.properties.metadata.assignedBy) { - $assignedBy = $L0mgmtGroupPolicyAssignment.properties.metadata.assignedBy - } - if ($L0mgmtGroupPolicyAssignment.properties.metadata.createdBy) { - $createdBy = $L0mgmtGroupPolicyAssignment.properties.metadata.createdBy - } - if ($L0mgmtGroupPolicyAssignment.properties.metadata.createdOn) { - $createdOn = $L0mgmtGroupPolicyAssignment.properties.metadata.createdOn.ToString("yyyy-MM-dd HH:mm:ss") - } - if ($L0mgmtGroupPolicyAssignment.properties.metadata.updatedBy) { - $updatedBy = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedBy - } - if ($L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn) { - $updatedOn = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn.ToString("yyyy-MM-dd HH:mm:ss") - } + if ($L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn) { + $updatedOn = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn.ToString("yyyy-MM-dd HH:mm:ss") } - - addRowToTable ` - -level (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count - 1) ` - -mgName $getMgParentName ` - -mgId $getMgParentId ` - -mgParentId "'upperScopes'" ` - -mgParentName "upperScopes" ` - -Policy $Def.DisplayName ` - -PolicyDescription $Def.Description ` - -PolicyVariant $PolicyVariant ` - -PolicyType $Def.Type ` - -PolicyCategory $Def.Category ` - -PolicyDefinitionIdGuid (($Def.Id) -replace ".*/") ` - -PolicyDefinitionId $Def.PolicyDefinitionId ` - -PolicyDefintionScope $policyDefintionScope ` - -PolicyDefintionScopeMgSub $policyDefintionScopeMgSub ` - -PolicyDefintionScopeId $policyDefintionScopeId ` - -PolicyDefinitionsScopedLimit $LimitPOLICYPolicyDefinitionsScopedManagementGroup ` - -PolicyDefinitionsScopedCount $PolicyDefinitionsScopedCount ` - -PolicySetDefinitionsScopedLimit $LimitPOLICYPolicySetDefinitionsScopedManagementGroup ` - -PolicySetDefinitionsScopedCount $PolicySetDefinitionsScopedCount ` - -PolicyAssignmentScope $PolicyAssignmentScope ` - -PolicyAssignmentScopeMgSubRg "Mg" ` - -PolicyAssignmentScopeName ($PolicyAssignmentScope -replace ".*/", "") ` - -PolicyAssignmentNotScopes $L0mgmtGroupPolicyAssignment.Properties.NotScopes ` - -PolicyAssignmentId $PolicyAssignmentId ` - -PolicyAssignmentName $PolicyAssignmentName ` - -PolicyAssignmentDisplayName $PolicyAssignmentDisplayName ` - -PolicyAssignmentDescription $PolicyAssignmentDescription ` - -PolicyAssignmentEnforcementMode $L0mgmtGroupPolicyAssignment.Properties.EnforcementMode ` - -PolicyAssignmentIdentity $PolicyAssignmentIdentity ` - -PolicyAssigmentLimit $LimitPOLICYPolicyAssignmentsManagementGroup ` - -PolicyAssigmentCount $upperScopesPolicyAssignmentsPolicyCount ` - -PolicyAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAtScopeCount ` - -PolicyAssigmentParameters $L0mgmtGroupPolicyAssignment.Properties.Parameters ` - -PolicyAssignmentAssignedBy $assignedBy ` - -PolicyAssignmentCreatedBy $createdBy ` - -PolicyAssignmentCreatedOn $createdOn ` - -PolicyAssignmentUpdatedBy $updatedBy ` - -PolicyAssignmentUpdatedOn $updatedOn ` - -PolicySetAssigmentLimit $LimitPOLICYPolicySetAssignmentsManagementGroup ` - -PolicySetAssigmentCount $upperScopesPolicyAssignmentsPolicySetCount ` - -PolicySetAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicySetAtScopeCount ` - -PolicyAndPolicySetAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAndPolicySetAtScopeCount } - if ($L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/") { - $PolicyVariant = "PolicySet" - $definitiontype = "policySet" - $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 - if (($L0mgmtGroupPolicyAssignment.Properties.Description).length -eq 0) { - $PolicyAssignmentDescription = "no description given" - } - else { - $PolicyAssignmentDescription = $L0mgmtGroupPolicyAssignment.Properties.Description - } + addRowToTable ` + -level (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count - 1) ` + -mgName $getMgParentName ` + -mgId $getMgParentId ` + -mgParentId "'upperScopes'" ` + -mgParentName "upperScopes" ` + -Policy $Def.DisplayName ` + -PolicyDescription $Def.Description ` + -PolicyVariant $PolicyVariant ` + -PolicyType $Def.Type ` + -PolicyCategory $Def.Category ` + -PolicyDefinitionIdGuid (($Def.Id) -replace ".*/") ` + -PolicyDefinitionId $Def.PolicyDefinitionId ` + -PolicyDefintionScope $policyDefintionScope ` + -PolicyDefintionScopeMgSub $policyDefintionScopeMgSub ` + -PolicyDefintionScopeId $policyDefintionScopeId ` + -PolicyDefinitionsScopedLimit $LimitPOLICYPolicyDefinitionsScopedManagementGroup ` + -PolicyDefinitionsScopedCount $PolicyDefinitionsScopedCount ` + -PolicySetDefinitionsScopedLimit $LimitPOLICYPolicySetDefinitionsScopedManagementGroup ` + -PolicySetDefinitionsScopedCount $PolicySetDefinitionsScopedCount ` + -PolicyAssignmentScope $PolicyAssignmentScope ` + -PolicyAssignmentScopeMgSubRg "Mg" ` + -PolicyAssignmentScopeName ($PolicyAssignmentScope -replace ".*/", "") ` + -PolicyAssignmentNotScopes $L0mgmtGroupPolicyAssignment.Properties.NotScopes ` + -PolicyAssignmentId $PolicyAssignmentId ` + -PolicyAssignmentName $PolicyAssignmentName ` + -PolicyAssignmentDisplayName $PolicyAssignmentDisplayName ` + -PolicyAssignmentDescription $PolicyAssignmentDescription ` + -PolicyAssignmentEnforcementMode $L0mgmtGroupPolicyAssignment.Properties.EnforcementMode ` + -PolicyAssignmentNonComplianceMessages $L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages ` + -PolicyAssignmentIdentity $PolicyAssignmentIdentity ` + -PolicyAssigmentLimit $LimitPOLICYPolicyAssignmentsManagementGroup ` + -PolicyAssigmentCount $upperScopesPolicyAssignmentsPolicyCount ` + -PolicyAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAtScopeCount ` + -PolicyAssigmentParameters $L0mgmtGroupPolicyAssignment.Properties.Parameters ` + -PolicyAssignmentAssignedBy $assignedBy ` + -PolicyAssignmentCreatedBy $createdBy ` + -PolicyAssignmentCreatedOn $createdOn ` + -PolicyAssignmentUpdatedBy $updatedBy ` + -PolicyAssignmentUpdatedOn $updatedOn ` + -PolicySetAssigmentLimit $LimitPOLICYPolicySetAssignmentsManagementGroup ` + -PolicySetAssigmentCount $upperScopesPolicyAssignmentsPolicySetCount ` + -PolicySetAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicySetAtScopeCount ` + -PolicyAndPolicySetAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAndPolicySetAtScopeCount + } - if ($L0mgmtGroupPolicyAssignment.identity) { - $PolicyAssignmentIdentity = $L0mgmtGroupPolicyAssignment.identity.principalId - } - else { - $PolicyAssignmentIdentity = "n/a" - } + if ($L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match "/providers/Microsoft.Authorization/policySetDefinitions/") { + $PolicyVariant = "PolicySet" + $definitiontype = "policySet" + $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 + if (($L0mgmtGroupPolicyAssignment.Properties.Description).length -eq 0) { + $PolicyAssignmentDescription = "no description given" + } + else { + $PolicyAssignmentDescription = $L0mgmtGroupPolicyAssignment.Properties.Description + } - if ($Def.Type -eq "Custom") { - $policyDefintionScope = $Def.Scope - $policyDefintionScopeMgSub = $Def.ScopeMgSub - $policyDefintionScopeId = $Def.ScopeId - } - else { - $policyDefintionScope = "n/a" - $policyDefintionScopeMgSub = "n/a" - $policyDefintionScopeId = "n/a" - } + if ($L0mgmtGroupPolicyAssignment.identity) { + $PolicyAssignmentIdentity = $L0mgmtGroupPolicyAssignment.identity.principalId + } + else { + $PolicyAssignmentIdentity = "n/a" + } - addRowToTable ` - -level (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count - 1) ` - -mgName $getMgParentName ` - -mgId $getMgParentId ` - -mgParentId "'upperScopes'" ` - -mgParentName "upperScopes" ` - -Policy $Def.DisplayName ` - -PolicyDescription $Def.Description ` - -PolicyVariant $PolicyVariant ` - -PolicyType $Def.Type ` - -PolicyCategory $Def.Category ` - -PolicyDefinitionIdGuid (($Def.Id) -replace ".*/") ` - -PolicyDefinitionId $Def.PolicyDefinitionId ` - -PolicyDefintionScope $policyDefintionScope ` - -PolicyDefintionScopeMgSub $policyDefintionScopeMgSub ` - -PolicyDefintionScopeId $policyDefintionScopeId ` - -PolicyDefinitionsScopedLimit $LimitPOLICYPolicyDefinitionsScopedManagementGroup ` - -PolicyDefinitionsScopedCount $PolicyDefinitionsScopedCount ` - -PolicySetDefinitionsScopedLimit $LimitPOLICYPolicySetDefinitionsScopedManagementGroup ` - -PolicySetDefinitionsScopedCount $PolicySetDefinitionsScopedCount ` - -PolicyAssignmentScope $PolicyAssignmentScope ` - -PolicyAssignmentScopeMgSubRg "Mg" ` - -PolicyAssignmentScopeName ($PolicyAssignmentScope -replace ".*/", "") ` - -PolicyAssignmentNotScopes $L0mgmtGroupPolicyAssignment.Properties.NotScopes ` - -PolicyAssignmentId $PolicyAssignmentId ` - -PolicyAssignmentName $PolicyAssignmentName ` - -PolicyAssignmentDisplayName $PolicyAssignmentDisplayName ` - -PolicyAssignmentDescription $PolicyAssignmentDescription ` - -PolicyAssignmentEnforcementMode $L0mgmtGroupPolicyAssignment.Properties.EnforcementMode ` - -PolicyAssignmentIdentity $PolicyAssignmentIdentity ` - -PolicyAssigmentLimit $LimitPOLICYPolicyAssignmentsManagementGroup ` - -PolicyAssigmentCount $upperScopesPolicyAssignmentsPolicyCount ` - -PolicyAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAtScopeCount ` - -PolicyAssigmentParameters $L0mgmtGroupPolicyAssignment.Properties.Parameters ` - -PolicySetAssigmentLimit $LimitPOLICYPolicySetAssignmentsManagementGroup ` - -PolicySetAssigmentCount $upperScopesPolicyAssignmentsPolicySetCount ` - -PolicySetAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicySetAtScopeCount ` - -PolicyAndPolicySetAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAndPolicySetAtScopeCount + if ($Def.Type -eq "Custom") { + $policyDefintionScope = $Def.Scope + $policyDefintionScopeMgSub = $Def.ScopeMgSub + $policyDefintionScopeId = $Def.ScopeId + } + else { + $policyDefintionScope = "n/a" + $policyDefintionScopeMgSub = "n/a" + $policyDefintionScopeId = "n/a" } + + addRowToTable ` + -level (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count - 1) ` + -mgName $getMgParentName ` + -mgId $getMgParentId ` + -mgParentId "'upperScopes'" ` + -mgParentName "upperScopes" ` + -Policy $Def.DisplayName ` + -PolicyDescription $Def.Description ` + -PolicyVariant $PolicyVariant ` + -PolicyType $Def.Type ` + -PolicyCategory $Def.Category ` + -PolicyDefinitionIdGuid (($Def.Id) -replace ".*/") ` + -PolicyDefinitionId $Def.PolicyDefinitionId ` + -PolicyDefintionScope $policyDefintionScope ` + -PolicyDefintionScopeMgSub $policyDefintionScopeMgSub ` + -PolicyDefintionScopeId $policyDefintionScopeId ` + -PolicyDefinitionsScopedLimit $LimitPOLICYPolicyDefinitionsScopedManagementGroup ` + -PolicyDefinitionsScopedCount $PolicyDefinitionsScopedCount ` + -PolicySetDefinitionsScopedLimit $LimitPOLICYPolicySetDefinitionsScopedManagementGroup ` + -PolicySetDefinitionsScopedCount $PolicySetDefinitionsScopedCount ` + -PolicyAssignmentScope $PolicyAssignmentScope ` + -PolicyAssignmentScopeMgSubRg "Mg" ` + -PolicyAssignmentScopeName ($PolicyAssignmentScope -replace ".*/", "") ` + -PolicyAssignmentNotScopes $L0mgmtGroupPolicyAssignment.Properties.NotScopes ` + -PolicyAssignmentId $PolicyAssignmentId ` + -PolicyAssignmentName $PolicyAssignmentName ` + -PolicyAssignmentDisplayName $PolicyAssignmentDisplayName ` + -PolicyAssignmentDescription $PolicyAssignmentDescription ` + -PolicyAssignmentEnforcementMode $L0mgmtGroupPolicyAssignment.Properties.EnforcementMode ` + -PolicyAssignmentNonComplianceMessages $L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages ` + -PolicyAssignmentIdentity $PolicyAssignmentIdentity ` + -PolicyAssigmentLimit $LimitPOLICYPolicyAssignmentsManagementGroup ` + -PolicyAssigmentCount $upperScopesPolicyAssignmentsPolicyCount ` + -PolicyAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAtScopeCount ` + -PolicyAssigmentParameters $L0mgmtGroupPolicyAssignment.Properties.Parameters ` + -PolicySetAssigmentLimit $LimitPOLICYPolicySetAssignmentsManagementGroup ` + -PolicySetAssigmentCount $upperScopesPolicyAssignmentsPolicySetCount ` + -PolicySetAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicySetAtScopeCount ` + -PolicyAndPolicySetAssigmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAndPolicySetAtScopeCount } } } } - # - if ($htParameters.LargeTenant -eq $true) { + } + # + if ($htParameters.LargeTenant -eq $true) { - #RoleAssignment API (system metadata e.g. createdOn) + #RoleAssignment API (system metadata e.g. createdOn) $currentTask = "Role assignments API '$($ManagementGroupId)'" $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).ResourceManagerUrl)providers/Microsoft.Management/managementGroups/$($ManagementGroupId)/providers/Microsoft.Authorization/roleAssignments?api-version=2015-07-01" #$path = "/providers/Microsoft.Management/managementGroups/$($mgdetail.Name)/providers/Microsoft.Authorization/roleAssignments?api-version=2015-07-01" @@ -19300,148 +19310,144 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $htMgAtScopePolicyAssignmentsAndPoliciesScopedAndRoleAssignments.RoleAssignments."tenantLevelRoleAssignments".AssignmentsCount = $tenantLevelRoleAssignmentsCount } - foreach ($upperScopesRoleAssignment in $upperScopesRoleAssignments) { + foreach ($upperScopesRoleAssignment in $upperScopesRoleAssignments) { - if (-not $upperScopesRoleAssignment.RoleAssignmentId) { - if (-not $($htCacheAssignments).roleClassic.("$($upperScopesRoleAssignment.RoleDefinitionName)_$($upperScopesRoleAssignment.Scope)_$($upperScopesRoleAssignment.SignInName)")) { - $($script:htCacheAssignments).roleClassic.("$($upperScopesRoleAssignment.RoleDefinitionName)_$($upperScopesRoleAssignment.Scope)_$($upperScopesRoleAssignment.SignInName)") = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) - $($script:htCacheAssignments).roleClassic.("$($upperScopesRoleAssignment.RoleDefinitionName)_$($upperScopesRoleAssignment.Scope)_$($upperScopesRoleAssignment.SignInName)") = $upperScopesRoleAssignment - } - continue + if (-not $upperScopesRoleAssignment.RoleAssignmentId) { + if (-not $($htCacheAssignments).roleClassic.("$($upperScopesRoleAssignment.RoleDefinitionName)_$($upperScopesRoleAssignment.Scope)_$($upperScopesRoleAssignment.SignInName)")) { + $($script:htCacheAssignments).roleClassic.("$($upperScopesRoleAssignment.RoleDefinitionName)_$($upperScopesRoleAssignment.Scope)_$($upperScopesRoleAssignment.SignInName)") = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) + $($script:htCacheAssignments).roleClassic.("$($upperScopesRoleAssignment.RoleDefinitionName)_$($upperScopesRoleAssignment.Scope)_$($upperScopesRoleAssignment.SignInName)") = $upperScopesRoleAssignment } + continue + } - if ($upperScopesRoleAssignment.Scope -ne "/providers/Microsoft.Management/managementGroups/$ManagementGroupId") { - $Id = $upperScopesRoleAssignment.RoleDefinitionId - $definitiontype = "role" + if ($upperScopesRoleAssignment.Scope -ne "/providers/Microsoft.Management/managementGroups/$ManagementGroupId") { + $Id = $upperScopesRoleAssignment.RoleDefinitionId + $definitiontype = "role" - if (($upperScopesRoleAssignment.RoleDefinitionName).length -eq 0) { - $RoleDefinitionName = "'This roleDefinition likely was deleted although a roleAssignment existed'" - } - else { - $RoleDefinitionName = $upperScopesRoleAssignment.RoleDefinitionName - } - if (($upperScopesRoleAssignment.DisplayName).length -eq 0) { - $RoleAssignmentIdentityDisplayname = "n/a" - } - else { - if ($upperScopesRoleAssignment.ObjectType -eq "User") { - if ($htParameters.DoNotShowRoleAssignmentsUserData -eq $false) { - $RoleAssignmentIdentityDisplayname = $upperScopesRoleAssignment.DisplayName - } - else { - $RoleAssignmentIdentityDisplayname = "scrubbed" - } - } - else { + if (($upperScopesRoleAssignment.RoleDefinitionName).length -eq 0) { + $RoleDefinitionName = "'This roleDefinition likely was deleted although a roleAssignment existed'" + } + else { + $RoleDefinitionName = $upperScopesRoleAssignment.RoleDefinitionName + } + if (($upperScopesRoleAssignment.DisplayName).length -eq 0) { + $RoleAssignmentIdentityDisplayname = "n/a" + } + else { + if ($upperScopesRoleAssignment.ObjectType -eq "User") { + if ($htParameters.DoNotShowRoleAssignmentsUserData -eq $false) { $RoleAssignmentIdentityDisplayname = $upperScopesRoleAssignment.DisplayName } - } - if (($upperScopesRoleAssignment.SignInName).length -eq 0) { - $RoleAssignmentIdentitySignInName = "n/a" + else { + $RoleAssignmentIdentityDisplayname = "scrubbed" + } } else { - if ($upperScopesRoleAssignment.ObjectType -eq "User") { - if ($htParameters.DoNotShowRoleAssignmentsUserData -eq $false) { - $RoleAssignmentIdentitySignInName = $upperScopesRoleAssignment.SignInName - } - else { - $RoleAssignmentIdentitySignInName = "scrubbed" - } + $RoleAssignmentIdentityDisplayname = $upperScopesRoleAssignment.DisplayName + } + } + if (($upperScopesRoleAssignment.SignInName).length -eq 0) { + $RoleAssignmentIdentitySignInName = "n/a" + } + else { + if ($upperScopesRoleAssignment.ObjectType -eq "User") { + if ($htParameters.DoNotShowRoleAssignmentsUserData -eq $false) { + $RoleAssignmentIdentitySignInName = $upperScopesRoleAssignment.SignInName } else { - $RoleAssignmentIdentitySignInName = $upperScopesRoleAssignment.SignInName + $RoleAssignmentIdentitySignInName = "scrubbed" } } - $RoleAssignmentIdentityObjectId = $upperScopesRoleAssignment.ObjectId - $RoleAssignmentIdentityObjectType = $upperScopesRoleAssignment.ObjectType - $RoleAssignmentId = $upperScopesRoleAssignment.RoleAssignmentId - $RoleAssignmentScope = $upperScopesRoleAssignment.Scope - $RoleAssignmentScopeName = $RoleAssignmentScope -replace '.*/' - $RoleAssignmentScopeType = "MG" - - $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 - } - $RoleSecurityOwnerAssignmentSP = 0 - if ((($htCacheDefinitions).$definitiontype.$($Id).Id -eq '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' -and $RoleAssignmentIdentityObjectType -eq "ServicePrincipal") -or (($htCacheDefinitions).$definitiontype.$($Id).Actions -eq '*' -and ((($htCacheDefinitions).$definitiontype.$($Id).NotActions)).length -eq 0 -and ($htCacheDefinitions).$definitiontype.$($Id).IsCustom -eq $True -and $RoleAssignmentIdentityObjectType -eq "ServicePrincipal")) { - $RoleSecurityOwnerAssignmentSP = 1 + else { + $RoleAssignmentIdentitySignInName = $upperScopesRoleAssignment.SignInName } + } + $RoleAssignmentIdentityObjectId = $upperScopesRoleAssignment.ObjectId + $RoleAssignmentIdentityObjectType = $upperScopesRoleAssignment.ObjectType + $RoleAssignmentId = $upperScopesRoleAssignment.RoleAssignmentId + $RoleAssignmentScope = $upperScopesRoleAssignment.Scope + $RoleAssignmentScopeName = $RoleAssignmentScope -replace '.*/' + $RoleAssignmentScopeType = "MG" + + $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 + } + $RoleSecurityOwnerAssignmentSP = 0 + if ((($htCacheDefinitions).$definitiontype.$($Id).Id -eq '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' -and $RoleAssignmentIdentityObjectType -eq "ServicePrincipal") -or (($htCacheDefinitions).$definitiontype.$($Id).Actions -eq '*' -and ((($htCacheDefinitions).$definitiontype.$($Id).NotActions)).length -eq 0 -and ($htCacheDefinitions).$definitiontype.$($Id).IsCustom -eq $True -and $RoleAssignmentIdentityObjectType -eq "ServicePrincipal")) { + $RoleSecurityOwnerAssignmentSP = 1 + } - $createdBy = "" - $createdOn = "" - $createdOnUnformatted = $null - $updatedBy = "" - $updatedOn = "" - if (($htCacheAssignments).roleFromAPI.($RoleAssignmentId)) { - $hlp = ($htCacheAssignments).roleFromAPI.($RoleAssignmentId).assignment.properties - if ($hlp.createdBy) { - $createdBy = $hlp.createdBy - } - if ($hlp.createdOn) { - $createdOn = $hlp.createdOn.ToString("yyyy-MM-dd HH:mm:ss") - } - if ($hlp.updatedBy) { - $updatedBy = $hlp.updatedBy - } - if ($hlp.updatedOn) { - $updatedOn = $hlp.updatedOn.ToString("yyyy-MM-dd HH:mm:ss") - } - $createdOnUnformatted = $hlp.createdOn + $createdBy = "" + $createdOn = "" + $createdOnUnformatted = $null + $updatedBy = "" + $updatedOn = "" + if (($htCacheAssignments).roleFromAPI.($RoleAssignmentId)) { + $hlp = ($htCacheAssignments).roleFromAPI.($RoleAssignmentId).assignment.properties + if ($hlp.createdBy) { + $createdBy = $hlp.createdBy } - - if (($checkContext).Tenant.Id -ne $ManagementGroupId) { - $levelToUse = (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count - 1) - $toUseAsmgName = $getMgParentName - $toUseAsmgId = $getMgParentId - $toUseAsmgParentId = "'upperScopes'" - $toUseAsmgParentName = "upperScopes" + if ($hlp.createdOn) { + $createdOn = $hlp.createdOn.ToString("yyyy-MM-dd HH:mm:ss") } - else { - $levelToUse = (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count) - $toUseAsmgName = $selectedManagementGroupId.DisplayName - $toUseAsmgId = $selectedManagementGroupId.Name - $toUseAsmgParentId = "Tenant" - $toUseAsmgParentName = "Tenant" + if ($hlp.updatedBy) { + $updatedBy = $hlp.updatedBy } - addRowToTable ` - -level $levelToUse ` - -mgName $toUseAsmgName ` - -mgId $toUseAsmgId ` - -mgParentId $toUseAsmgParentId ` - -mgParentName $toUseAsmgParentName ` - -RoleDefinitionId ($htCacheDefinitions).$definitiontype.$($Id).Id ` - -RoleDefinitionName $RoleDefinitionName ` - -RoleIsCustom ($htCacheDefinitions).$definitiontype.$($Id).IsCustom ` - -RoleAssignableScopes (($htCacheDefinitions).$definitiontype.$($Id).AssignableScopes -join "$CsvDelimiterOpposite ") ` - -RoleActions (($htCacheDefinitions).$definitiontype.$($Id).Actions -join "$CsvDelimiterOpposite ") ` - -RoleNotActions (($htCacheDefinitions).$definitiontype.$($Id).NotActions -join "$CsvDelimiterOpposite ") ` - -RoleDataActions (($htCacheDefinitions).$definitiontype.$($Id).DataActions -join "$CsvDelimiterOpposite ") ` - -RoleNotDataActions (($htCacheDefinitions).$definitiontype.$($Id).NotDataActions -join "$CsvDelimiterOpposite ") ` - -RoleAssignmentIdentityDisplayname $RoleAssignmentIdentityDisplayname ` - -RoleAssignmentIdentitySignInName $RoleAssignmentIdentitySignInName ` - -RoleAssignmentIdentityObjectId $RoleAssignmentIdentityObjectId ` - -RoleAssignmentIdentityObjectType $RoleAssignmentIdentityObjectType ` - -RoleAssignmentId $RoleAssignmentId ` - -RoleAssignmentScope $RoleAssignmentScope ` - -RoleAssignmentScopeName $RoleAssignmentScopeName ` - -RoleAssignmentScopeType $RoleAssignmentScopeType ` - -RoleAssignmentCreatedBy $createdBy ` - -RoleAssignmentCreatedOn $createdOn ` - -RoleAssignmentCreatedOnUnformatted $createdOnUnformatted ` - -RoleAssignmentUpdatedBy $updatedBy ` - -RoleAssignmentUpdatedOn $updatedOn ` - -RoleAssignmentsLimit $LimitRBACRoleAssignmentsManagementGroup ` - -RoleAssignmentsCount $upperScopesRoleAssignmentsLimitUtilization ` - -RoleSecurityCustomRoleOwner $RoleSecurityCustomRoleOwner ` - -RoleSecurityOwnerAssignmentSP $RoleSecurityOwnerAssignmentSP + if ($hlp.updatedOn) { + $updatedOn = $hlp.updatedOn.ToString("yyyy-MM-dd HH:mm:ss") + } + $createdOnUnformatted = $hlp.createdOn + } + + if (($checkContext).Tenant.Id -ne $ManagementGroupId) { + $levelToUse = (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count - 1) + $toUseAsmgName = $getMgParentName + $toUseAsmgId = $getMgParentId + $toUseAsmgParentId = "'upperScopes'" + $toUseAsmgParentName = "upperScopes" + } + else { + $levelToUse = (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count) + $toUseAsmgName = $selectedManagementGroupId.DisplayName + $toUseAsmgId = $selectedManagementGroupId.Name + $toUseAsmgParentId = "Tenant" + $toUseAsmgParentName = "Tenant" } + addRowToTable ` + -level $levelToUse ` + -mgName $toUseAsmgName ` + -mgId $toUseAsmgId ` + -mgParentId $toUseAsmgParentId ` + -mgParentName $toUseAsmgParentName ` + -RoleDefinitionId ($htCacheDefinitions).$definitiontype.$($Id).Id ` + -RoleDefinitionName $RoleDefinitionName ` + -RoleIsCustom ($htCacheDefinitions).$definitiontype.$($Id).IsCustom ` + -RoleAssignableScopes (($htCacheDefinitions).$definitiontype.$($Id).AssignableScopes -join "$CsvDelimiterOpposite ") ` + -RoleActions (($htCacheDefinitions).$definitiontype.$($Id).Actions -join "$CsvDelimiterOpposite ") ` + -RoleNotActions (($htCacheDefinitions).$definitiontype.$($Id).NotActions -join "$CsvDelimiterOpposite ") ` + -RoleDataActions (($htCacheDefinitions).$definitiontype.$($Id).DataActions -join "$CsvDelimiterOpposite ") ` + -RoleNotDataActions (($htCacheDefinitions).$definitiontype.$($Id).NotDataActions -join "$CsvDelimiterOpposite ") ` + -RoleAssignmentIdentityDisplayname $RoleAssignmentIdentityDisplayname ` + -RoleAssignmentIdentitySignInName $RoleAssignmentIdentitySignInName ` + -RoleAssignmentIdentityObjectId $RoleAssignmentIdentityObjectId ` + -RoleAssignmentIdentityObjectType $RoleAssignmentIdentityObjectType ` + -RoleAssignmentId $RoleAssignmentId ` + -RoleAssignmentScope $RoleAssignmentScope ` + -RoleAssignmentScopeName $RoleAssignmentScopeName ` + -RoleAssignmentScopeType $RoleAssignmentScopeType ` + -RoleAssignmentCreatedBy $createdBy ` + -RoleAssignmentCreatedOn $createdOn ` + -RoleAssignmentCreatedOnUnformatted $createdOnUnformatted ` + -RoleAssignmentUpdatedBy $updatedBy ` + -RoleAssignmentUpdatedOn $updatedOn ` + -RoleAssignmentsLimit $LimitRBACRoleAssignmentsManagementGroup ` + -RoleAssignmentsCount $upperScopesRoleAssignmentsLimitUtilization ` + -RoleSecurityCustomRoleOwner $RoleSecurityCustomRoleOwner ` + -RoleSecurityOwnerAssignmentSP $RoleSecurityOwnerAssignmentSP } } - - - - + } $endDataCollection = get-date Write-Host "Collecting custom data duration: $((NEW-TIMESPAN -Start $startDataCollection -End $endDataCollection).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startDataCollection -End $endDataCollection).TotalSeconds) seconds)" @@ -19492,37 +19498,6 @@ $optimizedTableForPathQueryMg = ($optimizedTableForPathQuery.where( { [String]:: $optimizedTableForPathQuerySub = ($optimizedTableForPathQuery.where( { -not [String]::IsNullOrEmpty($_.SubscriptionId) } ) | Select-Object -Property subscription*) | sort-object -Property subscriptionId -Unique if ($htParameters.HierarchyMapOnly -eq $false) { - #region dataprocessingAADGuests - if (-not $NoAADGuestUsers) { - Write-Host "Getting AAD Guest Users" - $startAADGuestUsers = get-date - - $currenttask = "Get AAD Guest Users Count" - $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).MSGraphUrl)/v1.0/users/`$count?`$filter=userType eq 'Guest'" - $method = "GET" - $aadGuestUsersCountFromAPI = AzAPICall -uri $uri -method $method -currentTask $currenttask -listenOn "Content" $true -consistencyLevel "eventual" - Write-Host " Count of $aadGuestUsersCountFromAPI AAD Guest Users received" - - if ($aadGuestUsersCountFromAPI -gt 0) { - - $currenttask = "Get AAD Guest Users" - $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).MSGraphUrl)/v1.0/users?`$filter=userType eq 'Guest'" - $method = "GET" - $aadGuestUsers = AzAPICall -uri $uri -method $method -currentTask $currenttask -getGuests $true - - $aadGuestUsersCount = ($aadGuestUsers | Measure-Object).Count - Write-Host " Collected $aadGuestUsersCount AAD Guest Users" - - foreach ($aadGuestUser in $aadGuestUsers) { - $htUserTypes.($aadGuestUser.Id) = @{ } - $htUserTypes.($aadGuestUser.Id).userType = "Guest" - } - } - - $endAADGuestUsers = Get-Date - Write-Host "Getting AAD Guest Users duration: $((NEW-TIMESPAN -Start $startAADGuestUsers -End $endAADGuestUsers).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startAADGuestUsers -End $endAADGuestUsers).TotalSeconds) seconds)" - } - #endregion dataprocessingAADGuests #region dataprocessingAADGroups if (-not $NoAADGroupsResolveMembers) { @@ -19537,7 +19512,7 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $script:htAADGroupsDetails.$aadGroupId = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) $script:htAADGroupsDetails.($aadGroupId).Id = $aadGroupId $script:htAADGroupsDetails.($aadGroupId).displayname = $aadGroupDisplayName - $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).MSGraphUrl)/beta/groups/$($aadGroupId)/transitiveMembers" + $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).MSGraphUrl)/v1.0/groups/$($aadGroupId)/transitiveMembers" $method = "GET" $aadGroupMembers = AzAPICall -uri $uri -method $method -currentTask "getGroupMembers $($aadGroupId)" -getGroup $true @@ -19670,6 +19645,87 @@ if ($htParameters.HierarchyMapOnly -eq $false) { } #endregion dataprocessingAADGroups + #region dataprocessingAADGuests + if (-not $NoAADGuestUsers) { + Write-Host "Getting AAD Guest Users" + $startAADGuestUsers = get-date + + $currenttask = "Get AAD Guest Users Count" + $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).MSGraphUrl)/v1.0/users/`$count?`$filter=userType eq 'Guest'" + $method = "GET" + $aadGuestUsersCountFromAPI = AzAPICall -uri $uri -method $method -currentTask $currenttask -listenOn "Content" $true -consistencyLevel "eventual" + Write-Host " Count of $aadGuestUsersCountFromAPI AAD Guest Users received" + + if ($aadGuestUsersCountFromAPI -gt 0) { + + + $startguestuserscheck = Get-Date + Write-Host " GuestUsers check" + #users (objectId) that are group members + if (-not $NoAADGroupsResolveMembers) { + if ($htAADGroupsDetails.values.MembersUsers){ + $usersThatAreGroupMembers = ($htAADGroupsDetails.values.MembersUsers.id | sort-object -unique) + $usersThatAreGroupMembersCount = $usersThatAreGroupMembers.Count + } + else{ + $usersThatAreGroupMembersCount = 0 + } + } + else{ + $usersThatAreGroupMembersCount = 0 + } + + #users (objectId) that have a direct ra + $usersThatHaveADirectRA = ($newTable.where( { $_.RoleAssignmentIdentityObjectType -eq "User" } ) | sort-object -Property RoleAssignmentIdentityObjectId -Unique).RoleAssignmentIdentityObjectId + $usersThatHaveADirectRACount = $usersThatHaveADirectRA.Count + + $htUsersThatNeedToBeResolvedForUserType = @{} + if ($usersThatAreGroupMembersCount -gt 0){ + foreach ($userThatIsAGroupMember in $usersThatAreGroupMembers){ + $htUsersThatNeedToBeResolvedForUserType.($userThatIsAGroupMember) = @{} + } + } + if ($usersThatHaveADirectRACount -gt 0){ + foreach ($userThatHasADirectRA in $usersThatHaveADirectRA){ + if (-not $htUsersThatNeedToBeResolvedForUserType.($userThatHasADirectRA)){ + $htUsersThatNeedToBeResolvedForUserType.($userThatHasADirectRA) = @{} + } + } + } + + $usersThatNeedToBeResolvedForUserTypeCount = $htUsersThatNeedToBeResolvedForUserType.Count + + if ($aadGuestUsersCountFromAPI -gt $usersThatNeedToBeResolvedForUserTypeCount){ + Write-Host " guest count $aadGuestUsersCountFromAPI > usersToBeResolved count $usersThatNeedToBeResolvedForUserTypeCount" + } + else{ + Write-Host " guest count $aadGuestUsersCountFromAPI < usersToBeResolved count $usersThatNeedToBeResolvedForUserTypeCount" + } + + $endguestuserscheck = Get-Date + Write-Host " GuestUsers check duration: $((NEW-TIMESPAN -Start $startguestuserscheck -End $endguestuserscheck).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startguestuserscheck -End $endguestuserscheck).TotalSeconds) seconds)" + + + + $currenttask = "Get AAD Guest Users" + $uri = "$(($htAzureEnvironmentRelatedUrls).($checkContext.Environment.Name).MSGraphUrl)/v1.0/users?`$filter=userType eq 'Guest'" + $method = "GET" + $aadGuestUsers = AzAPICall -uri $uri -method $method -currentTask $currenttask -getGuests $true + + $aadGuestUsersCount = ($aadGuestUsers | Measure-Object).Count + Write-Host " Collected $aadGuestUsersCount AAD Guest Users" + + foreach ($aadGuestUser in $aadGuestUsers) { + $htUserTypes.($aadGuestUser.Id) = @{ } + $htUserTypes.($aadGuestUser.Id).userType = "Guest" + } + } + + $endAADGuestUsers = Get-Date + Write-Host "Getting AAD Guest Users duration: $((NEW-TIMESPAN -Start $startAADGuestUsers -End $endAADGuestUsers).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startAADGuestUsers -End $endAADGuestUsers).TotalSeconds) seconds)" + } + #endregion dataprocessingAADGuests + #region dataprocessingAADSP if (-not $NoAADServicePrincipalResolve) { Write-Host "Getting ServicePrincipals (for which a RBAC Role assignment exists)" @@ -20150,17 +20206,15 @@ $startBuildCSV = get-date $outprops = $newtable[0].PSObject.Properties.Name $outprops.Set($outprops.IndexOf('PolicyAssignmentNotScopes'), @{L = 'PolicyAssignmentNotScopes'; E = { ($_.PolicyAssignmentNotScopes -join "$CsvDelimiterOpposite ") } }) if ($CsvExportUseQuotesAsNeeded) { - #$newTable | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded - $newTable | Select-Object -Property $outprops | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded + $newTable | Sort-Object -Property level, mgId, SubscriptionId, PolicyAssignmentId, RoleAssignmentId, BlueprintId, BlueprintAssignmentId | Select-Object -Property $outprops | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).csv" -Delimiter "$csvDelimiter" -NoTypeInformation -UseQuotes AsNeeded } else { - #$newTable | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).csv" -Delimiter "$csvDelimiter" -NoTypeInformation - $newTable | Select-Object -Property $outprops | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).csv" -Delimiter "$csvDelimiter" -NoTypeInformation + $newTable | Sort-Object -Property level, mgId, SubscriptionId, PolicyAssignmentId, RoleAssignmentId, BlueprintId, BlueprintAssignmentId | Select-Object -Property $outprops | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName).csv" -Delimiter "$csvDelimiter" -NoTypeInformation } if (-not $NoCsvExport) { #DataCollection Export of All Resources - $resourcesIdsAll | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName)_ResourcesAll.csv" -Delimiter "$csvDelimiter" -NoTypeInformation + $resourcesIdsAll | Sort-Object -Property id | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName)_ResourcesAll.csv" -Delimiter "$csvDelimiter" -NoTypeInformation } $endBuildCSV = get-date @@ -20171,7 +20225,7 @@ if ($htParameters.HierarchyMapOnly -eq $false) { #region preQueries Write-Host " Building preQueries" - if ($htParameters.PolicyIncludeResourceGroups -eq $true) { + if (-not $DoNotIncludeResourceGroupsOnPolicy) { $policyBaseQuery = $newTable.where( { -not [String]::IsNullOrEmpty($_.PolicyVariant) } ) | Sort-Object -Property PolicyType, Policy | Select-Object -Property Level, Policy*, mg*, Subscription* } else { @@ -20183,13 +20237,20 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $policyPolicyBaseQueryScopeInsights = ($policyBaseQuery | Select-Object Mg*, Subscription*, PolicyAssigmentAtScopeCount, PolicySetAssigmentAtScopeCount, PolicyAndPolicySetAssigmentAtScopeCount, PolicyAssigmentLimit -Unique) $policyBaseQueryUniqueAssignments = $policyBaseQuery | Select-Object -Property Policy* | sort-object -Property PolicyAssignmentId -Unique - $policyPolicyBaseQueryUniqueAssignmentsArrayList = [System.Collections.ArrayList]@() + $htPolicyWithAssignmentsBase = @{ } $htCacheAssignments2 = @{ } ($htCacheAssignments2).policy = @{ } foreach ($policyAssignment in $policyBaseQueryUniqueAssignments) { - #array policyPolicyBaseQueryUniqueAssignmentsArrayList if ($policyAssignment.PolicyVariant -eq "Policy") { - $null = $policyPolicyBaseQueryUniqueAssignmentsArrayList.Add($policyAssignment) + if (-not $htPolicyWithAssignmentsBase.($policyAssignment.PolicyDefinitionId)) { + $htPolicyWithAssignmentsBase.($policyAssignment.PolicyDefinitionId) = @{ } + $htPolicyWithAssignmentsBase.($policyAssignment.PolicyDefinitionId).Assignments = [array]$policyAssignment.PolicyAssignmentId + } + else { + $usedInAssignments = $htPolicyWithAssignmentsBase.($policyAssignment.PolicyDefinitionId).Assignments + $usedInAssignments += $policyAssignment.PolicyAssignmentId + $htPolicyWithAssignmentsBase.($policyAssignment.PolicyDefinitionId).Assignments = $usedInAssignments + } } #ht htCacheAssignments2 @@ -20225,7 +20286,7 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $endcreateArrayListRBAC = get-date Write-Host " Create ArrayListsRBAC duration: $((NEW-TIMESPAN -Start $startcreateArrayListRBAC -End $endcreateArrayListRBAC).TotalMinutes) minutes ($((NEW-TIMESPAN -Start $startcreateArrayListRBAC -End $endcreateArrayListRBAC).TotalSeconds) seconds)" - $blueprintBaseQuery = $newTable.where( { -not [String]::IsNullOrEmpty($_.BlueprintName) } ) + $blueprintBaseQuery = ($newTable | Select-Object mgid, SubscriptionId, Blueprint*).where( { -not [String]::IsNullOrEmpty($_.BlueprintName) } ) $mgsAndSubs = (($optimizedTableForPathQuery.where( { $_.mgId -ne "" -and $_.Level -ne "0" } )) | select-object MgId, SubscriptionId -unique) #region create array Policy definitions @@ -20292,13 +20353,10 @@ if ($htParameters.HierarchyMapOnly -eq $false) { } $mgSubRoleAssignmentsArrayFromHTValues = ($htCacheAssignments).role.Values.Assignment - if (-not $RBACIncludeResourceGroupsAndResources) { + if ($DoNotIncludeResourceGroupsAndResourcesOnRBAC) { $rgResRoleAssignmentsArrayFromHTValues = ($htCacheAssignments).rbacOnResourceGroupsAndResources.Values } - - $endHelperQueries = get-date - Write-Host "Helper Queries duration: $((NEW-TIMESPAN -Start $startHelperQueries -End $endHelperQueries).TotalSeconds) seconds" - + #diagnostics Mg/Sub $diagnosticSettingsMg = $arrayDiagnosticSettingsMgSub.where( { $_.Scope -eq "Mg" -and $_.DiagnosticsPresent -eq "true" }) $diagnosticSettingsMgCount = $diagnosticSettingsMg.Count @@ -20353,6 +20411,8 @@ if ($htParameters.HierarchyMapOnly -eq $false) { } } } + $endHelperQueries = get-date + Write-Host " Pre Queries duration: $((NEW-TIMESPAN -Start $startHelperQueries -End $endHelperQueries).TotalSeconds) seconds" #endregion preQueries #region summarizeDataCollectionResults @@ -20367,7 +20427,7 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $totalPolicyDefinitionsCustomCount = ((($htCacheDefinitions).policy.keys | Where-Object { ($htCacheDefinitions).policy.($_).Type -eq "Custom" }) | Measure-Object).count $totalPolicySetDefinitionsCustomCount = ((($htCacheDefinitions).policySet.keys | Where-Object { ($htCacheDefinitions).policySet.($_).Type -eq "Custom" }) | Measure-Object).count - if ($htParameters.PolicyIncludeResourceGroups -eq $true) { + if (-not $DoNotIncludeResourceGroupsOnPolicy) { $totalPolicyAssignmentsCount = (($htCacheAssignments2).policy.keys | Measure-Object).count $totalPolicyAssignmentsCountMg = (($htCacheAssignments2).policy.keys | Where-Object { ($htCacheAssignments2).policy.($_).PolicyAssignmentScopeMgSubRg -eq "Mg" } | Measure-Object).count $totalPolicyAssignmentsCountSub = (($htCacheAssignments2).policy.keys | Where-Object { ($htCacheAssignments2).policy.($_).PolicyAssignmentScopeMgSubRg -eq "Sub" } | Measure-Object).count @@ -20377,7 +20437,6 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $totalPolicyAssignmentsCount = (($htCacheAssignments2).policy.keys | Measure-Object).count $totalPolicyAssignmentsCountMg = (($htCacheAssignments2).policy.keys | Where-Object { ($htCacheAssignments2).policy.($_).PolicyAssignmentScopeMgSubRg -eq "Mg" } | Measure-Object).count $totalPolicyAssignmentsCountSub = (($htCacheAssignments2).policy.keys | Where-Object { ($htCacheAssignments2).policy.($_).PolicyAssignmentScopeMgSubRg -eq "Sub" } | Measure-Object).count - #$totalPolicyAssignmentsCountRg = ($arrayCachePolicyAssignmentsResourceGroupsAndResources | Measure-Object).count $totalPolicyAssignmentsCountRg = (($htCacheAssignments).policyOnResourceGroupsAndResources.values | Measure-Object).count $totalPolicyAssignmentsCount = $totalPolicyAssignmentsCount + $totalPolicyAssignmentsCountRg } @@ -20430,7 +20489,7 @@ $html += @" link.media = "screen,print"; document.getElementsByTagName( "head" )[0].appendChild( link ); - + @@ -20598,26 +20657,26 @@ $script:html += @"
"@ - $script:html += @" +$script:html += @"
"@ - if ($tenantRoleAssignmentCount -gt 0) { - $script:html += @" +if ($tenantRoleAssignmentCount -gt 0) { + $script:html += @"
$($tenantRoleAssignmentCount)
"@ - } - else { - $script:html += @" +} +else { + $script:html += @"
"@ - } - $script:html += @" +} +$script:html += @"
@@ -20649,14 +20708,12 @@ else { $tenantDetailsDisplay = "" } - $policyAssignmentsMg = $htcacheassignments2.policy.values.where({$_.PolicyAssignmentScopeMgSubRg -eq "Mg"}) - $policiesMgScoped = ($htCacheDefinitions).policy.values.where({$_.ScopeMgSub -eq "Mg"}) - $policySetsMgScoped = ($htCacheDefinitions).policySet.values.where({$_.ScopeMgSub -eq "Mg"}) - $roleAssignmentsMg = ($htcacheAssignments.role.values.where({$_.AssignmentScopeTenMgSubRgRes -eq "Mg"})) - #$htManagementGroupsMgPath."9".ParentNameChain[1..($htManagementGroupsMgPath."9".ParentNameChain.Count)] - #$parentMgIdx = "0110" - #foreach ($parentMgId in $htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain[1..($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain.Count)]){ - foreach ($parentMgId in $htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain){ + $policyAssignmentsMg = $htcacheassignments2.policy.values.where( { $_.PolicyAssignmentScopeMgSubRg -eq "Mg" }) + $policiesMgScoped = ($htCacheDefinitions).policy.values.where( { $_.ScopeMgSub -eq "Mg" }) + $policySetsMgScoped = ($htCacheDefinitions).policySet.values.where( { $_.ScopeMgSub -eq "Mg" }) + $roleAssignmentsMg = ($htcacheAssignments.role.values.where( { $_.AssignmentScopeTenMgSubRgRes -eq "Mg" })) + + foreach ($parentMgId in $htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain) { if ($parentMgId -eq $defaultManagementGroupId) { $classdefaultMG = "defaultMG" } @@ -20664,11 +20721,9 @@ else { $classdefaultMG = "" } - $mgPolicyAssignmentCount = ($policyAssignmentsMg.where({$_.PolicyAssignmentScopeName -eq $parentMgId})).Count - - $mgPolicyPolicySetScopedCount = ($policiesMgScoped.where({$_.ScopeId -eq $parentMgId}).Count) + ($policySetsMgScoped.where({$_.ScopeId -eq $parentMgId}).Count) - - $mgIdRoleAssignmentCount = $roleAssignmentsMg.where({$_.AssignmentScopeId -eq $parentMgId}).Count + $mgPolicyAssignmentCount = ($policyAssignmentsMg.where( { $_.PolicyAssignmentScopeName -eq $parentMgId })).Count + $mgPolicyPolicySetScopedCount = ($policiesMgScoped.where( { $_.ScopeId -eq $parentMgId }).Count) + ($policySetsMgScoped.where( { $_.ScopeId -eq $parentMgId }).Count) + $mgIdRoleAssignmentCount = $roleAssignmentsMg.where( { $_.AssignmentScopeId -eq $parentMgId }).Count $html += @"
    @@ -20679,9 +20734,9 @@ else {
    "@ -if ($mgPolicyAssignmentCount -gt 0 -or $mgPolicyPolicySetScopedCount -gt 0) { -if ($mgPolicyAssignmentCount -gt 0 -and $mgPolicyPolicySetScopedCount -gt 0) { - $script:html += @" + if ($mgPolicyAssignmentCount -gt 0 -or $mgPolicyPolicySetScopedCount -gt 0) { + if ($mgPolicyAssignmentCount -gt 0 -and $mgPolicyPolicySetScopedCount -gt 0) { + $script:html += @"
    $($mgPolicyAssignmentCount)
    @@ -20689,49 +20744,49 @@ if ($mgPolicyAssignmentCount -gt 0 -and $mgPolicyPolicySetScopedCount -gt 0) { $($mgPolicyPolicySetScopedCount)
    "@ -} -else { - if ($mgPolicyAssignmentCount -gt 0) { - $script:html += @" + } + else { + if ($mgPolicyAssignmentCount -gt 0) { + $script:html += @"
    $($mgPolicyAssignmentCount)
    "@ - } - if ($mgPolicyPolicySetScopedCount -gt 0) { - $script:html += @" + } + if ($mgPolicyPolicySetScopedCount -gt 0) { + $script:html += @"
    $($mgPolicyPolicySetScopedCount)
    "@ - } -} -} -else { -$script:html += @" + } + } + } + else { + $script:html += @"
    "@ -} -$script:html += @" + } + $script:html += @"
    "@ -if ($mgIdRoleAssignmentCount -gt 0) { -$script:html += @" + if ($mgIdRoleAssignmentCount -gt 0) { + $script:html += @"
    $($mgIdRoleAssignmentCount)
    "@ -} -else { -$script:html += @" + } + else { + $script:html += @"
    "@ -} -$script:html += @" + } + $script:html += @"
    @@ -20813,7 +20868,7 @@ if ($htParameters.HierarchyMapOnly -eq $false) { "@ - if (-not $LargeTenant) { + if ((-not $LargeTenant) -or (-not $NoScopeInsights)) { $html += @"
    @@ -20852,7 +20907,7 @@ if ($htParameters.HierarchyMapOnly -eq $false) { $endAzGovVizHTML = get-date $AzGovVizHTMLDuration = (NEW-TIMESPAN -Start $startAzGovViz -End $endAzGovVizHTML).TotalMinutes $paramsUsed += "Creation duration: $AzGovVizHTMLDuration minutes " - if (-not $LargeTenant) { + if ((-not $LargeTenant) -or (-not $NoScopeInsights)) { $html += @"
    @@ -21051,125 +21106,156 @@ if (-not $NoJsonExport) { $MgIds = $newTable | select-object -property level, MgId, MgName, mgParentId, mgParentName | sort-object -property level, MgId -unique $grpScopePolicyDefinitionsCustom = (($htCacheDefinitions).policy.values).Where( { $_.Type -eq "Custom" }) | Group-Object ScopeMgSub - $grpMgScopePolicyDefinitionsCustom = $grpScopePolicyDefinitionsCustom.where( { $_.Name -eq "Mg" }).Group | Group-Object ScopeId - $grpSubScopePolicyDefinitionsCustom = $grpScopePolicyDefinitionsCustom.where( { $_.Name -eq "Sub" }).Group | Group-Object ScopeId + $grpMgScopePolicyDefinitionsCustom = ($grpScopePolicyDefinitionsCustom.where( { $_.Name -eq "Mg" }).Group | sort-object -Property PolicyDefinitionId | Group-Object ScopeId) + $grpSubScopePolicyDefinitionsCustom = ($grpScopePolicyDefinitionsCustom.where( { $_.Name -eq "Sub" }).Group | sort-object -Property PolicyDefinitionId | Group-Object ScopeId) $grpScopePolicySetDefinitionsCustom = (($htCacheDefinitions).policySet.values).Where( { $_.Type -eq "Custom" }) | Group-Object ScopeMgSub - $grpMgScopePolicySetDefinitionsCustom = $grpScopePolicySetDefinitionsCustom.where( { $_.Name -eq "Mg" }).Group | Group-Object ScopeId - $grpSubScopePolicySetDefinitionsCustom = $grpScopePolicySetDefinitionsCustom.where( { $_.Name -eq "Sub" }).Group | Group-Object ScopeId + $grpMgScopePolicySetDefinitionsCustom = $grpScopePolicySetDefinitionsCustom.where( { $_.Name -eq "Mg" }).Group | sort-object -Property PolicyDefinitionId | Group-Object ScopeId + $grpSubScopePolicySetDefinitionsCustom = $grpScopePolicySetDefinitionsCustom.where( { $_.Name -eq "Sub" }).Group | sort-object -Property PolicyDefinitionId | Group-Object ScopeId $grpScopePolicyAssignments = ($htCacheAssignmentsPolicy).values | Group-Object -Property AssignmentScopeMgSubRg - $grpMgScopePolicyAssignments = $grpScopePolicyAssignments.where( { $_.Name -eq "Mg" }).Group | Group-Object -Property AssignmentScopeId - $grpSubScopePolicyAssignments = $grpScopePolicyAssignments.where( { $_.Name -eq "Sub" }).Group | Group-Object -Property AssignmentScopeId + $grpMgScopePolicyAssignments = $grpScopePolicyAssignments.where( { $_.Name -eq "Mg" }).Group | sort-object @{Expression = { $_.Assignment.Id } } | Group-Object -Property AssignmentScopeId + $grpSubScopePolicyAssignments = $grpScopePolicyAssignments.where( { $_.Name -eq "Sub" }).Group | sort-object @{Expression = { $_.Assignment.Id } } | Group-Object -Property AssignmentScopeId $grpScopeRoleAssignments = ($htCacheAssignments).role.values | Group-Object -Property AssignmentScopeTenMgSubRgRes $grpTenantScopeRoleAssignments = $grpScopeRoleAssignments.where( { $_.Name -eq "Tenant" }).Group | Group-Object -Property AssignmentScopeId - $grpMgScopeRoleAssignments = $grpScopeRoleAssignments.where( { $_.Name -eq "Mg" }).Group | Group-Object -Property AssignmentScopeId - $grpSubScopeRoleAssignments = $grpScopeRoleAssignments.where( { $_.Name -eq "Sub" }).Group | Group-Object -Property AssignmentScopeId + $grpMgScopeRoleAssignments = $grpScopeRoleAssignments.where( { $_.Name -eq "Mg" }).Group | sort-object @{Expression = { $_.Assignment.RoleAssignmentId } } | Group-Object -Property AssignmentScopeId + $grpSubScopeRoleAssignments = $grpScopeRoleAssignments.where( { $_.Name -eq "Sub" }).Group | sort-object @{Expression = { $_.Assignment.RoleAssignmentId } } | Group-Object -Property AssignmentScopeId - $bluePrintsAssignmentsAtScope = ($htCacheAssignments).blueprint.keys - $bluePrintDefinitions = ($htCacheDefinitions).blueprint.Keys - $subscriptions = ($newTable.Where( { -not [string]::IsNullOrEmpty($_.subscriptionId) })) | Sort-Object -Property subscriptionId -Unique + $bluePrintsAssignmentsAtScope = ($htCacheAssignments).blueprint.keys | Sort-Object + $bluePrintDefinitions = ($htCacheDefinitions).blueprint.Keys | Sort-Object + $subscriptions = ($newTable.Where( { -not [string]::IsNullOrEmpty($_.subscriptionId) })) | Select-Object mgId, Subscription* | Sort-Object -Property subscriptionId -Unique foreach ($mg in $MgIds) { - $htJSON.ManagementGroups.$($mg.MgId) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).MgId = $mg.MgId - $htJSON.ManagementGroups.$($mg.MgId).MgName = $mg.MgName - $htJSON.ManagementGroups.$($mg.MgId).mgParentId = $mg.mgParentId - $htJSON.ManagementGroups.$($mg.MgId).mgParentName = $mg.mgParentName - $htJSON.ManagementGroups.$($mg.MgId).level = $mg.level - $htJSON.ManagementGroups.$($mg.MgId).PolicyDefinitionsCustom = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).PolicySetDefinitionsCustom = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Blueprints = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).PolicyAssignments = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).RoleAssignments = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).MgId = $mg.MgId + $htJSON.ManagementGroups.($mg.MgId).MgName = $mg.MgName + $htJSON.ManagementGroups.($mg.MgId).mgParentId = $mg.mgParentId + $htJSON.ManagementGroups.($mg.MgId).mgParentName = $mg.mgParentName + $htJSON.ManagementGroups.($mg.MgId).level = $mg.level + $htJSON.ManagementGroups.($mg.MgId).PolicyDefinitionsCustom = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).PolicySetDefinitionsCustom = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).BlueprintDefinitions = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).PolicyAssignments = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).RoleAssignments = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).DiagnosticSettings = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions = [ordered]@{} - foreach ($PolDef in ($grpMgScopePolicyDefinitionsCustom.Where( { $_.Name -eq $mg.MgId })).group | sort-object -Property PolicyDefinitionId) { - $htJSON.ManagementGroups.$($mg.MgId).PolicyDefinitionsCustom.$($PolDef.Id) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).PolicyDefinitionsCustom.$($PolDef.Id) = $PolDef.Json + foreach ($PolDef in (($grpMgScopePolicyDefinitionsCustom).Where( { $_.Name -eq $mg.MgId })).group) { + $htJSON.ManagementGroups.($mg.MgId).PolicyDefinitionsCustom.($PolDef.Id) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).PolicyDefinitionsCustom.($PolDef.Id) = $PolDef.Json } - foreach ($PolSetDef in ($grpMgScopePolicySetDefinitionsCustom.Where( { $_.Name -eq $mg.MgId })).group | sort-object -Property PolicyDefinitionId) { - $htJSON.ManagementGroups.$($mg.MgId).PolicySetDefinitionsCustom.$($PolSetDef.Id) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).PolicySetDefinitionsCustom.$($PolSetDef.Id) = $PolSetDef.Json + foreach ($PolSetDef in (($grpMgScopePolicySetDefinitionsCustom).Where( { $_.Name -eq $mg.MgId })).group) { + $htJSON.ManagementGroups.($mg.MgId).PolicySetDefinitionsCustom.($PolSetDef.Id) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).PolicySetDefinitionsCustom.($PolSetDef.Id) = $PolSetDef.Json } - foreach ($PolAssignment in $grpMgScopePolicyAssignments.Where( { $_.Name -eq $mg.MgId }).group| sort-object @{Expression = { $_.Assignment.Id }}) { - $htJSON.ManagementGroups.$($mg.MgId).PolicyAssignments.$($PolAssignment.Assignment.id) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).PolicyAssignments.$($PolAssignment.Assignment.id) = $PolAssignment.Assignment + foreach ($PolAssignment in ($grpMgScopePolicyAssignments).Where( { $_.Name -eq $mg.MgId }).group) { + $htJSON.ManagementGroups.($mg.MgId).PolicyAssignments.($PolAssignment.Assignment.id) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).PolicyAssignments.($PolAssignment.Assignment.id) = $PolAssignment.Assignment } - - foreach ($RoleAssignment in ($grpMgScopeRoleAssignments).Where( { $_.Name -eq $mg.MgId }).group | sort-object @{Expression = { $_.Assignment.RoleAssignmentId }}) { - $htJSON.ManagementGroups.$($mg.MgId).RoleAssignments.$($RoleAssignment.Assignment.RoleAssignmentId) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).RoleAssignments.$($RoleAssignment.Assignment.RoleAssignmentId) = $RoleAssignment.Assignment + + foreach ($RoleAssignment in ($grpMgScopeRoleAssignments).Where( { $_.Name -eq $mg.MgId }).group) { + $htJSON.ManagementGroups.($mg.MgId).RoleAssignments.($RoleAssignment.Assignment.RoleAssignmentId) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).RoleAssignments.($RoleAssignment.Assignment.RoleAssignmentId) = $RoleAssignment.Assignment + } + + foreach ($BlueprintDefinition in ($bluePrintDefinitions).Where( { $_ -like "/providers/Microsoft.Management/managementGroups/$($mg.MgId)/*" })) { + $htJSON.ManagementGroups.($mg.MgId).BlueprintDefinitions.($BlueprintDefinition) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).BlueprintDefinitions.($BlueprintDefinition) = $BlueprintDefinition + } + + if (($htDiagnosticSettingsMgSub).mg.($mg.MgId)){ + foreach ($entry in ($htDiagnosticSettingsMgSub).mg.($mg.MgId).keys | Sort-Object) { + $htJSON.ManagementGroups.($mg.MgId).DiagnosticSettings.($entry) = [ordered]@{} + foreach ($diagset in ($htDiagnosticSettingsMgSub).mg.($mg.MgId).$entry.keys | Sort-Object) { + $htJSON.ManagementGroups.($mg.MgId).DiagnosticSettings.($entry).Name = (($htDiagnosticSettingsMgSub).mg.($mg.MgId).$entry.$diagset.DiagnosticSettingName) + $htJSON.ManagementGroups.($mg.MgId).DiagnosticSettings.($entry).Type = (($htDiagnosticSettingsMgSub).mg.($mg.MgId).$entry.$diagset.DiagnosticTargetType) + $htJSON.ManagementGroups.($mg.MgId).DiagnosticSettings.($entry).TargetId = (($htDiagnosticSettingsMgSub).mg.($mg.MgId).$entry.$diagset.DiagnosticTargetId) + $htJSON.ManagementGroups.($mg.MgId).DiagnosticSettings.($entry).Settings = (($htDiagnosticSettingsMgSub).mg.($mg.MgId).$entry.$diagset.DiagnosticCategories) + } + } } foreach ($subscription in $subscriptions) { if ($subscription.MgId -eq $mg.MgId) { - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).SubscriptionName = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).SubscriptionQuotaId = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).SubscriptionState = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).SubscriptionTags = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).SubscriptionName = $subscription.Subscription - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).SubscriptionQuotaId = $subscription.SubscriptionQuotaId - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).SubscriptionState = $subscription.SubscriptionState + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).SubscriptionName = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).SubscriptionQuotaId = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).SubscriptionState = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).SubscriptionTags = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).SubscriptionName = $subscription.Subscription + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).SubscriptionQuotaId = $subscription.SubscriptionQuotaId + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).SubscriptionState = $subscription.SubscriptionState if ($htSubscriptionTags.($subscription.SubscriptionId)) { - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).SubscriptionTags = $htSubscriptionTags.($subscription.SubscriptionId).getEnumerator() | Sort-Object Key - } - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicyDefinitionsCustom = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicySetDefinitionsCustom = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).BlueprintDefinitions = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicyAssignments = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).RoleAssignments = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).BlueprintAssignments = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).SubscriptionTags = $htSubscriptionTags.($subscription.SubscriptionId).getEnumerator() | Sort-Object Key -CaseSensitive + } + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicyDefinitionsCustom = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicySetDefinitionsCustom = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).BlueprintDefinitions = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicyAssignments = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).RoleAssignments = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).BlueprintAssignments = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).DiagnosticSettings = [ordered]@{} - foreach ($PolDef in ($grpSubScopePolicyDefinitionsCustom.Where( { $_.Name -eq $subscription.subscriptionId })).group | sort-object -Property PolicyDefinitionId) { - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicyDefinitionsCustom.$($PolDef.Id) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicyDefinitionsCustom.$($PolDef.Id) = $PolDef.Json + foreach ($PolDef in (($grpSubScopePolicyDefinitionsCustom).Where( { $_.Name -eq $subscription.subscriptionId })).group) { + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicyDefinitionsCustom.($PolDef.Id) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicyDefinitionsCustom.($PolDef.Id) = $PolDef.Json + } + + foreach ($PolSetDef in (($grpSubScopePolicySetDefinitionsCustom).Where( { $_.Name -eq $subscription.subscriptionId })).group) { + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicySetDefinitionsCustom.($PolSetDef.Id) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicySetDefinitionsCustom.($PolSetDef.Id) = $PolSetDef.Json } - foreach ($PolSetDef in ($grpSubScopePolicySetDefinitionsCustom.Where( { $_.Name -eq $subscription.subscriptionId })).group | sort-object -Property PolicyDefinitionId) { - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicySetDefinitionsCustom.$($PolSetDef.Id) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicySetDefinitionsCustom.$($PolSetDef.Id) = $PolSetDef.Json + foreach ($PolAssignment in ($grpSubScopePolicyAssignments).Where( { $_.Name -eq $subscription.subscriptionId }).group) { + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicyAssignments.($PolAssignment.Assignment.id) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).PolicyAssignments.($PolAssignment.Assignment.id) = $PolAssignment.Assignment } - foreach ($PolAssignment in $grpSubScopePolicyAssignments.Where( { $_.Name -eq $subscription.subscriptionId }).group| sort-object @{Expression = { $_.Assignment.Id }}) { - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicyAssignments.$($PolAssignment.Assignment.id) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).PolicyAssignments.$($PolAssignment.Assignment.id) = $PolAssignment.Assignment + foreach ($RoleAssignment in ($grpSubScopeRoleAssignments).Where( { $_.Name -eq $subscription.subscriptionId }).group) { + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).RoleAssignments.($RoleAssignment.Assignment.RoleAssignmentId) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).RoleAssignments.($RoleAssignment.Assignment.RoleAssignmentId) = $RoleAssignment.Assignment } - foreach ($RoleAssignment in ($grpSubScopeRoleAssignments).Where( { $_.Name -eq $subscription.subscriptionId }).group | sort-object @{Expression = { $_.Assignment.RoleAssignmentId }}) { - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).RoleAssignments.$($RoleAssignment.Assignment.RoleAssignmentId) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).RoleAssignments.$($RoleAssignment.Assignment.RoleAssignmentId) = $RoleAssignment.Assignment + foreach ($BlueprintDefinition in ($bluePrintDefinitions).Where( { $_ -like "/subscriptions/$($subscription.subscriptionId)/*" })) { + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).BlueprintDefinitions.($BlueprintDefinition) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).BlueprintDefinitions.($BlueprintDefinition) = $BlueprintDefinition } - foreach ($BlueprintDefinition in $bluePrintDefinitions.Where( { $_ -like "/subscriptions/$($subscription.subscriptionId)/*" })) { - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).BlueprintDefinitions.$($BlueprintDefinition) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).BlueprintDefinitions.$($BlueprintDefinition) = $BlueprintDefinition + foreach ($BlueprintsAssignment in ($blueprintsAssignmentsAtScope).Where( { $_ -like "/subscriptions/$($subscription.subscriptionId)/*" })) { + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).BlueprintAssignments.($BlueprintsAssignment) = [ordered]@{} + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).BlueprintAssignments.($BlueprintsAssignment) = $BlueprintsAssignment } - foreach ($BlueprintsAssignment in $blueprintsAssignmentsAtScope.Where( { $_ -like "/subscriptions/$($subscription.subscriptionId)/*" })) { - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).BlueprintAssignments.$($BlueprintsAssignment) = [ordered]@{} - $htJSON.ManagementGroups.$($mg.MgId).Subscriptions.$($subscription.subscriptionId).BlueprintAssignments.$($BlueprintsAssignment) = $BlueprintsAssignment + if (($htDiagnosticSettingsMgSub).sub.($subscription.subscriptionId)){ + foreach ($entry in ($htDiagnosticSettingsMgSub).sub.($subscription.subscriptionId).keys | Sort-Object) { + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).DiagnosticSettings.($entry) = [ordered]@{} + foreach ($diagset in ($htDiagnosticSettingsMgSub).sub.($subscription.subscriptionId).$entry.keys | Sort-Object) { + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).DiagnosticSettings.($entry).Name = (($htDiagnosticSettingsMgSub).sub.($subscription.subscriptionId).$entry.$diagset.DiagnosticSettingName) + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).DiagnosticSettings.($entry).Type = (($htDiagnosticSettingsMgSub).sub.($subscription.subscriptionId).$entry.$diagset.DiagnosticTargetType) + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).DiagnosticSettings.($entry).TargetId = (($htDiagnosticSettingsMgSub).sub.($subscription.subscriptionId).$entry.$diagset.DiagnosticTargetId) + $htJSON.ManagementGroups.($mg.MgId).Subscriptions.($subscription.subscriptionId).DiagnosticSettings.($entry).Settings = (($htDiagnosticSettingsMgSub).sub.($subscription.subscriptionId).$entry.$diagset.DiagnosticCategories) + } + } } } } } - if ($AzureDevOpsWikiAsCode){ - $JSONPath = "JSON" + if ($AzureDevOpsWikiAsCode) { + $JSONPath = "JSON_$($ManagementGroupId)" if (Test-Path -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($JSONPath)") { Write-Host " Cleaning old state (Pipeline only)" Remove-Item -Recurse -Force "$($outputPath)$($DirectorySeparatorChar)$($JSONPath)" } } - else{ - $JSONPath = "JSON_$($fileTimestamp)" - Write-Host " Creating new state (JSON_$($fileTimestamp) (local only))" + else { + $JSONPath = "JSON_$($ManagementGroupId)_$($fileTimestamp)" + Write-Host " Creating new state ($($JSONPath)) (local only))" } $null = new-item -Name $JSONPath -ItemType directory -path $outputPath $null = new-item -Name "$($JSONPath)$($DirectorySeparatorChar)Definitions" -ItemType directory -path $outputPath @@ -21191,7 +21277,6 @@ if (-not $NoJsonExport) { $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($pathRoleDefinitionCustom)$($DirectorySeparatorChar)$(($htCacheDefinitions).role.($roleDefinition).Name -replace ":" -replace "/" -replace "\\" -replace "<" -replace ">" -replace "\*" -replace "\?" -replace "|" -replace '"' ) ($(($htCacheDefinitions).role.($roleDefinition).Id).json" -Encoding utf8 } foreach ($roleDefinition in ($htCacheDefinitions).role.Keys.Where( { -not ($htCacheDefinitions).role.($_).IsCustom })) { - #$htJSON.RoleDefinitions.($roleDefinition) = ($htCacheDefinitions).role.($roleDefinition).Json $jsonConverted = ($htCacheDefinitions).role.($roleDefinition).Json | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($pathRoleDefinitionBuiltIn)$($DirectorySeparatorChar)$(($htCacheDefinitions).role.($roleDefinition).Name ) ($(($htCacheDefinitions).role.($roleDefinition).Id).json" -Encoding utf8 } @@ -21242,59 +21327,59 @@ if (-not $NoJsonExport) { $json = $json."ManagementGroups".($getMg.Name) = [ordered]@{} foreach ($mgCap in $htJSON.ManagementGroups.($getMg.Name).keys) { $json.$mgCap = $htJSON.ManagementGroups.($getMg.Name).$mgCap - if ($mgCap -eq "PolicyDefinitionsCustom"){ - foreach ($pdc in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys){ + if ($mgCap -eq "PolicyDefinitionsCustom") { + foreach ($pdc in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys) { $jsonConverted = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($pdc) | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($prntx)$($DirectorySeparatorChar)$($mgCap)_$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($pdc).name).json" -Encoding utf8 $path = "$($JSONPath)$($DirectorySeparatorChar)Definitions$($DirectorySeparatorChar)PolicyDefinitions$($DirectorySeparatorChar)Custom$($DirectorySeparatorChar)Mg$($DirectorySeparatorChar)$($getMg.Name) ($($getMg.properties.displayName))" if (-not (Test-Path -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)")) { $null = new-item -Name $path -ItemType directory -path $outputPath } - if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($pdc).properties.displayName)){ + if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($pdc).properties.displayName)) { $displayName = "noDisplayNameGiven" } - else{ + else { $displayName = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($pdc).properties.displayName -replace ":" -replace "/" -replace "\\" -replace "<" -replace ">" -replace "\*" -replace "\?" -replace "|" -replace '"' } $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)$($DirectorySeparatorChar)$($displayName) ($($htJSON.ManagementGroups.($getMg.Name).($mgCap).($pdc).name)).json" -Encoding utf8 } } - if ($mgCap -eq "PolicySetDefinitionsCustom"){ - foreach ($psdc in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys){ + if ($mgCap -eq "PolicySetDefinitionsCustom") { + foreach ($psdc in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys) { $jsonConverted = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($psdc) | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($prntx)$($DirectorySeparatorChar)$($mgCap)_$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($psdc).name).json" -Encoding utf8 $path = "$($JSONPath)$($DirectorySeparatorChar)Definitions$($DirectorySeparatorChar)PolicySetDefinitions$($DirectorySeparatorChar)Custom$($DirectorySeparatorChar)Mg$($DirectorySeparatorChar)$($getMg.Name) ($($getMg.properties.displayName))" if (-not (Test-Path -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)")) { $null = new-item -Name $path -ItemType directory -path $outputPath } - if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($psdc).properties.displayName)){ + if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($psdc).properties.displayName)) { $displayName = "noDisplayNameGiven" } - else{ + else { $displayName = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($psdc).properties.displayName -replace ":" -replace "/" -replace "\\" -replace "<" -replace ">" -replace "\*" -replace "\?" -replace "|" -replace '"' } $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)$($DirectorySeparatorChar)$($displayName) ($($htJSON.ManagementGroups.($getMg.Name).($mgCap).($psdc).name)).json" -Encoding utf8 } } - if ($mgCap -eq "PolicyAssignments"){ - foreach ($pa in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys){ + if ($mgCap -eq "PolicyAssignments") { + foreach ($pa in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys) { $jsonConverted = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($pa) | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($prntx)$($DirectorySeparatorChar)$($mgCap)_$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($pa).name).json" -Encoding utf8 $path = "$($JSONPath)$($DirectorySeparatorChar)Assignments$($DirectorySeparatorChar)$($mgCap)$($DirectorySeparatorChar)Mg$($DirectorySeparatorChar)$($getMg.Name) ($($getMg.properties.displayName))" if (-not (Test-Path -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)")) { $null = new-item -Name $path -ItemType directory -path $outputPath } - if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($pa).properties.displayName)){ + if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($pa).properties.displayName)) { $displayName = "noDisplayNameGiven" } - else{ + else { $displayName = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($pa).properties.displayName -replace ":" -replace "/" -replace "\\" -replace "<" -replace ">" -replace "\*" -replace "\?" -replace "|" -replace '"' } $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)$($DirectorySeparatorChar)$($displayName) ($($htJSON.ManagementGroups.($getMg.Name).($mgCap).($pa).name)).json" -Encoding utf8 } } - if ($mgCap -eq "RoleAssignments"){ - foreach ($ra in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys){ + if ($mgCap -eq "RoleAssignments") { + foreach ($ra in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys) { $jsonConverted = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($ra) | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($prntx)$($DirectorySeparatorChar)$($mgCap)_$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($ra).RoleAssignmentId -replace ".*/").json" -Encoding utf8 $path = "$($JSONPath)$($DirectorySeparatorChar)Assignments$($DirectorySeparatorChar)$($mgCap)$($DirectorySeparatorChar)Mg$($DirectorySeparatorChar)$($getMg.Name) ($($getMg.properties.displayName))" @@ -21305,64 +21390,64 @@ if (-not $NoJsonExport) { } } - if ($mgCap -eq "Subscriptions"){ - foreach ($sub in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys){ + if ($mgCap -eq "Subscriptions") { + foreach ($sub in $htJSON.ManagementGroups.($getMg.Name).($mgCap).Keys) { $subFolderName = "$($prntx)$($DirectorySeparatorChar)$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).SubscriptionName) ($($sub))" $null = new-item -Name $subFolderName -ItemType directory -path $outputPath - foreach ($subCap in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).Keys){ - if ($subCap -eq "PolicyDefinitionsCustom"){ - foreach ($pdc in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).Keys){ + foreach ($subCap in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).Keys) { + if ($subCap -eq "PolicyDefinitionsCustom") { + foreach ($pdc in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).Keys) { $jsonConverted = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pdc) | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($subFolderName)$($DirectorySeparatorChar)$($subCap)_$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pdc).name).json" -Encoding utf8 $path = "$($JSONPath)$($DirectorySeparatorChar)Definitions$($DirectorySeparatorChar)PolicyDefinitions$($DirectorySeparatorChar)Custom$($DirectorySeparatorChar)Sub$($DirectorySeparatorChar)$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).SubscriptionName) ($($sub))" if (-not (Test-Path -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)")) { $null = new-item -Name $path -ItemType directory -path $outputPath } - if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pdc).properties.displayName)){ + if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pdc).properties.displayName)) { $displayName = "noDisplayNameGiven" } - else{ + else { $displayName = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pdc).properties.displayName -replace ":" -replace "/" -replace "\\" -replace "<" -replace ">" -replace "\*" -replace "\?" -replace "|" -replace '"' } $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)$($DirectorySeparatorChar)$($displayName) ($($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pdc).name)).json" -Encoding utf8 } } - if ($subCap -eq "PolicySetDefinitionsCustom"){ - foreach ($psdc in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).Keys){ + if ($subCap -eq "PolicySetDefinitionsCustom") { + foreach ($psdc in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).Keys) { $jsonConverted = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($psdc) | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($subFolderName)$($DirectorySeparatorChar)$($subCap)_$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($psdc).name).json" -Encoding utf8 $path = "$($JSONPath)$($DirectorySeparatorChar)Definitions$($DirectorySeparatorChar)PolicySetDefinitions$($DirectorySeparatorChar)Custom$($DirectorySeparatorChar)Sub$($DirectorySeparatorChar)$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).SubscriptionName) ($($sub))" if (-not (Test-Path -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)")) { $null = new-item -Name $path -ItemType directory -path $outputPath } - if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($psdc).properties.displayName)){ + if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($psdc).properties.displayName)) { $displayName = "noDisplayNameGiven" } - else{ + else { $displayName = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($psdc).properties.displayName -replace ":" -replace "/" -replace "\\" -replace "<" -replace ">" -replace "\*" -replace "\?" -replace "|" -replace '"' } $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)$($DirectorySeparatorChar)$($displayName) ($($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($psdc).name)).json" -Encoding utf8 } } - if ($subCap -eq "PolicyAssignments"){ - foreach ($pa in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).Keys){ + if ($subCap -eq "PolicyAssignments") { + foreach ($pa in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).Keys) { $jsonConverted = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pa) | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($subFolderName)$($DirectorySeparatorChar)$($subCap)_$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pa).name).json" -Encoding utf8 $path = "$($JSONPath)$($DirectorySeparatorChar)Assignments$($DirectorySeparatorChar)$($subCap)$($DirectorySeparatorChar)Sub$($DirectorySeparatorChar)$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).SubscriptionName) ($($sub))" if (-not (Test-Path -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)")) { $null = new-item -Name $path -ItemType directory -path $outputPath } - if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pa).properties.displayName)){ + if ([string]::IsNullOrEmpty($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pa).properties.displayName)) { $displayName = "noDisplayNameGiven" } - else{ + else { $displayName = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pa).properties.displayName -replace ":" -replace "/" -replace "\\" -replace "<" -replace ">" -replace "\*" -replace "\?" -replace "|" -replace '"' } $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($path)$($DirectorySeparatorChar)$($displayName) ($($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($pa).name)).json" -Encoding utf8 } } - if ($subCap -eq "RoleAssignments"){ - foreach ($ra in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).Keys){ + if ($subCap -eq "RoleAssignments") { + foreach ($ra in $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).Keys) { $jsonConverted = $htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($ra) | ConvertTo-Json -Depth 99 $jsonConverted | Set-Content -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($subFolderName)$($DirectorySeparatorChar)$($subCap)_$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).($subCap).($ra).RoleAssignmentId -replace ".*/").json" -Encoding utf8 $path = "$($JSONPath)$($DirectorySeparatorChar)Assignments$($DirectorySeparatorChar)$($subCap)$($DirectorySeparatorChar)Sub$($DirectorySeparatorChar)$($htJSON.ManagementGroups.($getMg.Name).($mgCap).($sub).SubscriptionName) ($($sub))" @@ -21393,7 +21478,7 @@ if (-not $NoJsonExport) { $htTree."Tenant" = [ordered] @{} $htTree.Tenant.TenantId = $checkContext.Tenant.Id $htTree.Tenant.RoleAssignments = [ordered]@{} - foreach ($RoleAssignment in ($grpTenantScopeRoleAssignments).Group | sort-object @{Expression = { $_.Assignment.RoleAssignmentId }}) { + foreach ($RoleAssignment in ($grpTenantScopeRoleAssignments).Group | sort-object @{Expression = { $_.Assignment.RoleAssignmentId } }) { $htTree.Tenant.RoleAssignments.$($RoleAssignment.Assignment.RoleAssignmentId) = [ordered]@{} $htTree.Tenant.RoleAssignments.$($RoleAssignment.Assignment.RoleAssignmentId) = $RoleAssignment.Assignment @@ -21456,4 +21541,4 @@ $Error | Out-host if ($DoTranscript) { Stop-Transcript -} +} \ No newline at end of file
$($blueprintAssignment.BlueprintName)
Subscription SubscriptionIdPath Diagnostic setting Target TargetId
$($entry.ScopeName) $($entry.ScopeId) $($entry.ScopeMgPath) $($entry.DiagnosticSettingName) $($entry.DiagnosticTargetType) $($entry.DiagnosticTargetId)
Diagnostics capable (logs) Policy Id Policy DisplayNameRole DefinitionsRole definitions Target Log Categories not covered by PolicyPolicy AssignmentsPolicy assignments Policy used in PolicySetPolicySet AssignmentsPolicySet assignments
$($mgApproachingLimitPolicyAssignments.MgName) $($mgApproachingLimitPolicyAssignments.MgId)$(($mgApproachingLimitPolicyAssignments.PolicyAndPolicySetAssigmentAtScopeCount/$LimitPOLICYPolicyAssignmentsManagementGroup).tostring("P")) ($($mgApproachingLimitPolicyAssignments.PolicyAndPolicySetAssigmentAtScopeCount)/$($LimitPOLICYPolicyAssignmentsManagementGroup)) ($($mgApproachingLimitPolicyAssignments.PolicyAssigmentAtScopeCount) Policy Assignments, $($mgApproachingLimitPolicyAssignments.PolicySetAssigmentAtScopeCount) PolicySet Assignments)$(($mgApproachingLimitPolicyAssignments.PolicyAndPolicySetAssigmentAtScopeCount/$LimitPOLICYPolicyAssignmentsManagementGroup).tostring("P")) ($($mgApproachingLimitPolicyAssignments.PolicyAndPolicySetAssigmentAtScopeCount)/$($LimitPOLICYPolicyAssignmentsManagementGroup)) ($($mgApproachingLimitPolicyAssignments.PolicyAssigmentAtScopeCount) Policy assignments, $($mgApproachingLimitPolicyAssignments.PolicySetAssigmentAtScopeCount) PolicySet assignments)
$($subscriptionApproachingLimitPolicyAssignments.subscription) $($subscriptionApproachingLimitPolicyAssignments.subscriptionId)$(($subscriptionApproachingLimitPolicyAssignments.PolicyAndPolicySetAssigmentAtScopeCount/$subscriptionApproachingLimitPolicyAssignments.PolicyAssigmentLimit).tostring("P")) ($($subscriptionApproachingLimitPolicyAssignments.PolicyAndPolicySetAssigmentAtScopeCount)/$($subscriptionApproachingLimitPolicyAssignments.PolicyAssigmentLimit)) ($($subscriptionApproachingLimitPolicyAssignments.PolicyAssigmentAtScopeCount) Policy Assignments, $($subscriptionApproachingLimitPolicyAssignments.PolicySetAssigmentAtScopeCount) PolicySet Assignments)$(($subscriptionApproachingLimitPolicyAssignments.PolicyAndPolicySetAssigmentAtScopeCount/$subscriptionApproachingLimitPolicyAssignments.PolicyAssigmentLimit).tostring("P")) ($($subscriptionApproachingLimitPolicyAssignments.PolicyAndPolicySetAssigmentAtScopeCount)/$($subscriptionApproachingLimitPolicyAssignments.PolicyAssigmentLimit)) ($($subscriptionApproachingLimitPolicyAssignments.PolicyAssigmentAtScopeCount) Policy assignments, $($subscriptionApproachingLimitPolicyAssignments.PolicySetAssigmentAtScopeCount) PolicySet assignments)
Usage Usage info Policy assigment detailsRole AssignmentsRole assignments
DisplayName SP ObjectId OrganizationIdRole Assignments$($abbr)Role assignments$($abbr)
PolicyId Category EffectRole DefinitionsUnique AssignmentsRole definitionsUnique assignments Used in PolicySets Created/Updated CreatedOnPolicySet DisplayName PolicySetId CategoryUnique AssignmentsUnique assignments Policies used in PolicySet Created/Updated CreatedOnCategory Effect EnforcementNonCompliance Message$($policyAssignment.PolicyCategory) $($policyAssignment.Effect) $($policyAssignment.PolicyAssignmentEnforcementMode)$($policyAssignment.PolicyAssignmentNonComplianceMessages)