Skip to content

Commit aa67339

Browse files
committed
6.4.4
1 parent d777afa commit aa67339

File tree

9 files changed

+2803
-2825
lines changed

9 files changed

+2803
-2825
lines changed

README.md

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -87,24 +87,14 @@ As an alternative, you can use the [Azure Governance Visualizer accelerator](htt
8787

8888
## Release history
8989

90-
__Changes__ (2024-Mar-19 / 6.4.3 Minor)
90+
__Changes__ (2024-Apr-17 / 6.4.4 Minor)
9191

92-
* Support for `-DoAzureConsumptionPreviousMonth` - Azure Consumption data should be collected/reported for the previous month
93-
94-
__Changes__ (2024-Mar-14 / 6.4.2 Minor)
95-
96-
* optimize objects handling / best practices
97-
98-
__Changes__ (2024-Feb-06 / 6.4.0 Minor)
99-
100-
* change PowerShell parallel handling / batches
101-
* add addition JSON outputs 'definitions_tracking' and 'assignments_tracking' (JSON filenames have no displayName included; GUIDs only)
102-
* update ARM API-version for RBAC Role definitions. Using `2022-05-01-preview` instead of `2018-11-01-preview` consequently
103-
* fix *_roleDefinitions.csv - description partially missing
104-
* optimize array handling / best practices
105-
* optimize getting private endpoint capable resource types / in case resource provider 'microsoft.network' is not registered, try with next available subscription instead of throwing
106-
* use [AzAPICall](https://aka.ms/AzAPICall) PowerShell module version 1.2.0
107-
* documentation update - style guidance, links updates - kudos @ckittel
92+
* fix issue #230
93+
* use [AzAPICall](https://aka.ms/AzAPICall) PowerShell module version 1.2.1
94+
* update [API reference](#api-reference) Microsoft.Security/pricings use API version 2024-01-01 (previous 2018-06-01)
95+
* add 'Mutate' to `ValidPolicyEffects`
96+
* location related tasks - use only physical locations (exclude logical)
97+
* optimize collection of Role definitions that are used in Policy definitions
10898

10999
[Full release history](history.md)
110100

@@ -614,7 +604,7 @@ Azure Governance Visualizer polls the following APIs
614604
| ARM | 2022-05-01 | /subscriptions/`subscriptionId`/providers/Microsoft.Network/privateEndpoints |
615605
| ARM | 2022-05-01 | /subscriptions/`subscriptionId`/providers/Microsoft.Network/virtualNetworks |
616606
| ARM | 2020-06-01 | /subscriptions/`subscriptionId`/providers/Microsoft.Resources/tags/default |
617-
| ARM | 2018-06-01 | /subscriptions/`subscriptionId`/providers/Microsoft.Security/pricings |
607+
| ARM | 2024-01-01 | /subscriptions/`subscriptionId`/providers/Microsoft.Security/pricings |
618608
| ARM | 2020-01-01 | /subscriptions/`subscriptionId`/providers/Microsoft.Security/securescores |
619609
| ARM | 2020-01-01-preview | /subscriptions/`subscriptionId`/providers/Microsoft.Security/securityContacts |
620610
| ARM | 2019-10-01 | /subscriptions/`subscriptionId`/providers |

history.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@
44

55
### Azure Governance Visualizer version 6
66

7+
__Changes__ (2024-Apr-17 / 6.4.4 Minor)
8+
9+
* fix issue #230
10+
* use [AzAPICall](https://aka.ms/AzAPICall) PowerShell module version 1.2.1
11+
* update [API reference](#api-reference) Microsoft.Security/pricings use API version 2024-01-01 (previous 2018-06-01)
12+
* add 'Mutate' to `ValidPolicyEffects`
13+
* location related tasks - use only physical locations (exclude logical)
14+
* optimize collection of Role definitions that are used in Policy definitions
15+
716
__Changes__ (2024-Mar-19 / 6.4.3 Minor)
817

918
* Support for `-DoAzureConsumptionPreviousMonth` - Azure Consumption data should be collected/reported for the previous month

pwsh/AzGovVizParallel.ps1

Lines changed: 2681 additions & 2692 deletions
Large diffs are not rendered by default.

pwsh/dev/devAzGovVizParallel.ps1

Lines changed: 8 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -365,14 +365,14 @@ Param
365365
$Product = 'AzGovViz',
366366

367367
[string]
368-
$ProductVersion = '6.4.3',
368+
$ProductVersion = '6.4.4',
369369

370370
[string]
371371
$GithubRepository = 'aka.ms/AzGovViz',
372372

373373
# <--- AzAPICall related parameters #consult the AzAPICall GitHub repository for details aka.ms/AzAPICall
374374
[string]
375-
$AzAPICallVersion = '1.2.0',
375+
$AzAPICallVersion = '1.2.1',
376376

377377
[switch]
378378
$DebugAzAPICall,
@@ -627,7 +627,7 @@ Param
627627
$MSTenantIds = @('2f4a9838-26b7-47ee-be60-ccc1fdec5953', '33e01921-4d64-4f8c-a055-5bdaffd5e33d'),
628628

629629
[array]
630-
$ValidPolicyEffects = @('append', 'audit', 'auditIfNotExists', 'deny', 'denyAction', 'deployIfNotExists', 'modify', 'manual', 'disabled', 'EnforceRegoPolicy', 'enforceSetting')
630+
$ValidPolicyEffects = @('append', 'audit', 'auditIfNotExists', 'deny', 'denyAction', 'deployIfNotExists', 'modify', 'manual', 'disabled', 'EnforceRegoPolicy', 'enforceSetting', 'Mutate')
631631
)
632632

633633
$Error.clear()
@@ -648,6 +648,7 @@ if ($ManagementGroupId -match ' ') {
648648
}
649649

650650
#region Functions
651+
. ".\$($ScriptPath)\functions\getPrivateEndpointCapableResourceTypes.ps1"
651652
. ".\$($ScriptPath)\functions\validateLeastPrivilegeForUser.ps1"
652653
. ".\$($ScriptPath)\functions\getPolicyRemediation.ps1"
653654
. ".\$($ScriptPath)\functions\getPolicyHash.ps1"
@@ -820,14 +821,14 @@ if (-not $ignoreARMLocation) {
820821
#EndRegion initAZAPICall
821822

822823
#region required AzAPICall version
823-
if (-not ([System.Version]"$($azapicallConf['htParameters'].azAPICallModuleVersion)" -ge [System.Version]'1.1.84')) {
824+
if (-not ([System.Version]"$($azapicallConf['htParameters'].azAPICallModuleVersion)" -ge [System.Version]'1.2.1')) {
824825
Write-Host ''
825826
Write-Host 'Azure Governance Visualizer version '$ProductVersion' - AzAPICall PowerShell module version check failed -> https://aka.ms/AzAPICall; https://www.powershellgallery.com/packages/AzAPICall'
826-
throw "This version of Azure Governance Visualizer '$ProductVersion' requires AzAPICall PowerShell module version '1.1.84' or greater"
827+
throw "This version of Azure Governance Visualizer '$ProductVersion' requires AzAPICall PowerShell module version '1.2.1' or greater"
827828
}
828829
else {
829830
Write-Host ''
830-
Write-Host "Azure Governance Visualizer version '$ProductVersion' - AzAPICall PowerShell module version requirement check succeeded: '1.1.84' or greater - current: '$($azapicallConf['htParameters'].azAPICallModuleVersion)' " -ForegroundColor Green
831+
Write-Host "Azure Governance Visualizer version '$ProductVersion' - AzAPICall PowerShell module version requirement check succeeded: '1.2.1' or greater - current: '$($azapicallConf['htParameters'].azAPICallModuleVersion)' " -ForegroundColor Green
831832
}
832833
#endregion required AzAPICall version
833834

@@ -1160,93 +1161,7 @@ if (-not $HierarchyMapOnly) {
11601161
Write-Host "Getting Tenant Resource Providers duration: $((New-TimeSpan -Start $startGetRPs -End $endGetRPs).TotalMinutes) minutes ($((New-TimeSpan -Start $startGetRPs -End $endGetRPs).TotalSeconds) seconds)"
11611162
#endregion Getting Tenant Resource Providers
11621163

1163-
#region Getting Available Private Endpoint Types
1164-
$startGetAvailablePrivateEndpointTypes = Get-Date
1165-
$privateEndpointAvailabilityCheckCompleted = $false
1166-
$subsToProcessForGettingPrivateEndpointTypes = [System.Collections.ArrayList]@()
1167-
$prioCounter = 0
1168-
foreach ($subscription in $subsToProcessInCustomDataCollection) {
1169-
$prioCounter++
1170-
if ($subscription.subscriptionId -eq $azAPICallConf['checkcontext'].Subscription.Id) {
1171-
$null = $subsToProcessForGettingPrivateEndpointTypes.Add([PSCustomObject]@{
1172-
subscriptionInfo = $subscription
1173-
prio = 0
1174-
})
1175-
}
1176-
else {
1177-
$null = $subsToProcessForGettingPrivateEndpointTypes.Add([PSCustomObject]@{
1178-
subscriptionInfo = $subscription
1179-
prio = $prioCounter
1180-
})
1181-
}
1182-
}
1183-
1184-
foreach ($subscription in $subsToProcessForGettingPrivateEndpointTypes | Sort-Object -Property prio) {
1185-
1186-
if ($privateEndpointAvailabilityCheckCompleted) {
1187-
continue
1188-
}
1189-
1190-
$subscriptionId = $subscription.subscriptionInfo.subscriptionId
1191-
$subscriptionName = $subscription.subscriptionInfo.subscriptionName
1192-
1193-
$currentTask = "Getting Locations for Subscription '$($subscriptionName)' ($($subscriptionId))"
1194-
Write-Host $currentTask
1195-
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/subscriptions/$($subscriptionId)/locations?api-version=2020-01-01"
1196-
$method = 'GET'
1197-
$getLocations = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask
1198-
Write-Host " Returned $($getLocations.Count) locations"
1199-
1200-
Write-Host "Getting 'Available Private Endpoint Types' for Subscription '$($subscriptionName)' ($($subscriptionId)) for $($getLocations.Count) locations"
1201-
1202-
$batchSize = [math]::ceiling($getLocations.Count / $ThrottleLimit)
1203-
Write-Host "Optimal batch size: $($batchSize)"
1204-
$counterBatch = [PSCustomObject] @{ Value = 0 }
1205-
$getLocationsBatch = ($getLocations) | Group-Object -Property { [math]::Floor($counterBatch.Value++ / $batchSize) }
1206-
Write-Host "Processing data in $($getLocationsBatch.Count) batches"
1207-
1208-
$getLocationsBatch | ForEach-Object -Parallel {
1209-
$subscriptionId = $using:subscriptionId
1210-
$azAPICallConf = $using:azAPICallConf
1211-
$htAvailablePrivateEndpointTypes = $using:htAvailablePrivateEndpointTypes
1212-
1213-
foreach ($location in $_.Group) {
1214-
$currentTask = "Getting 'Available Private Endpoint Types' for location $($location.name)"
1215-
#Write-Host $currentTask
1216-
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/subscriptions/$($subscriptionId)/providers/Microsoft.Network/locations/$($location.name)/availablePrivateEndpointTypes?api-version=2022-07-01"
1217-
$method = 'GET'
1218-
$availablePrivateEndpointTypes = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask -skipOnErrorCode 400, 409
1219-
Write-Host " Returned $($availablePrivateEndpointTypes.Count) 'Available Private Endpoint Types' for location $($location.name)"
1220-
foreach ($availablePrivateEndpointType in $availablePrivateEndpointTypes) {
1221-
if (-not $htAvailablePrivateEndpointTypes.(($availablePrivateEndpointType.resourceName).ToLower())) {
1222-
$script:htAvailablePrivateEndpointTypes.(($availablePrivateEndpointType.resourceName).ToLower()) = @{}
1223-
}
1224-
}
1225-
}
1226-
} -ThrottleLimit $ThrottleLimit
1227-
1228-
if ($htAvailablePrivateEndpointTypes.Keys.Count -gt 0) {
1229-
#Write-Host " Created ht for $($htAvailablePrivateEndpointTypes.Keys.Count) 'Available Private Endpoint Types'"
1230-
$privateEndpointAvailabilityCheckCompleted = $true
1231-
}
1232-
else {
1233-
Write-Host " $($htAvailablePrivateEndpointTypes.Keys.Count) 'Available Private Endpoint Types' - likely the Resource Provider 'Microsoft.Network' is not registered - trying next available subscription"
1234-
$privateEndpointAvailabilityCheckCompleted = $false
1235-
}
1236-
}
1237-
1238-
if ($htAvailablePrivateEndpointTypes.Keys.Count -gt 0) {
1239-
Write-Host " Created ht for $($htAvailablePrivateEndpointTypes.Keys.Count) 'Available Private Endpoint Types'"
1240-
}
1241-
else {
1242-
$throwmsg = "$($htAvailablePrivateEndpointTypes.Keys.Count) 'Available Private Endpoint Types' - Checked for $($subsToProcessForGettingPrivateEndpointTypes.Count) Subscriptions with no success. Make sure that for at least one Subscription the Resource Provider 'Microsoft.Network' is registered. Once you registered the Resource Provider for Subscription 'subscriptionEnabled' it may be a good idea to use the parameter: -SubscriptionId4AzContext '<subscriptionId of subscriptionEnabled>'"
1243-
Write-Host $throwmsg -ForegroundColor DarkRed
1244-
Throw $throwmsg
1245-
}
1246-
1247-
$endGetAvailablePrivateEndpointTypes = Get-Date
1248-
Write-Host "Getting 'Available Private Endpoint Types' duration: $((New-TimeSpan -Start $startGetAvailablePrivateEndpointTypes -End $endGetAvailablePrivateEndpointTypes).TotalMinutes) minutes ($((New-TimeSpan -Start $startGetAvailablePrivateEndpointTypes -End $endGetAvailablePrivateEndpointTypes).TotalSeconds) seconds)"
1249-
#endregion Getting Available Private Endpoint Types
1164+
getPrivateEndpointCapableResourceTypes
12501165
}
12511166

12521167
Write-Host 'Collecting custom data'

pwsh/dev/functions/cacheBuiltIn.ps1

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -79,15 +79,12 @@ function cacheBuiltIn {
7979
if (-not [string]::IsNullOrWhiteSpace($builtinPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds)) {
8080
$script:htCacheDefinitionsPolicy.(($builtinPolicyDefinition.Id).ToLower()).RoleDefinitionIds = $builtinPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds
8181
foreach ($roledefinitionId in $builtinPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds) {
82-
if (-not $htRoleDefinitionIdsUsedInPolicy.($roledefinitionId)) {
83-
$script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId) = @{
82+
if (-not $htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower())) {
83+
$script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()) = @{
8484
UsedInPolicies = [System.Collections.ArrayList]@()
8585
}
86-
#$null = $script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId).UsedInPolicies.Add($builtinPolicyDefinition.Id)
8786
}
88-
#else {
89-
$null = $script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId).UsedInPolicies.Add($builtinPolicyDefinition.Id)
90-
#}
87+
$null = $script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()).UsedInPolicies.Add($builtinPolicyDefinition.Id)
9188
}
9289
}
9390
else {
@@ -170,15 +167,12 @@ function cacheBuiltIn {
170167
if (-not [string]::IsNullOrWhiteSpace($staticPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds)) {
171168
$script:htCacheDefinitionsPolicy.(($staticPolicyDefinition.Id).ToLower()).RoleDefinitionIds = $staticPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds
172169
foreach ($roledefinitionId in $staticPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds) {
173-
if (-not $htRoleDefinitionIdsUsedInPolicy.($roledefinitionId)) {
174-
$script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId) = @{
170+
if (-not $htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower())) {
171+
$script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()) = @{
175172
UsedInPolicies = [System.Collections.ArrayList]@()
176173
}
177-
#$null = $script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId).UsedInPolicies.Add($staticPolicyDefinition.Id)
178174
}
179-
#else {
180-
$null = $script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId).UsedInPolicies.Add($staticPolicyDefinition.Id)
181-
#}
175+
$null = $script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()).UsedInPolicies.Add($staticPolicyDefinition.Id)
182176
}
183177
}
184178
else {

pwsh/dev/functions/dataCollection/dataCollectionFunctions.ps1

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ function dataCollectionDefenderPlans {
2828

2929
$currentTask = "Getting Microsoft Defender for Cloud plans for Subscription: '$($scopeDisplayName)' ('$scopeId') [quotaId:'$SubscriptionQuotaId']"
3030
#https://learn.microsoft.com/rest/api/defenderforcloud/pricings
31-
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/subscriptions/$($scopeId)/providers/Microsoft.Security/pricings?api-version=2018-06-01"
31+
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/subscriptions/$($scopeId)/providers/Microsoft.Security/pricings?api-version=2024-01-01"
3232
$method = 'GET'
3333
$defenderPlansResult = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask -caller 'CustomDataCollection'
3434

@@ -2194,15 +2194,12 @@ function dataCollectionPolicyDefinitions {
21942194
$script:htCacheDefinitionsPolicy.($hlpPolicyDefinitionId).RoleDefinitionIds = $scopePolicyDefinition.properties.policyRule.then.details.roleDefinitionIds
21952195
foreach ($roledefinitionId in $scopePolicyDefinition.properties.policyRule.then.details.roleDefinitionIds) {
21962196
if (-not [string]::IsNullOrEmpty($roledefinitionId)) {
2197-
if (-not $htRoleDefinitionIdsUsedInPolicy.($roledefinitionId)) {
2198-
$script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId) = @{
2197+
if (-not $htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower())) {
2198+
$script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()) = @{
21992199
UsedInPolicies = [System.Collections.ArrayList]@()
22002200
}
2201-
#$null = $script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId).UsedInPolicies.Add($hlpPolicyDefinitionId)
22022201
}
2203-
#else {
2204-
$script:htRoleDefinitionIdsUsedInPolicy.($roledefinitionId).UsedInPolicies.Add($hlpPolicyDefinitionId)
2205-
#}
2202+
$script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()).UsedInPolicies.Add($hlpPolicyDefinitionId)
22062203
}
22072204
else {
22082205
Write-Host "$currentTask $($hlpPolicyDefinitionId) Finding: empty roleDefinitionId in roledefinitionIds"

0 commit comments

Comments
 (0)