Skip to content

Commit 69e5b56

Browse files
Merge pull request #231 from JulianHayward/orphanResources_latest
6.4.5
2 parents aa67339 + 032510a commit 69e5b56

16 files changed

+2007
-1276
lines changed

README.md

Lines changed: 375 additions & 363 deletions
Large diffs are not rendered by default.

history.md

Lines changed: 729 additions & 718 deletions
Large diffs are not rendered by default.

pwsh/AzGovVizParallel.ps1

Lines changed: 451 additions & 97 deletions
Large diffs are not rendered by default.

pwsh/dev/devAzGovVizParallel.ps1

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

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

370370
[string]
371371
$GithubRepository = 'aka.ms/AzGovViz',
@@ -458,7 +458,7 @@ Param
458458
$DoAzureConsumptionPreviousMonth,
459459

460460
[int]
461-
$AzureConsumptionPeriod = 1,
461+
$AzureConsumptionPeriod = 2,
462462

463463
[switch]
464464
$NoAzureConsumptionReportExportToCSV,
@@ -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', 'Mutate')
630+
$ValidPolicyEffects = @('addToNetworkGroup', 'append', 'audit', 'auditIfNotExists', 'deny', 'denyAction', 'deployIfNotExists', 'modify', 'manual', 'disabled', 'EnforceRegoPolicy', 'enforceSetting', 'mutate')
631631
)
632632

633633
$Error.clear()
@@ -920,7 +920,6 @@ if (-not $HierarchyMapOnly) {
920920
$htCacheDefinitionsPolicySet = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{} #[System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{}
921921
$htCacheDefinitionsRole = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{} #[System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{}
922922
$htCacheDefinitionsBlueprint = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{} #[System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{}
923-
$htRoleDefinitionIdsUsedInPolicy = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{}
924923
$htRoleAssignmentsPIM = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{} #[System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{}
925924
$htPoliciesUsedInPolicySets = @{}
926925
$htSubscriptionTags = [System.Collections.Hashtable]::Synchronized((New-Object System.Collections.Hashtable)) #@{}
@@ -1348,6 +1347,42 @@ if (-not $HierarchyMapOnly) {
13481347
$tenantCustomPolicies = (($htCacheDefinitionsPolicy).Values).where({ $_.Type -eq 'Custom' } )
13491348
$tenantCustomPoliciesCount = ($tenantCustomPolicies).count
13501349

1350+
#roleDefinitions used in policyDefinitions
1351+
Write-Host 'Processing roleDefinitions used in policyDefinitions'
1352+
$startRoleDefinitionsUsedInPolicyDefinitions = Get-Date
1353+
$htRoleDefinitionIdsUsedInPolicy = @{}
1354+
foreach ($policyDefinitionId in $htCacheDefinitionsPolicy.Keys) {
1355+
if (-not [string]::IsNullOrWhiteSpace($htCacheDefinitionsPolicy.($policyDefinitionId).Json.properties.policyRule.then.details.roleDefinitionIds)) {
1356+
foreach ($roledefinitionId in $htCacheDefinitionsPolicy.($policyDefinitionId).Json.properties.policyRule.then.details.roleDefinitionIds) {
1357+
if (-not [string]::IsNullOrWhitespace($roledefinitionId)) {
1358+
if (-not $htCacheDefinitionsRole.($roledefinitionId -replace '.*/')) {
1359+
Write-Host "Finding: policyDefinitionId '$($policyDefinitionId)' has unknown roleDefinitionId '$roledefinitionId' in policyRule.then.details.roleDefinitionIds" -ForegroundColor DarkRed
1360+
}
1361+
else {
1362+
if (-not $htRoleDefinitionIdsUsedInPolicy.($roledefinitionId -replace '.*/')) {
1363+
$htRoleDefinitionIdsUsedInPolicy.($roledefinitionId -replace '.*/') = [System.Collections.ArrayList]@()
1364+
}
1365+
try {
1366+
$null = $htRoleDefinitionIdsUsedInPolicy.($roledefinitionId -replace '.*/').Add($policyDefinitionId)
1367+
}
1368+
catch {
1369+
Write-Host "policyDefinitionId '$($policyDefinitionId)' JSON:"
1370+
$htCacheDefinitionsPolicy.($policyDefinitionId).Json | ConvertTo-Json -Depth 99
1371+
Write-Host '--->'
1372+
Throw "Failed: `$policyDefinitionId: '$($policyDefinitionId)' trying to add `$roledefinitionId: '$roledefinitionId' from policyRule.then.details.roleDefinitionIds to `$htRoleDefinitionIdsUsedInPolicy.(`$roledefinitionId).UsedInPolicies"
1373+
}
1374+
}
1375+
}
1376+
else {
1377+
Write-Host "Finding: policyDefinitionId '$($policyDefinitionId)' has empty roleDefinitionId in policyRule.then.details.roleDefinitionIds" -ForegroundColor DarkRed
1378+
}
1379+
}
1380+
}
1381+
}
1382+
Write-Host " $($htRoleDefinitionIdsUsedInPolicy.Keys.Count) roleDefinitions are used in policyDefinitions"
1383+
$endRoleDefinitionsUsedInPolicyDefinitions = Get-Date
1384+
Write-Host " roleDefinitions used in policyDefinitions duration: $((New-TimeSpan -Start $startRoleDefinitionsUsedInPolicyDefinitions -End $endRoleDefinitionsUsedInPolicyDefinitions).TotalSeconds) seconds"
1385+
13511386
#hashes for parity builtin/custom
13521387
Write-Host 'Processing Policy custom/built-In parity check'
13531388
$startPolicyCustomBuiltInParity = Get-Date
@@ -2467,7 +2502,7 @@ Write-Host '--------------------'
24672502
Write-Host "Azure Governance Visualizer ($ProductVersion) completed successful" -ForegroundColor Green
24682503

24692504
if ($Error.Count -gt 0) {
2470-
Write-Host "Don't bother about dumped errors"
2505+
Write-Host "Don't bother about dumped errors, execution was successful - if you see errors above this line, those were handled by the tool and are only dumped informational."
24712506
}
24722507

24732508
if ($DoPSRule) {

pwsh/dev/functions/cacheBuiltIn.ps1

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ function cacheBuiltIn {
1414
$htCacheDefinitionsPolicy = $using:htCacheDefinitionsPolicy
1515
$htCacheDefinitionsPolicySet = $using:htCacheDefinitionsPolicySet
1616
$htCacheDefinitionsRole = $using:htCacheDefinitionsRole
17-
$htRoleDefinitionIdsUsedInPolicy = $using:htRoleDefinitionIdsUsedInPolicy
1817
$ValidPolicyEffects = $using:ValidPolicyEffects
1918
$htHashesBuiltInPolicy = $using:htHashesBuiltInPolicy
2019
#vars
@@ -78,14 +77,6 @@ function cacheBuiltIn {
7877

7978
if (-not [string]::IsNullOrWhiteSpace($builtinPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds)) {
8079
$script:htCacheDefinitionsPolicy.(($builtinPolicyDefinition.Id).ToLower()).RoleDefinitionIds = $builtinPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds
81-
foreach ($roledefinitionId in $builtinPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds) {
82-
if (-not $htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower())) {
83-
$script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()) = @{
84-
UsedInPolicies = [System.Collections.ArrayList]@()
85-
}
86-
}
87-
$null = $script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()).UsedInPolicies.Add($builtinPolicyDefinition.Id)
88-
}
8980
}
9081
else {
9182
$script:htCacheDefinitionsPolicy.(($builtinPolicyDefinition.Id).ToLower()).RoleDefinitionIds = 'n/a'
@@ -166,14 +157,6 @@ function cacheBuiltIn {
166157

167158
if (-not [string]::IsNullOrWhiteSpace($staticPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds)) {
168159
$script:htCacheDefinitionsPolicy.(($staticPolicyDefinition.Id).ToLower()).RoleDefinitionIds = $staticPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds
169-
foreach ($roledefinitionId in $staticPolicyDefinition.properties.policyRule.then.details.roleDefinitionIds) {
170-
if (-not $htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower())) {
171-
$script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()) = @{
172-
UsedInPolicies = [System.Collections.ArrayList]@()
173-
}
174-
}
175-
$null = $script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()).UsedInPolicies.Add($staticPolicyDefinition.Id)
176-
}
177160
}
178161
else {
179162
$script:htCacheDefinitionsPolicy.(($staticPolicyDefinition.Id).ToLower()).RoleDefinitionIds = 'n/a'
@@ -236,22 +219,23 @@ function cacheBuiltIn {
236219
}
237220

238221
if ($builtInCapability -eq 'RoleDefinitions') {
239-
#Write-Host "`$ignoreARMLocation = '$ignoreARMLocation'" -ForegroundColor Yellow
222+
223+
#region subscriptionScope
240224
if ($ignoreARMLocation) {
241-
$currentTask = 'Caching built-in Role definitions'
225+
$currentTask = 'Caching built-in Role definitions (subscriptionScope)'
242226
Write-Host " $currentTask"
243-
$uri = "$($azAPICallConf['azAPIEndpointUrls'].'ARM')/subscriptions/$($azAPICallConf['checkContext'].Subscription.Id)/providers/Microsoft.Authorization/roleDefinitions?api-version=2022-05-01-preview&`$filter=type eq 'BuiltInRole'"
227+
$uri = "$($azAPICallConf['azAPIEndpointUrls'].'ARM')/subscriptions/$($azAPICallConf['checkContext'].Subscription.Id)/providers/Microsoft.Authorization/roleDefinitions?api-version=2023-07-01-preview&`$filter=type eq 'BuiltInRole'"
244228
}
245229
else {
246-
$currentTask = "Caching built-in Role definitions (Location: '$($ARMLocation)')"
230+
$currentTask = "Caching built-in Role definitions (Location: '$($ARMLocation)') (subscriptionScope)"
247231
Write-Host " $currentTask"
248-
$uri = "$($azAPICallConf['azAPIEndpointUrls']."ARM$($ARMLocation)")/subscriptions/$($azAPICallConf['checkContext'].Subscription.Id)/providers/Microsoft.Authorization/roleDefinitions?api-version=2022-05-01-preview&`$filter=type eq 'BuiltInRole'"
232+
$uri = "$($azAPICallConf['azAPIEndpointUrls']."ARM$($ARMLocation)")/subscriptions/$($azAPICallConf['checkContext'].Subscription.Id)/providers/Microsoft.Authorization/roleDefinitions?api-version=2023-07-01-preview&`$filter=type eq 'BuiltInRole'"
249233
}
250234

251235
$method = 'GET'
252236
$requestRoleDefinitionAPI = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask
253237

254-
Write-Host " $($requestRoleDefinitionAPI.Count) built-in Role definitions returned"
238+
Write-Host " $($requestRoleDefinitionAPI.Count) built-in Role definitions returned (subscriptionScope)"
255239
foreach ($roleDefinition in $requestRoleDefinitionAPI) {
256240
if (
257241
(
@@ -276,7 +260,7 @@ function cacheBuiltIn {
276260
$roleCapable4RoleAssignmentsWrite = $false
277261
}
278262

279-
($script:htCacheDefinitionsRole).($roleDefinition.name) = @{
263+
($script:htCacheDefinitionsRole).($roleDefinition.name) = @{
280264
Id = ($roleDefinition.name)
281265
Name = ($roleDefinition.properties.roleName)
282266
IsCustom = $false
@@ -291,6 +275,67 @@ function cacheBuiltIn {
291275
}
292276

293277
}
278+
#endregion subscriptionScope
279+
280+
#region tenantScope
281+
if ($ignoreARMLocation) {
282+
$currentTask = 'Caching built-in Role definitions (tenantScope)'
283+
Write-Host " $currentTask"
284+
$uri = "$($azAPICallConf['azAPIEndpointUrls'].'ARM')/providers/Microsoft.Authorization/roleDefinitions?api-version=2023-07-01-preview&`$filter=type eq 'BuiltInRole'"
285+
}
286+
else {
287+
$currentTask = "Caching built-in Role definitions (Location: '$($ARMLocation)') (tenantScope)"
288+
Write-Host " $currentTask"
289+
$uri = "$($azAPICallConf['azAPIEndpointUrls']."ARM$($ARMLocation)")/providers/Microsoft.Authorization/roleDefinitions?api-version=2023-07-01-preview&`$filter=type eq 'BuiltInRole'"
290+
}
291+
292+
$method = 'GET'
293+
$requestRoleDefinitionTenantScopeAPI = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask
294+
295+
Write-Host " $($requestRoleDefinitionTenantScopeAPI.Count) built-in Role definitions returned (tenantScope)"
296+
foreach ($roleDefinition in $requestRoleDefinitionTenantScopeAPI) {
297+
if (-not $htCacheDefinitionsRole.($roleDefinition.name)) {
298+
Write-Host "tenantScope role: '$($roleDefinition.properties.roleName)' - $($roleDefinition.name)"
299+
if (
300+
(
301+
$roleDefinition.properties.permissions.actions -contains 'Microsoft.Authorization/roleassignments/write' -or
302+
$roleDefinition.properties.permissions.actions -contains 'Microsoft.Authorization/roleassignments/*' -or
303+
$roleDefinition.properties.permissions.actions -contains 'Microsoft.Authorization/*/write' -or
304+
$roleDefinition.properties.permissions.actions -contains 'Microsoft.Authorization/*' -or
305+
$roleDefinition.properties.permissions.actions -contains '*/write' -or
306+
$roleDefinition.properties.permissions.actions -contains '*'
307+
) -and (
308+
$roleDefinition.properties.permissions.notActions -notcontains 'Microsoft.Authorization/roleassignments/write' -and
309+
$roleDefinition.properties.permissions.notActions -notcontains 'Microsoft.Authorization/roleassignments/*' -and
310+
$roleDefinition.properties.permissions.notActions -notcontains 'Microsoft.Authorization/*/write' -and
311+
$roleDefinition.properties.permissions.notActions -notcontains 'Microsoft.Authorization/*' -and
312+
$roleDefinition.properties.permissions.notActions -notcontains '*/write' -and
313+
$roleDefinition.properties.permissions.notActions -notcontains '*'
314+
)
315+
) {
316+
$roleCapable4RoleAssignmentsWrite = $true
317+
}
318+
else {
319+
$roleCapable4RoleAssignmentsWrite = $false
320+
}
321+
322+
($script:htCacheDefinitionsRole).($roleDefinition.name) = @{
323+
Id = ($roleDefinition.name)
324+
Name = ($roleDefinition.properties.roleName)
325+
IsCustom = $false
326+
AssignableScopes = ($roleDefinition.properties.assignableScopes)
327+
Actions = ($roleDefinition.properties.permissions.actions)
328+
NotActions = ($roleDefinition.properties.permissions.notActions)
329+
DataActions = ($roleDefinition.properties.permissions.dataActions)
330+
NotDataActions = ($roleDefinition.properties.permissions.notDataActions)
331+
Json = $roleDefinition
332+
LinkToAzAdvertizer = "<a class=`"externallink`" href=`"https://www.azadvertizer.net/azrolesadvertizer/$($roleDefinition.name).html`" target=`"_blank`" rel=`"noopener`">$($roleDefinition.properties.roleName)</a>"
333+
RoleCanDoRoleAssignments = $roleCapable4RoleAssignmentsWrite
334+
}
335+
}
336+
337+
}
338+
#endregion tenantScope
294339
}
295340
}
296341

pwsh/dev/functions/dataCollection/dataCollectionFunctions.ps1

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2192,19 +2192,6 @@ function dataCollectionPolicyDefinitions {
21922192

21932193
if (-not [string]::IsNullOrWhiteSpace($scopePolicyDefinition.properties.policyRule.then.details.roleDefinitionIds)) {
21942194
$script:htCacheDefinitionsPolicy.($hlpPolicyDefinitionId).RoleDefinitionIds = $scopePolicyDefinition.properties.policyRule.then.details.roleDefinitionIds
2195-
foreach ($roledefinitionId in $scopePolicyDefinition.properties.policyRule.then.details.roleDefinitionIds) {
2196-
if (-not [string]::IsNullOrEmpty($roledefinitionId)) {
2197-
if (-not $htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower())) {
2198-
$script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()) = @{
2199-
UsedInPolicies = [System.Collections.ArrayList]@()
2200-
}
2201-
}
2202-
$script:htRoleDefinitionIdsUsedInPolicy.(($roledefinitionId).ToLower()).UsedInPolicies.Add($hlpPolicyDefinitionId)
2203-
}
2204-
else {
2205-
Write-Host "$currentTask $($hlpPolicyDefinitionId) Finding: empty roleDefinitionId in roledefinitionIds"
2206-
}
2207-
}
22082195
}
22092196
else {
22102197
$script:htCacheDefinitionsPolicy.($hlpPolicyDefinitionId).RoleDefinitionIds = 'n/a'
@@ -3466,11 +3453,11 @@ function dataCollectionRoleDefinitions {
34663453

34673454
if ($TargetMgOrSub -eq 'Sub') {
34683455
$currentTask = "Getting Custom Role definitions for Subscription: '$($scopeDisplayName)' ('$scopeId') [quotaId:'$subscriptionQuotaId']"
3469-
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/subscriptions/$($scopeId)/providers/Microsoft.Authorization/roleDefinitions?api-version=2022-05-01-preview&`$filter=type eq 'CustomRole'"
3456+
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/subscriptions/$($scopeId)/providers/Microsoft.Authorization/roleDefinitions?api-version=2023-07-01-preview&`$filter=type eq 'CustomRole'"
34703457
}
34713458
if ($TargetMgOrSub -eq 'MG') {
34723459
$currentTask = "Getting Custom Role definitions for Management Group: '$($scopeDisplayName)' ('$scopeId')"
3473-
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/providers/Microsoft.Management/managementGroups/$($scopeId)/providers/Microsoft.Authorization/roleDefinitions?api-version=2022-05-01-preview&`$filter=type eq 'CustomRole'"
3460+
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/providers/Microsoft.Management/managementGroups/$($scopeId)/providers/Microsoft.Authorization/roleDefinitions?api-version=2023-07-01-preview&`$filter=type eq 'CustomRole'"
34743461
}
34753462
$method = 'GET'
34763463
$scopeCustomRoleDefinitions = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask -caller 'CustomDataCollection'

0 commit comments

Comments
 (0)