pwsh/dev/functions/processDataCollection.ps1 (1,210 lines of code) (raw):
function processDataCollection {
[CmdletBinding()]Param(
[string]$mgId
)
Write-Host ' CustomDataCollection ManagementGroups'
$startMgLoop = Get-Date
$allManagementGroupsFromEntitiesChildOfRequestedMg = $arrayEntitiesFromAPI.where( { $_.type -eq 'Microsoft.Management/managementGroups' -and ($_.Name -eq $mgId -or $_.properties.parentNameChain -contains $mgId) })
$allManagementGroupsFromEntitiesChildOfRequestedMgCount = ($allManagementGroupsFromEntitiesChildOfRequestedMg).Count
Write-Host " $allManagementGroupsFromEntitiesChildOfRequestedMgCount Management Groups: $(($allManagementGroupsFromEntitiesChildOfRequestedMg.Name | Sort-Object) -join ', ')"
$mgBatch = ($allManagementGroupsFromEntitiesChildOfRequestedMg | Group-Object -Property { ($_.properties.parentNameChain).Count }) | Sort-Object -Property Name
Write-Host " $(($mgBatch | Measure-Object).Count) batches of Management Groups to process:"
$btchCnt = 0
foreach ($btch in $mgBatch) {
$btchCnt++
$listOfMGs = [System.Collections.ArrayList]@()
foreach ($btchMg in $btch.Group | Sort-Object -Property name) {
if ($btchMg.name -eq $btchMg.Properties.displayName) {
$null = $listOfMGs.Add($btchMg.name)
}
else {
$null = $listOfMGs.Add("$($btchMg.name) ($($btchMg.Properties.displayName))")
}
}
Write-Host " Batch#$($btchCnt) - $($listOfMGs.Count) Management Groups: $($listOfMGs -join ', ')"
}
foreach ($batchLevel in $mgBatch) {
Write-Host " Processing Management Groups L$($batchLevel.Name) ($($batchLevel.Count) Management Groups)"
showMemoryUsage
$batchSize = [math]::ceiling($batchLevel.Group.Count / $ThrottleLimit)
Write-Host "Optimal batch size: $($batchSize)"
$counterBatch = [PSCustomObject] @{ Value = 0 }
$batchLevelGroupBatch = ($batchLevel.Group) | Group-Object -Property { [math]::Floor($counterBatch.Value++ / $batchSize) }
Write-Host "Processing data in $($batchLevelGroupBatch.Count) batches"
$batchLevelGroupBatch | ForEach-Object -Parallel {
#region UsingVARs
#Parameters MG&Sub related
$CsvDelimiter = $using:CsvDelimiter
$CsvDelimiterOpposite = $using:CsvDelimiterOpposite
$ManagementGroupId = $using:ManagementGroupId
#fromOtherFunctions
$azAPICallConf = $using:azAPICallConf
$scriptPath = $using:ScriptPath
#Array&HTs
$newTable = $using:newTable
$customDataCollectionDuration = $using:customDataCollectionDuration
$htSubscriptionTagList = $using:htSubscriptionTagList
$htResourceTypesUniqueResource = $using:htResourceTypesUniqueResource
$htAllTagList = $using:htAllTagList
$htSubscriptionTags = $using:htSubscriptionTags
$htCacheDefinitionsPolicy = $using:htCacheDefinitionsPolicy
$htCacheDefinitionsPolicySet = $using:htCacheDefinitionsPolicySet
$htCacheDefinitionsRole = $using:htCacheDefinitionsRole
$htCacheDefinitionsBlueprint = $using:htCacheDefinitionsBlueprint
$htCachePolicyComplianceMG = $using:htCachePolicyComplianceMG
$htCachePolicyComplianceResponseTooLargeMG = $using:htCachePolicyComplianceResponseTooLargeMG
$htCacheAssignmentsRole = $using:htCacheAssignmentsRole
$htCacheAssignmentsRBACOnResourceGroupsAndResources = $using:htCacheAssignmentsRBACOnResourceGroupsAndResources
$htCacheAssignmentsBlueprint = $using:htCacheAssignmentsBlueprint
$htCacheAssignmentsPolicy = $using:htCacheAssignmentsPolicy
$htPolicyAssignmentExemptions = $using:htPolicyAssignmentExemptions
$htManagementGroupsMgPath = $using:htManagementGroupsMgPath
$LimitPOLICYPolicyDefinitionsScopedManagementGroup = $using:LimitPOLICYPolicyDefinitionsScopedManagementGroup
$LimitPOLICYPolicySetDefinitionsScopedManagementGroup = $using:LimitPOLICYPolicySetDefinitionsScopedManagementGroup
$LimitPOLICYPolicyAssignmentsManagementGroup = $using:LimitPOLICYPolicyAssignmentsManagementGroup
$LimitPOLICYPolicySetAssignmentsManagementGroup = $using:LimitPOLICYPolicySetAssignmentsManagementGroup
$LimitRBACRoleAssignmentsManagementGroup = $using:LimitRBACRoleAssignmentsManagementGroup
$arrayEntitiesFromAPI = $using:arrayEntitiesFromAPI
$allManagementGroupsFromEntitiesChildOfRequestedMgCount = $using:allManagementGroupsFromEntitiesChildOfRequestedMgCount
$arrayDataCollectionProgressMg = $using:arrayDataCollectionProgressMg
$arrayDiagnosticSettingsMgSub = $using:arrayDiagnosticSettingsMgSub
$htMgAtScopePolicyAssignments = $using:htMgAtScopePolicyAssignments
$htMgAtScopePoliciesScoped = $using:htMgAtScopePoliciesScoped
$htMgAtScopeRoleAssignments = $using:htMgAtScopeRoleAssignments
$htMgASCSecureScore = $using:htMgASCSecureScore
$htRoleAssignmentsFromAPIInheritancePrevention = $using:htRoleAssignmentsFromAPIInheritancePrevention
$htNamingValidation = $using:htNamingValidation
$htPrincipals = $using:htPrincipals
$htServicePrincipals = $using:htServicePrincipals
$htUserTypesGuest = $using:htUserTypesGuest
$htRoleAssignmentsPIM = $using:htRoleAssignmentsPIM
$alzPolicies = $using:alzPolicies
$alzPolicySets = $using:alzPolicySets
$alzPolicyHashes = $using:alzPolicyHashes
$alzPolicySetHashes = $using:alzPolicySetHashes
$htDoARMRoleAssignmentScheduleInstances = $using:htDoARMRoleAssignmentScheduleInstances
$ValidPolicyEffects = $using:ValidPolicyEffects
#other
$function:addRowToTable = $using:funcAddRowToTable
$function:namingValidation = $using:funcNamingValidation
$function:resolveObjectIds = $using:funcResolveObjectIds
$function:testGuid = $using:funcTestGuid
$function:dataCollectionMGSecureScore = $using:funcDataCollectionMGSecureScore
$function:dataCollectionDiagnosticsMG = $using:funcDataCollectionDiagnosticsMG
$function:dataCollectionPolicyComplianceStates = $using:funcDataCollectionPolicyComplianceStates
$function:dataCollectionBluePrintDefinitionsMG = $using:funcDataCollectionBluePrintDefinitionsMG
$function:dataCollectionPolicyExemptions = $using:funcDataCollectionPolicyExemptions
$function:dataCollectionPolicyDefinitions = $using:funcDataCollectionPolicyDefinitions
$function:dataCollectionPolicySetDefinitions = $using:funcDataCollectionPolicySetDefinitions
$function:dataCollectionPolicyAssignmentsMG = $using:funcDataCollectionPolicyAssignmentsMG
$function:dataCollectionRoleDefinitions = $using:funcDataCollectionRoleDefinitions
$function:dataCollectionRoleAssignmentsMG = $using:funcDataCollectionRoleAssignmentsMG
$function:detectPolicyEffect = $using:funcDetectPolicyEffect
#endregion usingVARS
$builtInPolicyDefinitionsCount = $using:builtInPolicyDefinitionsCount
foreach ($mgdetail in $_.Group) {
$addRowToTableDone = $false
$MgDetailThis = $htManagementGroupsMgPath.($mgdetail.Name)
$MgParentId = $MgDetailThis.Parent
$hierarchyLevel = $MgDetailThis.ParentNameChainCount
if ($MgParentId -eq '__TenantRoot__') {
$MgParentId = 'TenantRoot'
$MgParentName = $MgParentId
}
else {
$MgParentName = $htManagementGroupsMgPath.($MgParentId).DisplayName
}
$rndom = Get-Random -Minimum 10 -Maximum 750
Start-Sleep -Millisecond $rndom
$startMgLoopThis = Get-Date
if ($azAPICallConf['htParameters'].HierarchyMapOnly -eq $false) {
#namingValidation
if (-not [string]::IsNullOrEmpty($mgdetail.properties.displayName)) {
$namingValidationResult = NamingValidation -toCheck $mgdetail.properties.displayName
if ($namingValidationResult.Count -gt 0) {
$script:htNamingValidation.ManagementGroup.($mgdetail.Name) = @{
nameInvalidChars = ($namingValidationResult -join '')
name = $mgdetail.properties.displayName
}
}
}
$targetMgOrSub = 'MG'
$baseParameters = @{
scopeId = $mgdetail.Name
scopeDisplayName = $mgdetail.properties.displayName
}
#ManagementGroupASCSecureScore
$mgAscSecureScoreResult = DataCollectionMGSecureScore -Id $mgdetail.Name
$addRowToTableParameters = @{
hierarchyLevel = $hierarchyLevel
mgParentId = $mgParentId
mgParentName = $mgParentName
mgAscSecureScoreResult = $mgAscSecureScoreResult
}
#mg diag
DataCollectionDiagnosticsMG @baseParameters
if ($azAPICallConf['htParameters'].NoPolicyComplianceStates -eq $false) {
#MGPolicyCompliance
DataCollectionPolicyComplianceStates @baseParameters -TargetMgOrSub $targetMgOrSub
}
#MGBlueprintDefinitions
$functionReturn = DataCollectionBluePrintDefinitionsMG @baseParameters @addRowToTableParameters
if ($functionReturn.'addRowToTableDone') {
$addRowToTableDone = $true
}
#MGPolicyExemptions
DataCollectionPolicyExemptions @baseParameters -TargetMgOrSub $targetMgOrSub
#MGPolicyDefinitions
$functionReturn = DataCollectionPolicyDefinitions @baseParameters -TargetMgOrSub $targetMgOrSub
$policyDefinitionsScopedCount = $functionReturn.'PolicyDefinitionsScopedCount'
#MGPolicySetDefinitions
$functionReturn = DataCollectionPolicySetDefinitions @baseParameters -TargetMgOrSub $targetMgOrSub
$policySetDefinitionsScopedCount = $functionReturn.'PolicySetDefinitionsScopedCount'
if (-not $htMgAtScopePoliciesScoped.($mgdetail.Name)) {
$script:htMgAtScopePoliciesScoped.($mgdetail.Name) = @{
ScopedCount = $policyDefinitionsScopedCount + $policySetDefinitionsScopedCount
}
}
$scopedPolicyCounts = @{
policyDefinitionsScopedCount = $policyDefinitionsScopedCount
policySetDefinitionsScopedCount = $policySetDefinitionsScopedCount
}
#MgPolicyAssignments
$functionReturn = DataCollectionPolicyAssignmentsMG @baseParameters @addRowToTableParameters @scopedPolicyCounts
if ($functionReturn.'addRowToTableDone') {
$addRowToTableDone = $true
}
#MGRoleDefinitions
DataCollectionRoleDefinitions @baseParameters -TargetMgOrSub $targetMgOrSub
#MGRoleAssignments
$functionReturn = DataCollectionRoleAssignmentsMG @baseParameters @addRowToTableParameters
if ($functionReturn.'addRowToTableDone') {
$addRowToTableDone = $true
}
if ($addRowToTableDone -ne $true) {
addRowToTable `
-level $hierarchyLevel `
-mgName $mgdetail.properties.displayName `
-mgId $mgdetail.Name `
-mgParentId $mgParentId `
-mgParentName $mgParentName `
-mgASCSecureScore $mgAscSecureScoreResult
}
}
else {
addRowToTable `
-level $hierarchyLevel `
-mgName $mgdetail.properties.displayName `
-mgId $mgdetail.Name `
-mgParentId $mgParentId `
-mgParentName $mgParentName `
-mgASCSecureScore $mgAscSecureScoreResult
}
$endMgLoopThis = Get-Date
$null = $script:customDataCollectionDuration.Add([PSCustomObject]@{
Type = 'Mg'
Id = $mgdetail.Name
DurationSec = (New-TimeSpan -Start $startMgLoopThis -End $endMgLoopThis).TotalSeconds
})
$null = $script:arrayDataCollectionProgressMg.Add($mgdetail.Name)
$progressCount = ($arrayDataCollectionProgressMg).Count
Write-Host " $($progressCount)/$($allManagementGroupsFromEntitiesChildOfRequestedMgCount) Management Groups processed"
}
} -ThrottleLimit $ThrottleLimit
}
$endMgLoop = Get-Date
Write-Host " CustomDataCollection ManagementGroups processing duration: $((New-TimeSpan -Start $startMgLoop -End $endMgLoop).TotalMinutes) minutes ($((New-TimeSpan -Start $startMgLoop -End $endMgLoop).TotalSeconds) seconds)"
apiCallTracking -stage 'CustomDataCollection ManagementGroups' -spacing ' '
#test
if ($builtInPolicyDefinitionsCount -ne ($($htCacheDefinitionsPolicy).Values.where({ $_.Type -eq 'BuiltIn' }).Count) -or $builtInPolicyDefinitionsCount -ne ((($htCacheDefinitionsPolicy).Values.where( { $_.Type -eq 'BuiltIn' } )).Count)) {
Write-Host "$builtInPolicyDefinitionsCount -ne $($($htCacheDefinitionsPolicy).Values.where({$_.Type -eq 'BuiltIn'}).Count) OR $builtInPolicyDefinitionsCount -ne $((($htCacheDefinitionsPolicy).Values.where( {$_.Type -eq 'BuiltIn'} )).Count)"
Write-Host 'Listing all PolicyDefinitions:'
foreach ($tmpPolicyDefinitionId in ($($htCacheDefinitionsPolicy).Keys | Sort-Object)) {
Write-Host $tmpPolicyDefinitionId
}
}
#region SUBSCRIPTION
Write-Host ' CustomDataCollection Subscriptions'
if ($outOfScopeSubscriptions.Count -gt 0) {
Write-Host " CustomDataCollection $($outOfScopeSubscriptions.Count) Subscriptions excluded" -ForegroundColor yellow
$outOfScopeSubscriptionsGroupedByOutOfScopeReason = $outOfScopeSubscriptions | Group-Object -Property outOfScopeReason
foreach ($exclusionreason in $outOfScopeSubscriptionsGroupedByOutOfScopeReason) {
Write-Host " $($exclusionreason.Count): $($exclusionreason.Name)"
}
}
Write-Host " CustomDataCollection Subscriptions will process $subsToProcessInCustomDataCollectionCount of $childrenSubscriptionsCount"
$startSubLoop = Get-Date
if ($subsToProcessInCustomDataCollectionCount -gt 0) {
$batchSize = [math]::ceiling($subsToProcessInCustomDataCollectionCount / $ThrottleLimit)
Write-Host "Optimal batch size: $($batchSize)"
$counterBatch = [PSCustomObject] @{ Value = 0 }
$subsToProcessInCustomDataCollectionBatch = ($subsToProcessInCustomDataCollection) | Group-Object -Property { [math]::Floor($counterBatch.Value++ / $batchSize) }
Write-Host "Processing data in $($subsToProcessInCustomDataCollectionBatch.Count) batches"
$startBatch = Get-Date
showMemoryUsage
$subsToProcessInCustomDataCollectionBatch | ForEach-Object -Parallel {
$startSubLoopThis = Get-Date
#region UsingVARs
#Parameters MG&Sub related
$CsvDelimiter = $using:CsvDelimiter
$CsvDelimiterOpposite = $using:CsvDelimiterOpposite
#Parameters Sub related
#fromOtherFunctions
$azAPICallConf = $using:azAPICallConf
$scriptPath = $using:ScriptPath
#Array&HTs
$newTable = $using:newTable
$storageAccounts = $using:storageAccounts
$resourcesAll = $using:resourcesAll
$resourcesIdsAll = $using:resourcesIdsAll
$resourceGroupsAll = $using:resourceGroupsAll
$customDataCollectionDuration = $using:customDataCollectionDuration
$htSubscriptionsMgPath = $using:htSubscriptionsMgPath
$htManagementGroupsMgPath = $using:htManagementGroupsMgPath
$htResourceProvidersAll = $using:htResourceProvidersAll
$arrayFeaturesAll = $using:arrayFeaturesAll
$htSubscriptionTagList = $using:htSubscriptionTagList
$htResourceTypesUniqueResource = $using:htResourceTypesUniqueResource
$htAllTagList = $using:htAllTagList
$htSubscriptionTags = $using:htSubscriptionTags
$htCacheDefinitionsPolicy = $using:htCacheDefinitionsPolicy
$htCacheDefinitionsPolicySet = $using:htCacheDefinitionsPolicySet
$htCacheDefinitionsRole = $using:htCacheDefinitionsRole
$htCacheDefinitionsBlueprint = $using:htCacheDefinitionsBlueprint
$htCachePolicyComplianceSUB = $using:htCachePolicyComplianceSUB
$htCachePolicyComplianceResponseTooLargeSUB = $using:htCachePolicyComplianceResponseTooLargeSUB
$htCacheAssignmentsRole = $using:htCacheAssignmentsRole
$htCacheAssignmentsRBACOnResourceGroupsAndResources = $using:htCacheAssignmentsRBACOnResourceGroupsAndResources
$htCacheAssignmentsBlueprint = $using:htCacheAssignmentsBlueprint
$htCacheAssignmentsPolicyOnResourceGroupsAndResources = $using:htCacheAssignmentsPolicyOnResourceGroupsAndResources
$htCacheAssignmentsPolicy = $using:htCacheAssignmentsPolicy
$htPolicyAssignmentExemptions = $using:htPolicyAssignmentExemptions
$htResourceLocks = $using:htResourceLocks
$LimitPOLICYPolicyDefinitionsScopedSubscription = $using:LimitPOLICYPolicyDefinitionsScopedSubscription
$LimitPOLICYPolicySetDefinitionsScopedSubscription = $using:LimitPOLICYPolicySetDefinitionsScopedSubscription
$LimitPOLICYPolicyAssignmentsSubscription = $using:LimitPOLICYPolicyAssignmentsSubscription
$LimitPOLICYPolicySetAssignmentsSubscription = $using:LimitPOLICYPolicySetAssignmentsSubscription
$childrenSubscriptionsCount = $using:childrenSubscriptionsCount
$subsToProcessInCustomDataCollectionCount = $using:subsToProcessInCustomDataCollectionCount
$arrayDataCollectionProgressSub = $using:arrayDataCollectionProgressSub
$arraySubResourcesAddArrayDuration = $using:arraySubResourcesAddArrayDuration
$htAllSubscriptionsFromAPI = $using:htAllSubscriptionsFromAPI
$arrayEntitiesFromAPI = $using:arrayEntitiesFromAPI
$arrayDiagnosticSettingsMgSub = $using:arrayDiagnosticSettingsMgSub
$htMgASCSecureScore = $using:htMgASCSecureScore
$htRoleAssignmentsFromAPIInheritancePrevention = $using:htRoleAssignmentsFromAPIInheritancePrevention
$htNamingValidation = $using:htNamingValidation
$htPrincipals = $using:htPrincipals
$htServicePrincipals = $using:htServicePrincipals
$htUserTypesGuest = $using:htUserTypesGuest
$arrayDefenderPlans = $using:arrayDefenderPlans
$arrayDefenderPlansSubscriptionsSkipped = $using:arrayDefenderPlansSubscriptionsSkipped
$htSecuritySettings = $using:htSecuritySettings
$arrayUserAssignedIdentities4Resources = $using:arrayUserAssignedIdentities4Resources
$htSubscriptionsRoleAssignmentLimit = $using:htSubscriptionsRoleAssignmentLimit
$arrayPsRule = $using:arrayPsRule
$arrayPSRuleTracking = $using:arrayPSRuleTracking
$htClassicAdministrators = $using:htClassicAdministrators
$htRoleAssignmentsPIM = $using:htRoleAssignmentsPIM
$alzPolicies = $using:alzPolicies
$alzPolicySets = $using:alzPolicySets
$alzPolicyHashes = $using:alzPolicyHashes
$alzPolicySetHashes = $using:alzPolicySetHashes
$htDoARMRoleAssignmentScheduleInstances = $using:htDoARMRoleAssignmentScheduleInstances
$htDefenderEmailContacts = $using:htDefenderEmailContacts
$arrayVNets = $using:arrayVNets
$arrayPrivateEndPoints = $using:arrayPrivateEndPoints
$htResourceProvidersRef = $using:htResourceProvidersRef
$arrayPrivateEndPointsFromResourceProperties = $using:arrayPrivateEndPointsFromResourceProperties
$htResourcePropertiesConvertfromJSONFailed = $using:htResourcePropertiesConvertfromJSONFailed
$htAvailablePrivateEndpointTypes = $using:htAvailablePrivateEndpointTypes
$arrayAdvisorScores = $using:arrayAdvisorScores
$ValidPolicyEffects = $using:ValidPolicyEffects
#$htResourcesWithProperties = $using:htResourcesWithProperties
#other
$function:addRowToTable = $using:funcAddRowToTable
$function:namingValidation = $using:funcNamingValidation
$function:resolveObjectIds = $using:funcResolveObjectIds
$function:testGuid = $using:funcTestGuid
$function:dataCollectionMGSecureScore = $using:funcDataCollectionMGSecureScore
$function:dataCollectionDefenderPlans = $using:funcDataCollectionDefenderPlans
$function:dataCollectionDiagnosticsSub = $using:funcDataCollectionDiagnosticsSub
$function:dataCollectionResources = $using:funcDataCollectionResources
$function:dataCollectionStorageAccounts = $using:funcDataCollectionStorageAccounts
$function:dataCollectionResourceGroups = $using:funcDataCollectionResourceGroups
$function:dataCollectionResourceProviders = $using:funcDataCollectionResourceProviders
$function:dataCollectionFeatures = $using:funcDataCollectionFeatures
$function:dataCollectionResourceLocks = $using:funcDataCollectionResourceLocks
$function:dataCollectionTags = $using:funcDataCollectionTags
$function:dataCollectionPolicyComplianceStates = $using:funcDataCollectionPolicyComplianceStates
$function:dataCollectionASCSecureScoreSub = $using:funcDataCollectionASCSecureScoreSub
$function:dataCollectionBluePrintDefinitionsSub = $using:funcDataCollectionBluePrintDefinitionsSub
$function:dataCollectionBluePrintAssignmentsSub = $using:funcDataCollectionBluePrintAssignmentsSub
$function:dataCollectionPolicyExemptions = $using:funcDataCollectionPolicyExemptions
$function:dataCollectionPolicyDefinitions = $using:funcDataCollectionPolicyDefinitions
$function:dataCollectionPolicySetDefinitions = $using:funcDataCollectionPolicySetDefinitions
$function:dataCollectionPolicyAssignmentsSub = $using:funcDataCollectionPolicyAssignmentsSub
$function:dataCollectionRoleDefinitions = $using:funcDataCollectionRoleDefinitions
$function:dataCollectionRoleAssignmentsSub = $using:funcDataCollectionRoleAssignmentsSub
$function:dataCollectionClassicAdministratorsSub = $using:funcDataCollectionClassicAdministratorsSub
$function:dataCollectionDefenderEmailContacts = $using:funcDataCollectionDefenderEmailContacts
$function:dataCollectionVNets = $using:funcDataCollectionVNets
$function:dataCollectionPrivateEndpoints = $using:funcDataCollectionPrivateEndpoints
$function:dataCollectionAdvisorScores = $using:funcDataCollectionAdvisorScores
$function:detectPolicyEffect = $using:funcDetectPolicyEffect
#endregion UsingVARs
foreach ($childMgSubDetail in $_.Group) {
$addRowToTableDone = $false
$childMgSubId = $childMgSubDetail.subscriptionId
$childMgSubDisplayName = $childMgSubDetail.subscriptionName
$hierarchyInfo = $htSubscriptionsMgPath.($childMgSubDetail.subscriptionId)
$hierarchyLevel = $hierarchyInfo.level
$childMgId = $hierarchyInfo.Parent
$childMgDisplayName = $hierarchyInfo.ParentName
$childMgMgPath = $hierarchyInfo.pathDelimited
$childMgParentNameChain = $hierarchyInfo.ParentNameChain
$childMgParentNameChainDelimited = $hierarchyInfo.ParentNameChainDelimited
$childMgParentInfo = $htManagementGroupsMgPath.($childMgId)
$childMgParentId = $childMgParentInfo.Parent
$childMgParentName = $htManagementGroupsMgPath.($childMgParentInfo.Parent).DisplayName
#namingValidation
if (-not [string]::IsNullOrEmpty($childMgSubDisplayName)) {
$namingValidationResult = NamingValidation -toCheck $childMgSubDisplayName
if ($namingValidationResult.Count -gt 0) {
$script:htNamingValidation.Subscription.($childMgSubId) = @{
displayNameInvalidChars = ($namingValidationResult -join '')
displayName = $childMgSubDisplayName
}
}
}
if ($azAPICallConf['htParameters'].HierarchyMapOnly -eq $false) {
$currentSubscription = $htAllSubscriptionsFromAPI.($childMgSubId).subDetails
$subscriptionQuotaId = $currentSubscription.subscriptionPolicies.quotaId
$subscriptionState = $currentSubscription.state
$targetMgOrSub = 'Sub'
$baseParameters = @{
scopeId = $childMgSubId
scopeDisplayName = $childMgSubDisplayName
subscriptionQuotaId = $subscriptionQuotaId
}
if (-not $azAPICallConf['htParameters'].ManagementGroupsOnly) {
#mgSecureScore
$mgAscSecureScoreResult = DataCollectionMGSecureScore -Id $childMgId
#defenderPlans
$dataCollectionDefenderPlansParameters = @{
ChildMgMgPath = $childMgMgPath
}
DataCollectionDefenderPlans @baseParameters @dataCollectionDefenderPlansParameters
#defenderEmailContacts
DataCollectionDefenderEmailContacts @baseParameters
#advisorScores
$dataCollectionAdvisorScoresParameters = @{
ChildMgMgPath = $childMgMgPath
}
DataCollectionAdvisorScores @baseParameters @dataCollectionAdvisorScoresParameters
if (-not $azAPICallConf['htParameters'].NoNetwork) {
#VNets
DataCollectionVNets @baseParameters
#PE
DataCollectionPrivateEndpoints @baseParameters
}
#diagnostics
$dataCollectionDiagnosticsSubParameters = @{
ChildMgMgPath = $childMgMgPath
ChildMgId = $childMgId
}
DataCollectionDiagnosticsSub @baseParameters @dataCollectionDiagnosticsSubParameters
if ($azAPICallConf['htParameters'].NoStorageAccountAccessAnalysis -eq $false) {
#resources
$dataCollectionStorageAccountsParameters = @{
ChildMgMgPath = $childMgMgPath
ChildMgParentNameChainDelimited = $childMgParentNameChainDelimited
}
DataCollectionStorageAccounts @baseParameters @dataCollectionStorageAccountsParameters
}
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
#resources
$dataCollectionResourcesParameters = @{
ChildMgMgPath = $childMgMgPath
ChildMgParentNameChainDelimited = $childMgParentNameChainDelimited
}
DataCollectionResources @baseParameters @dataCollectionResourcesParameters
}
#resourceGroups
DataCollectionResourceGroups @baseParameters
#resourceProviders
if ($azAPICallConf['htParameters'].NoResourceProvidersAtAll -eq $false) {
DataCollectionResourceProviders @baseParameters
}
#features
DataCollectionFeatures @baseParameters -MgParentNameChain $childMgParentNameChain
#resourceLocks
DataCollectionResourceLocks @baseParameters
#tags
$subscriptionTagsReturn = DataCollectionTags @baseParameters
$subscriptionTags = $subscriptionTagsReturn.subscriptionTags
$subscriptionTagsCount = $subscriptionTagsReturn.subscriptionTagsCount
if ($azAPICallConf['htParameters'].NoPolicyComplianceStates -eq $false) {
#SubscriptionPolicyCompliance
DataCollectionPolicyComplianceStates @baseParameters -TargetMgOrSub $targetMgOrSub
}
#SubscriptionASCSecureScore
$subscriptionASCSecureScore = DataCollectionASCSecureScoreSub @baseParameters
$addRowToTableParameters = @{
hierarchyLevel = $hierarchyLevel
childMgDisplayName = $childMgDisplayName
childMgId = $childMgId
childMgParentId = $childMgParentId
childMgParentName = $childMgParentName
mgAscSecureScoreResult = $mgAscSecureScoreResult
#subscriptionQuotaId = $subscriptionQuotaId
subscriptionState = $subscriptionState
subscriptionASCSecureScore = $subscriptionASCSecureScore
subscriptionTags = $subscriptionTags
subscriptionTagsCount = $subscriptionTagsCount
}
#SubscriptionBlueprintDefinitions
$functionReturn = DataCollectionBluePrintDefinitionsSub @baseParameters @addRowToTableParameters
if ($functionReturn.'addRowToTableDone') {
$addRowToTableDone = $true
}
#SubscriptionBlueprintAssignments
$functionReturn = DataCollectionBluePrintAssignmentsSub @baseParameters @addRowToTableParameters
if ($functionReturn.'addRowToTableDone') {
$addRowToTableDone = $true
}
#SubscriptionPolicyExemptions
DataCollectionPolicyExemptions @baseParameters -TargetMgOrSub $targetMgOrSub
#SubscriptionPolicyDefinitions
$functionReturn = DataCollectionPolicyDefinitions @baseParameters -TargetMgOrSub $targetMgOrSub
$policyDefinitionsScopedCount = $functionReturn.'PolicyDefinitionsScopedCount'
#SubscriptionPolicySets
$functionReturn = DataCollectionPolicySetDefinitions @baseParameters -TargetMgOrSub $targetMgOrSub
$policySetDefinitionsScopedCount = $functionReturn.'PolicySetDefinitionsScopedCount'
$scopedPolicyCounts = @{
policyDefinitionsScopedCount = $policyDefinitionsScopedCount
policySetDefinitionsScopedCount = $policySetDefinitionsScopedCount
}
#SubscriptionPolicyAssignments
$functionReturn = DataCollectionPolicyAssignmentsSub @baseParameters @addRowToTableParameters @scopedPolicyCounts
if ($functionReturn.'addRowToTableDone') {
$addRowToTableDone = $true
}
#SubscriptionRoleDefinitions
DataCollectionRoleDefinitions @baseParameters -TargetMgOrSub $targetMgOrSub
#SubscriptionRoleAssignments
$functionReturn = DataCollectionRoleAssignmentsSub @baseParameters @addRowToTableParameters
if ($functionReturn.'addRowToTableDone') {
$addRowToTableDone = $true
}
#SubscriptionClassicAdministrators
dataCollectionClassicAdministratorsSub @baseParameters -SubscriptionMgPath $childMgMgPath
}
if ($addRowToTableDone -ne $true) {
addRowToTable `
-level $hierarchyLevel `
-mgName $childMgDisplayName `
-mgId $childMgId `
-mgParentId $childMgParentId `
-mgParentName $childMgParentName `
-mgASCSecureScore $mgAscSecureScoreResult `
-Subscription $childMgSubDisplayName `
-SubscriptionId $childMgSubId `
-SubscriptionASCSecureScore $subscriptionASCSecureScore
}
}
else {
addRowToTable `
-level $hierarchyLevel `
-mgName $childMgDisplayName `
-mgId $childMgId `
-mgParentId $childMgParentId `
-mgParentName $childMgParentName `
-mgASCSecureScore $mgAscSecureScoreResult `
-Subscription $childMgSubDisplayName `
-SubscriptionId $childMgSubId `
-SubscriptionASCSecureScore $subscriptionASCSecureScore
}
$endSubLoopThis = Get-Date
$null = $script:customDataCollectionDuration.Add([PSCustomObject]@{
Type = 'SUB'
Id = $childMgSubId
DurationSec = (New-TimeSpan -Start $startSubLoopThis -End $endSubLoopThis).TotalSeconds
})
$null = $script:arrayDataCollectionProgressSub.Add($childMgSubId)
$progressCount = ($arrayDataCollectionProgressSub).Count
Write-Host " $($progressCount)/$($subsToProcessInCustomDataCollectionCount) Subscriptions processed"
}
} -ThrottleLimit $ThrottleLimit
$endBatch = Get-Date
Write-Host " Batch #$batchCnt processing duration: $((New-TimeSpan -Start $startBatch -End $endBatch).TotalMinutes) minutes ($((New-TimeSpan -Start $startBatch -End $endBatch).TotalSeconds) seconds)"
$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)"
if ($azAPICallConf['htParameters'].DoPSRule -eq $true) {
if ($arrayPSRuleTracking.Count -gt 0) {
$durationPSRuleTotalSeconds = (($arrayPSRuleTracking.duration | Measure-Object -Sum).Sum)
Write-Host " CustomDataCollection Subscriptions 'PSRule for Azure' processing duration (in sum): $($durationPSRuleTotalSeconds / 60) minutes ($($durationPSRuleTotalSeconds) seconds)"
}
}
Write-Host " built-in PolicyDefinitions: $($($htCacheDefinitionsPolicy).Values.where({$_.Type -eq 'BuiltIn'}).Count)"
Write-Host " custom PolicyDefinitions: $($($htCacheDefinitionsPolicy).Values.where({$_.Type -eq 'Custom'}).Count)"
Write-Host " all PolicyDefinitions: $($($htCacheDefinitionsPolicy).Values.Count)"
}
#endregion SUBSCRIPTION
$durationDataMG = $customDataCollectionDuration.where( { $_.Type -eq 'MG' } )
$durationDataSUB = $customDataCollectionDuration.where( { $_.Type -eq 'SUB' } )
$durationMGAverageMaxMin = ($durationDataMG.DurationSec | Measure-Object -Average -Maximum -Minimum)
$durationSUBAverageMaxMin = ($durationDataSUB.DurationSec | Measure-Object -Average -Maximum -Minimum)
Write-Host "Collecting custom data for $($arrayEntitiesFromAPIManagementGroupsCount) ManagementGroups Avg/Max/Min duration in seconds: Average: $([math]::Round($durationMGAverageMaxMin.Average,4)); Maximum: $([math]::Round($durationMGAverageMaxMin.Maximum,4)); Minimum: $([math]::Round($durationMGAverageMaxMin.Minimum,4))"
Write-Host "Collecting custom data for $($arrayEntitiesFromAPISubscriptionsCount) Subscriptions Avg/Max/Min duration in seconds: Average: $([math]::Round($durationSUBAverageMaxMin.Average,4)); Maximum: $([math]::Round($durationSUBAverageMaxMin.Maximum,4)); Minimum: $([math]::Round($durationSUBAverageMaxMin.Minimum,4))"
apiCallTracking -stage 'CustomDataCollection ManagementGroups and Subscriptions' -spacing ' '
if ($azAPICallConf['htParameters'].NoResources -eq $false) {
$script:resourcesAllGroupedBySubcriptionId = $resourcesAll | Group-Object -Property subscriptionId
$totaldurationSubResourcesAddArray = ($arraySubResourcesAddArrayDuration.DurationSec | Measure-Object -Sum).Sum
Write-Host "Collecting custom data total duration writing the subResourcesArray: $totaldurationSubResourcesAddArray seconds"
if (-not $azAPICallConf['htParameters'].HierarchyMapOnly -and -not $azAPICallConf['htParameters'].ManagementGroupsOnly) {
if (-not $NoCsvExport) {
#fluctuation
Write-Host 'Process Resource fluctuation'
$start = Get-Date
if (Test-Path -Filter "*$($ManagementGroupId)_ResourcesAll.csv" -LiteralPath "$($outputPath)") {
$startImportPrevious = Get-Date
$doResourceFluctuation = $true
try {
$previous = Get-ChildItem -Path $outputPath -Filter "*$($ManagementGroupId)_ResourcesAll.csv" | Sort-Object -Descending -Property LastWriteTime | Select-Object -First 1 -ErrorAction Stop
$importPrevious = Import-Csv -LiteralPath "$($outputPath)$($DirectorySeparatorChar)$($previous.Name)" -Encoding utf8 -Delimiter $CsvDelimiter | Select-Object -ExpandProperty id
Write-Host " Import previous ($($previous.Name)) duration: $((New-TimeSpan -Start $startImportPrevious -End (Get-Date)).TotalSeconds) seconds"
}
catch {
Write-Host " FAILED: importing previous CSV '$($outputPath)$($DirectorySeparatorChar)$($previous.Name)' OR it does not exist (*$($ManagementGroupId)_ResourcesAll.csv)"
$doResourceFluctuation = $false
}
if ($doResourceFluctuation) {
#$importPrevious.Count
#https://gist.github.com/fatherjack/4c91cc6832b8b02d1b7319716a5fba52
function Compare-StringSet {
<#
.SYNOPSIS
Compare two sets of strings and see the matched and unmatched elements from each input
.DESCRIPTION
Compares sets of
.PARAMETER Ref
The reference set of values to be compared
.PARAMETER Diff
The difference set of values to be compared
.PARAMETER CaseSensitive
Enables a case-sensitive comparison
.EXAMPLE
$ref, $dif = @(
, @('a', 'b', 'c')
, @('b', 'c', 'd')
)
$Sets = Compare-StringSet $ref $dif
$Sets.RefOnly
$Sets.DiffOnly
$Sets.Both
This example sets up two arrays with some similar values and then passes them both to the Compare-StringSet function. the results of this are stored in the variable $Sets.
$Sets is an object that has three properties - RefOnly, DiffOnly, and Both. These are sets of the incoming values where they intersect or not.
.EXAMPLE
$ref, $dif = @(
, @('tree', 'house', 'football')
, @('dog', 'cat', 'tree', 'house', 'Football')
)
$Sets = Compare-StringSet $ref $dif -CaseSensitive
$Sets.RefOnly
$Sets.DiffOnly
$Sets.Both
This example sets up two arrays with some similar values and then passes them both to the Compare-StringSet function using the -CaseSensitive switch. The results of this are stored in the variable $Sets.
$Sets is an object that has three properties - RefOnly, DiffOnly, and Both.
Because of the -CaseSensitive switch usage 'football' is shown as in RefOnly and 'Football' is shown as in DiffOnly.
.NOTES
From https://gist.github.com/IISResetMe/57ce7b76e1001974a4f7170e10775875
#>
param(
[string[]]$Ref,
[string[]]$Diff,
[switch]$CaseSensitive
)
$Comparer = if ($CaseSensitive) {
[System.StringComparer]::InvariantCulture
}
else {
[System.StringComparer]::InvariantCultureIgnoreCase
}
$Results = [ordered]@{
RefOnly = @()
Both = @()
DiffOnly = @()
}
$temp = [System.Collections.Generic.HashSet[string]]::new($Ref, $Comparer)
$temp.IntersectWith($Diff)
$Results['Both'] = $temp
#$temp = [System.Collections.Generic.HashSet[string]]::new($Ref, [System.StringComparer]::CurrentCultureIgnoreCase)
$temp = [System.Collections.Generic.HashSet[string]]::new($Ref, $Comparer)
$temp.ExceptWith($Diff)
$Results['RefOnly'] = $temp
#$temp = [System.Collections.Generic.HashSet[string]]::new($Diff, [System.StringComparer]::CurrentCultureIgnoreCase)
$temp = [System.Collections.Generic.HashSet[string]]::new($Diff, $Comparer)
$temp.ExceptWith($Ref)
$Results['DiffOnly'] = $temp
return [pscustomobject]$Results
}
Write-Host " Comparing previous ($($importPrevious.Count)) with latest ($($resourcesIdsAll.Count))"
$start = Get-Date
$x = Compare-StringSet $importPrevious $resourcesIdsAll.id
Write-Host ' unique values in previous (deleted):' $x.RefOnly.Count
Write-Host " values that are contained in previous and latest: $($x.Both.Count)"
Write-Host ' unique values in latest (added):' $x.DiffOnly.Count
$end = Get-Date
Write-Host " Compare previous with latest duration: $((New-TimeSpan -Start $start -End $end).TotalMinutes) mins ($((New-TimeSpan -Start $start -End $end).TotalSeconds) sec)"
$script:arrayResourceFluctuationFinal = [System.Collections.ArrayList]@()
#ADDED
$arrayAdded = [System.Collections.ArrayList]@()
$arrayAddedAndRemoved = [System.Collections.ArrayList]@()
foreach ($resource in $x.DiffOnly) {
$resourceSplitted = $resource.split('/')
#$resourceSplitted
$null = $arrayAdded.Add([PSCustomObject]@{
subscriptionId = $resourceSplitted[2]
resourceType0 = $resourceSplitted[6]
resourceType1 = $resourceSplitted[7]
resourceType2 = $resourceSplitted[9]
resourceType3 = $resourceSplitted[11]
})
$subDetails = $htSubscriptionsMgPath.($resourceSplitted[2])
$null = $arrayAddedAndRemoved.Add([pscustomobject]@{
action = 'add'
subscriptionId = $resourceSplitted[2]
subscriptionName = $subDetails.displayName
mgPath = $subDetails.pathDelimited
resourceId = $resource
resourceType0 = $resourceSplitted[6]
resourceType1 = $resourceSplitted[7]
resourceType2 = $resourceSplitted[9]
resourceType3 = $resourceSplitted[11]
})
if ($resourceSplitted.Count -gt 13) {
Write-Host ' Unforeseen Resource type!'
Write-Host " Please report this Resource type at $($GithubRepository): '$resource'"
}
}
if ($arrayAdded.Count -gt 0) {
$arrayGroupedByResourceType = $arrayAdded | Group-Object -Property resourceType0, resourceType1, resourceType2, resourceType3
foreach ($resourceType in $arrayGroupedByResourceType) {
$arrayGroupedBySubscription = $arrayGroupedByResourceType.where({ $_.Name -eq $resourceType.Name }).Group | Group-Object -Property subscriptionId | Select-Object -ExcludeProperty Group
$null = $arrayResourceFluctuationFinal.Add([PSCustomObject]@{
Event = 'Added'
ResourceType = ($resourceType.Name -replace ', ', '/')
'Resource count' = $resourceType.Count
'Subscription count' = ($arrayGroupedBySubscription | Measure-Object).Count
})
}
}
#REMOVED
$arrayRemoved = [System.Collections.ArrayList]@()
foreach ($resource in $x.RefOnly) {
$resourceSplitted = $resource.split('/')
#$resourceSplitted
$null = $arrayRemoved.Add([PSCustomObject]@{
subscriptionId = $resourceSplitted[2]
resourceType0 = $resourceSplitted[6]
resourceType1 = $resourceSplitted[7]
resourceType2 = $resourceSplitted[9]
resourceType3 = $resourceSplitted[11]
})
$subDetails = $htSubscriptionsMgPath.($resourceSplitted[2])
$null = $arrayAddedAndRemoved.Add([pscustomobject]@{
action = 'remove'
subscriptionId = $resourceSplitted[2]
subscriptionName = $subDetails.displayName
mgPath = $subDetails.pathDelimited
resourceId = $resource
resourceType0 = $resourceSplitted[6]
resourceType1 = $resourceSplitted[7]
resourceType2 = $resourceSplitted[9]
resourceType3 = $resourceSplitted[11]
})
if ($resourceSplitted.Count -gt 13) {
Write-Host ' Unforeseen Resource type!'
Write-Host " Please report this Resource type at $($GithubRepository): '$resource'"
}
}
if ($arrayRemoved.Count -gt 0) {
$arrayGroupedByResourceType = $arrayRemoved | Group-Object -Property resourceType0, resourceType1, resourceType2, resourceType3
foreach ($resourceType in $arrayGroupedByResourceType) {
$arrayGroupedBySubscription = $arrayGroupedByResourceType.where({ $_.Name -eq $resourceType.Name }).Group | Group-Object -Property subscriptionId | Select-Object -ExcludeProperty Group
$null = $arrayResourceFluctuationFinal.Add([PSCustomObject]@{
Event = 'Removed'
ResourceType = ($resourceType.Name -replace ', ', '/')
'Resource count' = $resourceType.Count
'Subscription count' = ($arrayGroupedBySubscription | Measure-Object).Count
})
}
}
}
}
else {
Write-Host " Process Resource fluctuation skipped, no previous output (*$($ManagementGroupId)_ResourcesAll.csv) found"
}
if ($arrayResourceFluctuationFinal.Count -gt 0 -and $doResourceFluctuation) {
if (-not $NoCsvExport) {
#DataCollection Export of Resource fluctuation
Write-Host " Exporting ResourceFluctuation CSV '$($outputPath)$($DirectorySeparatorChar)$($fileName)_ResourceFluctuation.csv'"
$arrayResourceFluctuationFinal | Sort-Object -Property ResourceType | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName)_ResourceFluctuation.csv" -Delimiter "$csvDelimiter" -NoTypeInformation
Write-Host " Exporting ResourceFluctuation detailed CSV '$($outputPath)$($DirectorySeparatorChar)$($fileName)_ResourceFluctuationDetailed.csv'"
$arrayAddedAndRemoved | Sort-Object -Property Resource | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName)_ResourceFluctuationDetailed.csv" -Delimiter "$csvDelimiter" -NoTypeInformation
}
}
Write-Host "Process Resource fluctuation duration: $((New-TimeSpan -Start $start -End (Get-Date)).TotalSeconds) seconds"
#DataCollection Export of All Resources
if ($resourcesIdsAll.Count -gt 0) {
if (-not $NoCsvExport) {
$startExportingResourcesAllCSV = Get-Date
Write-Host "Exporting ResourcesAll CSV '$($outputPath)$($DirectorySeparatorChar)$($fileName)_ResourcesAll.csv'"
$arrListSKUKeys = [System.Collections.ArrayList]@()
foreach ($entry in $resourcesIdsAll.where({ $_.sku }).sku) {
foreach ($noteProperty in ($entry | Get-Member).where({ $_.MemberType -eq 'NoteProperty' })) {
if ($arrListSKUKeys -notcontains $noteProperty.Name) {
$null = $arrListSKUKeys.Add($noteProperty.Name)
}
}
}
Write-Host " SKU keys: $(($arrListSKUKeys | Sort-Object) -join ', ')"
Write-Host ' Enriching resources with SKU keys'
foreach ($entry in $resourcesIdsAll) {
foreach ($key in $arrListSKUKeys | Sort-Object) {
if ($entry.sku.$key) {
$entry | Add-Member -MemberType NoteProperty -Name "sku_$($key)" -Value $entry.sku.$key
}
else {
$entry | Add-Member -MemberType NoteProperty -Name "sku_$($key)" -Value $null
}
}
}
$resourcesIdsAll | Sort-Object -Property id | Select-Object -Property subscriptionId, subscriptionName, mgPath, type, sku_*, kind, id, name, location, tags, createdTime, changedTime, cafResourceNamingResult, cafResourceNaming, cafResourceNamingFriendlyName | Export-Csv -Path "$($outputPath)$($DirectorySeparatorChar)$($fileName)_ResourcesAll.csv" -Delimiter "$csvDelimiter" -NoTypeInformation
$endExportingResourcesAllCSV = Get-Date
Write-Host " Exporting ResourcesAll CSV duration: $((New-TimeSpan -Start $startExportingResourcesAllCSV -End $endExportingResourcesAllCSV).TotalMinutes) minutes ($((New-TimeSpan -Start $startExportingResourcesAllCSV -End $endExportingResourcesAllCSV).TotalSeconds) seconds)"
}
}
else {
Write-Host "Not Exporting ResourcesAll CSV, as there are $($resourcesIdsAll.Count) resources"
}
}
}
}
if ($azAPICallConf['htParameters'].LargeTenant -eq $false -or $azAPICallConf['htParameters'].PolicyAtScopeOnly -eq $false -or $azAPICallConf['htParameters'].RBACAtScopeOnly -eq $false) {
if (($azAPICallConf['checkContext']).Tenant.Id -ne $ManagementGroupId) {
addRowToTable `
-level (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain | Measure-Object).Count - 1) `
-mgName $getMgParentName `
-mgId $getMgParentId `
-mgParentId "'upperScopes'" `
-mgParentName 'upperScopes'
}
}
if ($azAPICallConf['htParameters'].LargeTenant -eq $true -or $azAPICallConf['htParameters'].PolicyAtScopeOnly -eq $true) {
if (($azAPICallConf['checkContext']).Tenant.Id -ne $ManagementGroupId) {
$currentTask = "Policy assignments ('$($ManagementGroupId)')"
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/providers/Microsoft.Management/managementgroups/$($ManagementGroupId)/providers/Microsoft.Authorization/policyAssignments?`$filter=atScope()&api-version=2021-06-01"
$method = 'GET'
$upperScopesPolicyAssignments = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask -caller 'CustomDataCollection'
$upperScopesPolicyAssignments = $upperScopesPolicyAssignments.where({ $_.properties.scope -ne "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" })
$upperScopesPolicyAssignmentsPolicyCount = (($upperScopesPolicyAssignments.where({ $_.properties.policyDefinitionId -match '/providers/Microsoft.Authorization/policyDefinitions/' }))).count
$upperScopesPolicyAssignmentsPolicySetCount = (($upperScopesPolicyAssignments.where({ $_.properties.policyDefinitionId -match '/providers/Microsoft.Authorization/policySetDefinitions/' }))).count
$upperScopesPolicyAssignmentsPolicyAtScopeCount = (($upperScopesPolicyAssignments.where({ $_.properties.policyDefinitionId -match '/providers/Microsoft.Authorization/policyDefinitions/' -and $_.Id -match "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" }))).count
$upperScopesPolicyAssignmentsPolicySetAtScopeCount = (($upperScopesPolicyAssignments.where({ $_.properties.policyDefinitionId -match '/providers/Microsoft.Authorization/policySetDefinitions/' -and $_.Id -match "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" }))).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'
$Id = ($L0mgmtGroupPolicyAssignment.properties.policydefinitionid).ToLower()
$Def = ($htCacheDefinitionsPolicy).($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'
}
$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
}
if ($L0mgmtGroupPolicyAssignment.properties.metadata.updatedBy) {
$updatedBy = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedBy
}
if ($L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn) {
$updatedOn = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn
}
}
if (($L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages.where( { -not $_.policyDefinitionReferenceId })).Message) {
$nonComplianceMessage = ($L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages.where( { -not $_.policyDefinitionReferenceId })).Message
}
else {
$nonComplianceMessage = ''
}
$formatedPolicyAssignmentParameters = ''
$hlp = $L0mgmtGroupPolicyAssignment.Properties.Parameters
if (-not [string]::IsNullOrEmpty($hlp)) {
$arrayPolicyAssignmentParameters = @()
$arrayPolicyAssignmentParameters = foreach ($parameterName in $hlp.PSObject.Properties.Name | Sort-Object) {
"$($parameterName)=$($hlp.($parameterName).Value -join "$($CsvDelimiter) ")"
}
$formatedPolicyAssignmentParameters = $arrayPolicyAssignmentParameters -join "$($CsvDelimiterOpposite) "
}
#mgSecureScore
$mgAscSecureScoreResult = ''
addRowToTable `
-level (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain).Count - 1) `
-mgName $getMgParentName `
-mgId $getMgParentId `
-mgParentId "'upperScopes'" `
-mgParentName 'upperScopes' `
-mgASCSecureScore $mgAscSecureScoreResult `
-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 `
-PolicyDefinitionEffectDefault ($htCacheDefinitionsPolicy).(($Def.PolicyDefinitionId)).effectDefaultValue `
-PolicyDefinitionEffectFixed ($htCacheDefinitionsPolicy).(($Def.PolicyDefinitionId)).effectFixedValue `
-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 `
-PolicyAssignmentLimit $LimitPOLICYPolicyAssignmentsManagementGroup `
-PolicyAssignmentCount $upperScopesPolicyAssignmentsPolicyCount `
-PolicyAssignmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAtScopeCount `
-PolicyAssignmentParameters $L0mgmtGroupPolicyAssignment.Properties.Parameters `
-PolicyAssignmentParametersFormated $formatedPolicyAssignmentParameters `
-PolicyAssignmentAssignedBy $assignedBy `
-PolicyAssignmentCreatedBy $createdBy `
-PolicyAssignmentCreatedOn $createdOn `
-PolicyAssignmentUpdatedBy $updatedBy `
-PolicyAssignmentUpdatedOn $updatedOn `
-PolicySetAssignmentLimit $LimitPOLICYPolicySetAssignmentsManagementGroup `
-PolicySetAssignmentCount $upperScopesPolicyAssignmentsPolicySetCount `
-PolicySetAssignmentAtScopeCount $upperScopesPolicyAssignmentsPolicySetAtScopeCount `
-PolicyAndPolicySetAssignmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAndPolicySetAtScopeCount
}
if ($L0mgmtGroupPolicyAssignment.properties.policyDefinitionId -match '/providers/Microsoft.Authorization/policySetDefinitions/') {
$PolicyVariant = 'PolicySet'
$Id = ($L0mgmtGroupPolicyAssignment.properties.policydefinitionid).ToLower()
$Def = ($htCacheDefinitionsPolicySet).($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'
}
$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
}
if ($L0mgmtGroupPolicyAssignment.properties.metadata.updatedBy) {
$updatedBy = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedBy
}
if ($L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn) {
$updatedOn = $L0mgmtGroupPolicyAssignment.properties.metadata.updatedOn
}
}
if (($L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages.where( { -not $_.policyDefinitionReferenceId })).Message) {
$nonComplianceMessage = ($L0mgmtGroupPolicyAssignment.Properties.nonComplianceMessages.where( { -not $_.policyDefinitionReferenceId })).Message
}
else {
$nonComplianceMessage = ''
}
$formatedPolicyAssignmentParameters = ''
$hlp = $L0mgmtGroupPolicyAssignment.Properties.Parameters
if (-not [string]::IsNullOrEmpty($hlp)) {
$arrayPolicyAssignmentParameters = @()
$arrayPolicyAssignmentParameters = foreach ($parameterName in $hlp.PSObject.Properties.Name | Sort-Object) {
"$($parameterName)=$($hlp.($parameterName).Value -join "$($CsvDelimiter) ")"
}
$formatedPolicyAssignmentParameters = $arrayPolicyAssignmentParameters -join "$($CsvDelimiterOpposite) "
}
addRowToTable `
-level (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain).Count - 1) `
-mgName $getMgParentName `
-mgId $getMgParentId `
-mgParentId "'upperScopes'" `
-mgParentName 'upperScopes' `
-mgASCSecureScore $mgAscSecureScoreResult `
-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 `
-PolicyAssignmentLimit $LimitPOLICYPolicyAssignmentsManagementGroup `
-PolicyAssignmentCount $upperScopesPolicyAssignmentsPolicyCount `
-PolicyAssignmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAtScopeCount `
-PolicyAssignmentParameters $L0mgmtGroupPolicyAssignment.Properties.Parameters `
-PolicyAssignmentParametersFormated $formatedPolicyAssignmentParameters `
-PolicyAssignmentAssignedBy $assignedBy `
-PolicyAssignmentCreatedBy $createdBy `
-PolicyAssignmentCreatedOn $createdOn `
-PolicyAssignmentUpdatedBy $updatedBy `
-PolicyAssignmentUpdatedOn $updatedOn `
-PolicySetAssignmentLimit $LimitPOLICYPolicySetAssignmentsManagementGroup `
-PolicySetAssignmentCount $upperScopesPolicyAssignmentsPolicySetCount `
-PolicySetAssignmentAtScopeCount $upperScopesPolicyAssignmentsPolicySetAtScopeCount `
-PolicyAndPolicySetAssignmentAtScopeCount $upperScopesPolicyAssignmentsPolicyAndPolicySetAtScopeCount
}
}
}
}
}
if ($azAPICallConf['htParameters'].LargeTenant -eq $true -or $azAPICallConf['htParameters'].RBACAtScopeOnly -eq $true) {
#RoleAssignment API (system metadata e.g. createdOn)
$currentTask = "Role assignments API '$($ManagementGroupId)'"
$uri = "$($azAPICallConf['azAPIEndpointUrls'].ARM)/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)/providers/Microsoft.Authorization/roleAssignments?api-version=2015-07-01"
$method = 'GET'
$roleAssignmentsFromAPI = AzAPICall -AzAPICallConfiguration $azAPICallConf -uri $uri -method $method -currentTask $currentTask
if ($roleAssignmentsFromAPI.Count -gt 0) {
$principalsToResolve = @()
$principalsToResolve = foreach ($ra in $roleAssignmentsFromAPI.properties | Sort-Object -Property principalId -Unique) {
if (-not $htPrincipals.($ra.principalId)) {
$ra.principalId
}
}
if ($principalsToResolve.Count -gt 0) {
ResolveObjectIds -objectIds $principalsToResolve
}
}
#$upperScopesRoleAssignments = GetRoleAssignments -Scope "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" -scopeDetails "getRoleAssignments upperScopes (Mg)"
$upperScopesRoleAssignments = $roleAssignmentsFromAPI
$upperScopesRoleAssignmentsLimitUtilization = (($upperScopesRoleAssignments.where({ $_.properties.scope -eq "/providers/Microsoft.Management/managementGroups/$($ManagementGroupId)" }))).count
#tenantLevelRoleAssignments
if (-not $htMgAtScopeRoleAssignments.'tenantLevelRoleAssignments') {
$tenantLevelRoleAssignmentsCount = (($upperScopesRoleAssignments.where({ $_.id -like '/providers/Microsoft.Authorization/roleAssignments/*' }))).count
$htMgAtScopeRoleAssignments.'tenantLevelRoleAssignments' = @{
AssignmentsCount = $tenantLevelRoleAssignmentsCount
}
}
foreach ($upperScopesRoleAssignment in $upperScopesRoleAssignments) {
$roleAssignmentId = ($upperScopesRoleAssignment.id).ToLower()
if ($upperScopesRoleAssignment.properties.scope -ne "/providers/Microsoft.Management/managementGroups/$ManagementGroupId") {
$roleDefinitionId = $upperScopesRoleAssignment.properties.roleDefinitionId
$roleDefinitionIdGuid = $roleDefinitionId -replace '.*/'
if (-not ($htCacheDefinitionsRole).($roleDefinitionIdGuid)) {
$roleDefinitionName = "'This roleDefinition likely was deleted although a roleAssignment existed'"
}
else {
$roleDefinitionName = ($htCacheDefinitionsRole).($roleDefinitionIdGuid).Name
}
if (($htPrincipals.($upperScopesRoleAssignment.properties.principalId).displayName).length -eq 0) {
$roleAssignmentIdentityDisplayname = 'n/a'
}
else {
if ($htPrincipals.($upperScopesRoleAssignment.properties.principalId).type -eq 'User') {
if ($azAPICallConf['htParameters'].DoNotShowRoleAssignmentsUserData -eq $false) {
$roleAssignmentIdentityDisplayname = $htPrincipals.($upperScopesRoleAssignment.properties.principalId).displayName
}
else {
$roleAssignmentIdentityDisplayname = 'scrubbed'
}
}
else {
$roleAssignmentIdentityDisplayname = $htPrincipals.($upperScopesRoleAssignment.properties.principalId).displayName
}
}
if (-not $htPrincipals.($upperScopesRoleAssignment.properties.principalId).signInName) {
$roleAssignmentIdentitySignInName = 'n/a'
}
else {
if ($htPrincipals.($upperScopesRoleAssignment.properties.principalId).type -eq 'User') {
if ($azAPICallConf['htParameters'].DoNotShowRoleAssignmentsUserData -eq $false) {
$roleAssignmentIdentitySignInName = $htPrincipals.($upperScopesRoleAssignment.properties.principalId).signInName
}
else {
$roleAssignmentIdentitySignInName = 'scrubbed'
}
}
else {
$roleAssignmentIdentitySignInName = $htPrincipals.($upperScopesRoleAssignment.properties.principalId).signInName
}
}
$roleAssignmentIdentityObjectId = $upperScopesRoleAssignment.properties.principalId
$roleAssignmentIdentityObjectType = $htPrincipals.($upperScopesRoleAssignment.properties.principalId).type
$roleAssignmentScope = $upperScopesRoleAssignment.properties.scope
$roleAssignmentScopeName = $roleAssignmentScope -replace '.*/'
$roleAssignmentScopeType = 'MG'
$roleSecurityCustomRoleOwner = 0
if (($htCacheDefinitionsRole).$($roleDefinitionIdGuid).Actions -eq '*' -and ((($htCacheDefinitionsRole).$($roleDefinitionIdGuid).NotActions)).length -eq 0 -and ($htCacheDefinitionsRole).$($roleDefinitionIdGuid).IsCustom -eq $True) {
$roleSecurityCustomRoleOwner = 1
}
$roleSecurityOwnerAssignmentSP = 0
if ((($htCacheDefinitionsRole).$($roleDefinitionIdGuid).Id -eq '8e3af657-a8ff-443c-a75c-2fe8c4bcb635' -and $roleAssignmentIdentityObjectType -eq 'ServicePrincipal') -or (($htCacheDefinitionsRole).$($roleDefinitionIdGuid).Actions -eq '*' -and ((($htCacheDefinitionsRole).$($roleDefinitionIdGuid).NotActions)).length -eq 0 -and ($htCacheDefinitionsRole).$($roleDefinitionIdGuid).IsCustom -eq $True -and $roleAssignmentIdentityObjectType -eq 'ServicePrincipal')) {
$roleSecurityOwnerAssignmentSP = 1
}
$createdBy = ''
$createdOn = ''
$createdOnUnformatted = $null
$updatedBy = ''
$updatedOn = ''
if ($upperScopesRoleAssignment.properties.createdBy) {
$createdBy = $upperScopesRoleAssignment.properties.createdBy
}
if ($upperScopesRoleAssignment.properties.createdOn) {
$createdOn = $upperScopesRoleAssignment.properties.createdOn
}
if ($upperScopesRoleAssignment.properties.updatedBy) {
$updatedBy = $upperScopesRoleAssignment.properties.updatedBy
}
if ($upperScopesRoleAssignment.properties.updatedOn) {
$updatedOn = $upperScopesRoleAssignment.properties.updatedOn
}
$createdOnUnformatted = $upperScopesRoleAssignment.properties.createdOn
if (($azAPICallConf['checkContext']).Tenant.Id -ne $ManagementGroupId) {
$levelToUse = (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain).Count - 1)
$toUseAsmgName = $getMgParentName
$toUseAsmgId = $getMgParentId
$toUseAsmgParentId = "'upperScopes'"
$toUseAsmgParentName = 'upperScopes'
}
else {
$levelToUse = (($htManagementGroupsMgPath.($ManagementGroupId).ParentNameChain).Count)
$toUseAsmgName = $selectedManagementGroupId.DisplayName
$toUseAsmgId = $selectedManagementGroupId.Name
$toUseAsmgParentId = 'Tenant'
$toUseAsmgParentName = 'Tenant'
}
#mgSecureScore
$mgAscSecureScoreResult = ''
addRowToTable `
-level $levelToUse `
-mgName $toUseAsmgName `
-mgId $toUseAsmgId `
-mgParentId $toUseAsmgParentId `
-mgParentName $toUseAsmgParentName `
-mgASCSecureScore $mgAscSecureScoreResult `
-RoleDefinitionId $roleDefinitionIdGuid `
-RoleDefinitionName $roleDefinitionName `
-RoleIsCustom ($htCacheDefinitionsRole).$($roleDefinitionIdGuid).IsCustom `
-RoleAssignableScopes (($htCacheDefinitionsRole).$($roleDefinitionIdGuid).AssignableScopes -join "$CsvDelimiterOpposite ") `
-RoleActions (($htCacheDefinitionsRole).$($roleDefinitionIdGuid).Actions -join "$CsvDelimiterOpposite ") `
-RoleNotActions (($htCacheDefinitionsRole).$($roleDefinitionIdGuid).NotActions -join "$CsvDelimiterOpposite ") `
-RoleDataActions (($htCacheDefinitionsRole).$($roleDefinitionIdGuid).DataActions -join "$CsvDelimiterOpposite ") `
-RoleNotDataActions (($htCacheDefinitionsRole).$($roleDefinitionIdGuid).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 `
-RoleAssignmentPIM 'unknown'
}
}
}
}